ITPub博客

首页 > 数据库 > 数据库开发技术 > 前端预渲染机制引入实践

前端预渲染机制引入实践

原创 数据库开发技术 作者:前端下午茶 时间:2019-07-24 07:32:00 0 删除 编辑

周末想顺便把已经做好静态页面的webApp项目做一下SEO优化,由于不想写蹩脚的 SSR 代码,所以准备采用预渲染,本来想着网上有这么多预渲染的文章,随便找个来跟着做不就完了嘛,结果年轻的我付出了整个周末..... 这篇文章就记录一下最后是怎么配置的 T.T

声明:

  1. 以下配置只保留有必要的

  2. 生成目录这里使用 base代替,请自行修改

  3. vue-cli模板使用 webpack,其他模板类推

  4. Github - 配置了预渲染的demo :https://github.com/SHERlocked93/vue-style-codebase/tree/prerender

经过实践,预渲染后的页面在 FCP 指标上有 30% - 80% 左右的加载速度提升。

1. 简介与使用场景

我们知道 SPA 有很多优点,不过一个缺点就是对(不是 Google)愚蠢的搜索引擎的 SEO 不友好,为了照顾这些引擎,目前主要有两个方案:服务端渲染(Server Side Rendering)、预渲染(Prerending)。

如果你只需要改善少数页面(例如 /, /about, /contact 等)的 SEO,那么你可能需要预渲染。无需使用 web 服务器实时动态编译 HTML (服务端渲染, SSR),而是使用预渲染方式,在构建时(build time)简单地生成针对特定路由的静态 HTML 文件。它主要使用 prerender-spa-plugin 插件,其与SSR一样都可以加快页面的加载速度,并且侵入性更小,在已上线的项目稍加改动也可以轻松引入预渲染机制,而SSR方案则需要将整个项目结构推翻;

访问预渲染出来的页面在访问时与 SSR一样快,并且它将服务端编译HTML的时机提前到了构建时,因此也降低了服务端的压力,如果你的服务器跟我的一样买的 1M1G1核 的小水管服务器 ( 穷 ),那么预渲染可能更适合你。不过SSR和预渲染的使用场景还是有较明显的区别的。预渲染的使用场景更多是简单的静态页面。服务端渲染适用于复杂、较大型、与服务端交互频繁的功能型网站,比如电商网站。

2. 实践效果

经过实践,预渲染后的页面在 FCP 指标上有 40% - 80% 左右的加载速度提升。借用美团团队的一张实践图:


3. 安装配置

首先来看看相关技术栈:vue^2.5.2、vue-router^3.0.1、vue-cli^2.9.6、webpack^3.6.0、prerender-spa-plugin^3.3.0

下面来看看到底如何配置预渲染项目

3.1 安装

安装跟其他库一样

  1. # Yarn

  2. $ yarn add prerender-spa-plugin -D

  3. # or NPM

  4. $ npm install prerender-spa-plugin --save-dev

3.2 前端配置

首先看看文件结构,用的是vue-cli2的webpack模板生成的文件结构

  1. │ .babelrc

  2. │ index.html

  3. │ package.json

  4. │ README.md

  5. ├─build

  6. │ build.js

  7. │ check-versions.js

  8. │ utils.js

  9. │ vue-loader.conf.js

  10. │ webpack.base.conf.js

  11. │ webpack.dev.conf.js

  12. │ webpack.prod.conf.js

  13. ├─config

  14. │ dev.env.js

  15. │ index.js

  16. │ prod.env.js

  17. ├─src

  18. │ │ App.vue

  19. │ │ main.js

  20. │ │

  21. │ ├─assets

  22. │ ├─components

  23. │ ├─router

  24. │ │ index.js

  25. │ ├─styles

  26. │ ├─utils

  27. │ └─views

  28. │ BigData.vue

  29. │ CompanyHonor.vue

然后是router/index.js的配置,预渲染要求是histroy模式,有的文章说不需要history模式,这是错的,否则生成的页面都是同一个html。另外注意加上 base否则如果你希望跳转到二级页面的 localhost/base/home 时候,在页面中点击  <router-linkto="/home">home</router-link> 的时候会跳转 localhost/home

// src/router/index.js

  1. import Vue from 'vue'

  2. import Router from 'vue-router'



  3. Vue.use(Router)



  4. export default new Router({

  5. mode: 'history',

  6. base: '/base/',

  7. routes: [...]

  8. })

然后是config,这里注意 assetsPublicPath不是 ./,

// config/index.js

  1. const path = require("path")


  2. module.exports = {

  3. build: {

  4. index: path.resolve(__dirname, "../base/index.html"),

  5. assetsRoot: path.resolve(__dirname, ".."),

  6. assetsSubDirectory: "base/static",

  7. assetsPublicPath: "/",

  8. }

  9. }

然后是插件的配置,是放在 prod中的,因为只有build的时候会用

// build/webpack.prod.conf.js

  1. const path = require('path')

  2. const config = require('../config')

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

  4. const Renderer = PrerenderSPAPlugin.PuppeteerRenderer


  5. const webpackConfig = merge(baseWebpackConfig, {

  6. new PrerenderSPAPlugin({

  7. staticDir: config.build.assetsRoot,

  8. outputDir: path.join(config.build.assetsRoot, 'base'),

  9. indexPath: config.build.index,


  10. // 对应路由文件的path

  11. routes: [

  12. '/',

  13. '/BigData',

  14. '/CompanyHonor'

  15. ],


  16. renderer: new Renderer({

  17. headless: false, // 无桌面系统去掉

  18. renderAfterDocumentEvent: 'render-event'

  19. })

  20. })

  21. })

注意了,如果你的项目是部署在linux/centOS之类没有桌面的系统,需要把 headless:false去掉,如果centOS报没有找到lib的错,请参考 issue-200 的解决办法。

另外注意上面一个 renderAfterDocumentEvent:'render-event'了么,这个意思是在 render-event事件触发之后执行prerender,这个事件我们在main.js中mounted钩子触发

// src/main.js

  1. import Vue from 'vue'

  2. import App from './App'


  3. new Vue({

  4. el: '#app',

  5. render: h => h(App),

  6. mounted() {

  7. document.dispatchEvent(new Event('render-event'))

  8. }

  9. })

还有个配置要注意下在 build/utils.js 中的 ExtractTextPlugin.extract 的 publicPath ,否则一些vue中引用的资源会找不到

// build/utils.js

  1. ExtractTextPlugin.extract({

  2. use: loaders,

  3. fallback: 'vue-style-loader',

  4. // publicPath: '../../'

  5. })

这时候执行 npm run build 就可以生成刚刚配置在 PrerenderSPAPlugin 插件中 routes 中的页面 html 了,这过程中会一闪而过的短暂打开 chromium 浏览器,不用管。

最后生成的目录树:

  1. │ index.html

  2. ├─BigData

  3. │ index.html

  4. ├─CompanyHonor

  5. │ index.html

  6. └─static

  7. ├─css

  8. ├─fonts

  9. ├─img

  10. └─js

最后如果希望进一步优化生成出来页面的 SEO,可以配合 vue-meta-info 这个网上有很多文章,就不赘述了

3.3 nginx配置

顺便贴一下nginx配置

  1. server {

  2. listen 80;

  3. server_name localhost;

  4. root /nginx-1.14.0/html;


  5. error_page 500 502 503 504 /50x.html;


  6. location ~ ^/base/ {

  7. try_files $uri $uri/ /base/index.html;

  8. }

  9. location = /50x.html {

  10. root html;

  11. }

  12. }



网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出~

参考:

  1. Vue.js 服务器端渲染指南

  2. Vue 服务端渲染 & 预渲染

  3. vue-cli v3, can't get it to work.. issue #215

  4. unable to start Puppeteer. Failed to launch ... issue #200

  5. When assetsPublicPath is set, the... issue #176

  6. vue.js vue-router history模式路由,域名二级目录子目录nginx配置

  7. 处理 Vue 单页面 Meta SEO的另一种思路

原文作者:前端下午茶;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-07-03

  • 博文量
    45
  • 访问量
    18408