官方文档:https://ssr.vuejs.org/css
官方文档的解释:Vue.js 是构建客户端应用程序的框架。默认状况下,能够在浏览器中输出 Vue组件,进行生成 DOM 和操做 DOM。然而,也能够将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上彻底可交互的应用程序。html
服务器渲染的 Vue.js 应用程序也能够被认为是"同构"或"通用",由于应用程序的大部分代码均可以在服务器和客户端上运行。vue
仍是老样子,咱们在用ssr服务端渲染以前须要先问本身是否真的须要它.node
技术层面:webpack
业务层面:web
vue的ssr 主要分为两种express
Nuxt.js 开发框架npm
基于 Vue SSR 官方文档提供的解决方案json
next的文档写的很棒了,基本跟着它的文档作就能够了,这里主要是参考vue ssr的文档,来实现一下.
首先来个最简单的,把一个vue的实例转换成模板字符串,而后从服务器返回到客户端.segmentfault
npm install vue vue-server-renderer --save
const Vue = require('vue'); const server = require('express')(); //建立服务 //选择模板 const template = require('fs').readFileSync('./index.template.html', 'utf-8'); //建立渲染器 const renderer = require('vue-server-renderer').createRenderer({ template, }); //模板使用的数据上下文 const context = { title: 'vue ssr', metas: ` <meta name="keyword" content="vue,ssr"> <meta name="description" content="vue srr demo"> `, }; //匹配全部地址,返回html界面 server.get('*', (req, res) => { const app = new Vue({ //建立vue实例,每次请求都是一个新的实例,防止实例共享,数据错乱 data: { url: req.url }, template: `<div>访问的 URL 是: {{ url }}</div>`, }); //把vue实例和上下文数据和模板结合返回字符串给客户端浏览器 renderer .renderToString(app, context, (err, html) => { console.log(html); if (err) { res.status(500).end('Internal Server Error') return; } res.end(html); }); }) //监听端口 server.listen(8080);
模板注意点:注意 <!--vue-ssr-outlet-->
注释 -- 这里将是应用程序 HTML 标记注入的地方。
这是官网的例子:https://ssr.vuejs.org/zh/guide/
这会是一个最简单的demo,开发阶段热加载,路由定位,数据预取等都没有,下面就咱们来进一步实现它。
首先咱们来看一张图,来看它的构建流程:
首先来看,咱们确定是须要使用webpack来打包咱们的vue程序的,由于:
因此是这样,首先咱们把全部的源代码例如(store,router,components),经过公共entry app.js和服务端的入口和客户端入口进行webpack打包,对应客户端应用程序和服务端应用程序打出来:服务器须要的bundle 也就是serve bundle,用于服务器渲染ssr, 而打出来的客户端bundle 也就是client bundle, 这个js会写入到html模板中,用于客户端激活,接管服务端发送的静态html,使其变为由vue管理的动态dom.
因为服务器已经渲染好了 HTML,咱们显然无需将其丢弃再从新建立全部的 DOM 元素。相反,咱们须要"激活"这些静态的 HTML,而后使他们成为动态的(可以响应后续的数据变化)。
若是你检查服务器渲染的输出结果,你会注意到应用程序的根元素上添加了一个特殊的属性:
<div id="app" data-server-rendered="true">
data-server-rendered
特殊属性,让客户端 Vue 知道这部分 HTML 是由 Vue 在服务端渲染的,而且应该以激活模式进行挂载。注意,这里并无添加 id="app"
,而是添加 data-server-rendered
属性:你须要自行添加 ID 或其余可以选取到应用程序根元素的选择器,不然应用程序将没法正常激活。
在开发模式下,Vue 将推断客户端生成的虚拟 DOM 树 (virtual DOM tree),是否与从服务器渲染的 DOM 结构 (DOM structure) 匹配。若是没法匹配,它将退出混合模式,丢弃现有的 DOM 并从头开始渲染。在生产模式下,此检测会被跳过,以免性能损耗。
客户端渲染注意事项:https://ssr.vuejs.org/zh/guid...
一个基本的项目应该是这样:
而后下面就是一步一步来实如今这些功能.
准备工做安装依赖:
生产:
包 | 说明 |
---|---|
vue | Vue.js 核心库 |
vue-server-renderer | Vue 服务端渲染工具 |
express | 基于 Node 的 Web 服务框架 |
cross-env | 经过 npm scripts 设置跨平台环境变量 |
开发:
包 | 说明 |
---|---|
webpack | webpack 核心包 |
webpack-cli | webpack 的命令行工具 |
webpack-merge | webpack 配置信息合并工具 |
webpack-node-externals | 排除 webpack 中的 Node 模块 |
rimraf | 基于 Node 封装的一个跨平台rm-rf工具 |
friendly-errors-webpack-plugin | 友好的 webpack 错误提示 |
@babel/core , @babel/plugin-transform-runtime, @babel/preset-env, babel-loader | Babel 相关工具 |
vue-loader,vue-template-compiler | 处理 .vue 资源 |
file-loader | 处理字体资源 |
css-loader | 处理 CSS 资源 |
url-loader | 处理图片资源 |
而后一步一步来,首先是咱们的 webpack配置,先是公共的webpack.base.config.js
/** * 公共配置 */ const VueLoaderPlugin = require('vue-loader/lib/plugin') const path = require('path') const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')//友好的webpack错误提示 const resolve = file => path.resolve(__dirname, file) const isProd = process.env.NODE_ENV === 'production' //判断是生产仍是开发环境 module.exports = { mode: isProd ? 'production' : 'development', output: { path: resolve('../dist/'), publicPath: '/dist/', //设置客户端请求资源时的路径,从dist打包输出目录读取 filename: '[name].[chunkhash].js' //设置chunkhash }, resolve: { alias: { // 路径别名,@ 指向 src '@': resolve('../src/') }, // 能够省略的扩展名 // 当省略扩展名的时候,按照从前日后的顺序依次解析 extensions: ['.js', '.vue', '.json'] }, devtool: isProd ? 'source-map' : 'cheap-module-eval-source-map', module: { rules: [ // 处理图片资源 { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { limit: 8192, }, }, ], }, // 处理字体资源 { test: /\.(woff|woff2|eot|ttf|otf)$/, use: [ 'file-loader', ], }, // 处理 .vue 资源 { test: /\.vue$/, loader: 'vue-loader' }, // 处理 CSS 资源 // 它会应用到普通的 `.css` 文件 // 以及 `.vue` 文件中的 `<style>` 块 { test: /\.css$/, use: [ 'vue-style-loader', 'css-loader' ] }, // CSS 预处理器,参考:https://vue-loader.vuejs.org/zh/guide/pre-processors.html // 例如处理 Less 资源 // { // test: /\.less$/, // use: [ // 'vue-style-loader', // 'css-loader', // 'less-loader' // ] // }, ] }, plugins: [ new VueLoaderPlugin(), new FriendlyErrorsWebpackPlugin() //错误提示插件 ] }