单页应用之预渲染(prerendering)

如果你调研 服务器端渲染 (SSR) 只是用来改善少数营销页面(例如 /, /about, /contact 等)的 SEO,那么你可能需要 预渲染。无需使用 web 服务器实时动态编译 HTML,而是使用预渲染方式,在构建时 (build time) 简单地生成针对特定路由的静态 HTML 文件。优点是设置预渲染更简单,并可以将你的前端作为一个完全静态的站点。

我们可以使用 webpack 的插件 prerender-spa-plugin 来轻松地添加预渲染。它已经被 Vue 应用程序广泛测试,并且它的作者是 Vue 核心团队的成员。

这篇文章会基于 @vue/cli-3.x 说明 预渲染 如何配置。

安装

首先使用 npm 安装最新版的 prerender-spa-plugin 插件。

1
$ npm install prerender-spa-plugin --save-dev

由于 prerender-spa-plugin新的 3.x 版本依赖于 puppeteer 库,并且 puppeteer 是很大的,大约有200多M,所以对于网速很慢的同学,经常会在下载这个库的时候超时失败。鉴于这样的情况,推荐使用nrm 工具将下载源设置为淘宝源,然后再安装 prerender-spa-plugin

1
2
3
$ npm i nrm -g
$ nrm use taobao
$ npm i prerender-spa-plugin --save-dev

vue.config.js 配置

安装完毕后,我们在 vue.config.js 文件中添加如下配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// vue.config.js

const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer

module.exports = {
//部署应用包时的基本 URL。
publicPath: "/",
// 打包输出文件路径(文件名,默认 dist )。
outputDir: "dist",
//打包后静态静态资源的放置位置,该项配置默认为 "" , 即直接将 ( js/css/img/fonts/...) 这些文件夹放在了 dist 文件夹下
//这里将这些静态资源放置在 assets 文件夹中。
assetsDir: "assets",
//添加 webpack 配置
configureWebpack: {
//追加插件配置
plugins: [
new PrerenderSPAPlugin({
// 预渲染打包后的静态资源存放目录(必须),要跟 outputDir 配置对应上
staticDir: path.join(__dirname, 'dist'),

// 预渲染的输出路径,默认使用 staticDir 字段设置的值
// outputDir: path.join(__dirname, 'dist/prerendered'),

// 本地的 html 页面模块文件(必须)
indexPath: path.join(__dirname, 'dist', 'index.html'),

// 要匹配的预渲染路由(必须)
routes: ['/', '/about'],

// 渲染器(必须)
renderer: new Renderer({

// 默认挂在 window.__PRERENDER_INJECTED 对象上,可以通过 window.__PRERENDER_INJECTED.foo 在预渲染页面取值
inject: {
foo: 'bar'
},

headless: false,
// 定义渲染事件名称, document.dispatch(new Event('render-event'))
renderAfterDocumentEvent: 'render-event',
// 延迟渲染时间
//renderAfterTime: 5000,
// 触发渲染的元素,该元素生成后就保存渲染结果
//renderAfterElementExists: '#app'
}),

// 服务器配置
// server: {
// // 代理,用于发送请求,设置与 webpack-dev-server 并不完全相同
// proxy: {
// '/api': {
// // 代理地址
// target: '',
// // pathRewrite: {
// // '^/api': '/',
// // },
// },
// // proxy的属性用于express: app.use(key, proxy[key])
// // '/:foo': { target }, 可以不匹配 '/'
// },
// },

})
]
}
}

main.js

接下来,main.js 文件中,在构造 Vue 实例配置的 mounted 钩子中添加 预渲染 的事件发布。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// main.js

// 忽略其他代码 ...

new Vue({
el: '#app',
router,
store,
render: h => h(App),
mounted(){
// 实例被挂载后,触发渲染事件
document.dispatchEvent(new Event('render-event'));
}
})

路由模式

最后,我们需要将路由模式修改为 mode: history 模式。

构建

1
$ npm run build

执行构建命令后,我们可以看到多出了 about 文件夹。在使用 /about 访问关于页面时,展示的就是 about 文件夹下的 index.html 页面了。

配置说明

更多的详细配置信息请参考 prerender-spa-plugin