Vue预渲染

之前一段时间调研了React的SSR (opens new window),今天有时间研究下Vue的预渲染。老套路还是先说说预渲染有什么好处,跟SSR有什么区别???? Let's look down 👓⏬

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

预渲染是为了页面有更好的加载速度,而且可以改善少数页面的SEO,为什么是少数的,因为大量的路由会使预渲染变得非常缓慢(构建时)。预渲染基本原理是 - 启动无头浏览器,加载应用程序的路由并将结果保存到静态HTML文件中。然后,您可以将其与以前使用的任何静态文件服务解决方案一起使用,用最少的代码做到你想要的效果几乎没有任何的侵入性。

看下他们的区别:

SSR (opens new window) 预渲染 (opens new window)
运行时 构建时
代码侵入性大,开发调试代价高,报错不明显(钩子) 几乎没有侵入性
SEO更彻底 有局限性(动态URL的异步请求)
首屏加载更快 首屏加载快
需要Node环境,耗费CPU内存 不需要Node环境
难度较大(有现成的框架) 难度小
动态内容直出 HTMl 直出有限,客户端会再次加载(跳屏)

上干货

预渲染核心插件:prerender-spa-plugin 为了更好的SEO一般会动态需改meta的内容 vue-meta-info

安装:

yarn add prerender-spa-plugin vue-meta-info -D
1

prerender-spa-plugin 是基于puppeteer的,下载出错多试几次,百度很多文章可解决

vue.config.js中进行配置

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

module.exports = {
  configureWebpack: {
    plugins: [
       new PrerenderSPAPlugin({
          // 生成文件的路径,这个目录只能有一级。若目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动
          staticDir: path.join(__dirname, './dist'),
          // 可选-渲染的应用程序应输出到的路径。
          // (默认为staticDir。)
          outputDir: path.join(__dirname ,'/dist/prerendered'), 
          // 对应自己的路由文件
          routes: [ '/', '/home','/list'],
          // 若没有这段则不会进行预编译
          renderer: new Renderer({
            inject: {
              foo: 'bar'
            },
            // headless: false,
            // 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
            renderAfterDocumentEvent: 'render-event',
            // 可选-等待渲染,直到经过一定的时间。
            // 不推荐
            renderAfterTime: 5000,
            // 可选-默认为0,无限制。
            // 路由是异步呈现的。
            // 使用它来限制并行渲染的路由数量
            maxConcurrentRoutes: 4})
        }),
    ]
  }
}
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

main.js中进行配置

import Vue from 'vue'
import MetaInfo from 'vue-meta-info'


// ......


Vue.use(MetaInfo)
new Vue({
  router,
  store,
  render:h=>h(App),
  mounted(){
     document.dispatchEvent(new Event('render-event'))
  }
}).$mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

注:预渲染方式下的route需采用history模式,否则每个打包生成的index.html的文件内容会一样

组件内静态使用metaInfo

<template>
...
</template>

<script>
export default {
  metaInfo: {
    title: 'My Example App', // 可以是异步的
    meta: [{                 
      name: 'keyWords',
      content: '预渲染'
    }]
    link: [{                
      rel: 'asstes',
      href: 'file.jing999.cn'
    }]
  }
}
</script> 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19