前面记录了下next 如何做服务端渲染,最近看了看vue官方得ssr说明,然后不基于next,自己来做一个vue得ssr服务端渲染.
官方文档的解释:Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。
服务器渲染的 Vue.js 应用程序也可以被认为是"同构"或"通用",因为应用程序的大部分代码都可以在服务器和客户端上运行。
还是老样子,我们在用ssr服务端渲染之前需要先问自己是否真的需要它.
技术层面:
- 更快的首屏渲染速度
- 更好的 SEO
业务层面:
- 不适合管理系统
- 适合门户资讯类网站,例如企业官网、知乎、简书等
- 适合移动网站
vue的ssr 主要分为两种
Nuxt.js 开发框架
- NUXT提供了平滑的开箱即用的体验,它建立在同等的Vue技术栈之上,但抽象出很多模板,并提供了一些额外的功能,例如静态站点生成。通过 Nuxt.js 可以快速的使用 Vue SSR 构建同构应用。
基于 Vue SSR 官方文档提供的解决方案
- 官方方案具有更直接的控制应用程序的结构,更深入底层,更加灵活,同时在使用官方方案的过程中,也会对Vue SSR有更加深入的了解。
- 该方式需要你熟悉 Vue.js 本身,并且具有 Node.js 和 webpack 的相当不错的应用经验。
next的文档写的很棒了,基本跟着它的文档做就可以了,这里主要是参考vue ssr的文档,来实现一下.
首先来个最简单的,把一个vue的实例转换成模板字符串,然后从服务器返回到客户端.
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: `
`,
};
//匹配所有地址,返回html界面
server.get('*', (req, res) => {
const app = new Vue({ //创建vue实例,每次请求都是一个新的实例,防止实例共享,数据错乱
data: {
url: req.url
},
template: `访问的 URL 是: {{ url }}`,
});
//把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);
模板注意点:注意 注释 -- 这里将是应用程序 HTML 标记注入的地方。
这是官网的例子:https://ssr.vuejs.org/zh/guide/
这会是一个最简单的demo,开发阶段热加载,路由定位,数据预取等都没有,下面就我们来进一步实现它。
首先我们来看一张图,来看它的构建流程:
首先来看,我们肯定是需要使用webpack来打包我们的vue程序的,因为:
- 通常 Vue 应用程序是由 webpack 和vue-loader构建,并且许多 webpack 特定功能不能直接在Node.js 中运行(例如通过file-loader导入文件,通过css-loader导入 CSS)。
- 尽管 Node.js 最新版本能够完全支持 ES2015 特性,我们还是需要转译客户端代码以适应老版浏览器。这也会涉及到构建步骤。
所以是这样,首先我们把所有的源代码例如(store,router,components),通过公共entry app.js和服务端的入口和客户端入口进行webpack打包,对应客户端应用程序和服务端应用程序打出来:服务器需要的bundle 也就是serve bundle,用于服务器渲染ssr, 而打出来的客户端bundle 也就是client bundle, 这个js会写入到html模板中,用于客户端激活,接管服务端发送的静态html,使其变为由vue管理的动态dom.
客户端激活的一些注意事项:
由于服务器已经渲染好了 HTML,我们显然无需将其丢弃再重新创建所有的 DOM 元素。相反,我们需要"激活"这些静态的 HTML,然后使他们成为动态的(能够响应后续的数据变化)。
如果你检查服务器渲染的输出结果,你会注意到应用程序的根元素上添加了一个特殊的属性:
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...
一个基本的项目应该是这样:
- setup-dev-server: 开发模式下,用来监视打包构建,重新生成renderer渲染器
- webpack.base.config 公共的webpack配置
- webpack.client.config 客户端webpack配置
- webpack.server.config 服务端webpack配置
- pages,router,store 是vue 相关文件
- index.template.html 模板html文件
- app.js我们应用程序的「通用 entry」,在纯客户端应用程序中,我们将在此文件中创建根 Vue 实例,并直接挂载到 DOM。但是,对于服务器端渲染(SSR),责任转移到纯客户端 entry 文件。
- entry-server.js 服务器 entry 使用 default export 导出函数,并在每次渲染中重复调用此函数。此时,除了创建和返回应用程序实例之外,它不会做太多事情 - 但是稍后我们将在此执行服务器端路由匹配 (server-sideroute matching) 和数据预取逻辑 (data pre-fetching logic)。
- entry-client.js 客户端 entry 只需创建应用程序,并且将其挂载到 DOM 中
- server.js 我们node服务的启动文件
然后下面就是一步一步来实现在这些功能.
准备工作安装依赖:
生产:
包
说明
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