Vue预渲染插件prerender-spa-plugin使用全记录
给前端大学加星标,提升前端技能.)
作者:红烧牛肉面
https://github.com/masterkong/blog/issues/14
服务器端渲染 vs 预渲染 (SSR vs Prerendering)
如果你调研服务器端渲染 (SSR) 只是用来改善少数营销页面(例如 /, /about, /contact 等)的 SEO,那么你可能需要预渲染。无需使用 web 服务器实时动态编译 HTML,而是使用预渲染方式,在构建时 (build time) 简单地生成针对特定路由的静态 HTML 文件。优点是设置预渲染更简单,并可以将你的前端作为一个完全静态的站点。
预渲染页面方式由于不需要web服务器的参与,设置比SSR更简单,特别适合用来展示一些静态页面,比如根据页面UI来自动生成骨架屏。
安装
npm install prerender-spa-plugin --save-dev
prerender-spa-plugin本身的安装非常简单,但是它所依赖的 puppeteer 却有可能让你吃苦头。由于网络原因,直接从npm安装puppeteer有可能会失败,解决办法网络上有很多,最简单就是设置淘宝的镜像源npm config set registry https://registry.npm.taobao.org。
puppeteer的介绍可以参考之前的文章 Puppeteer入门简介
验证puppeteer
顺利安装完prerender-spa-plugin后,提前在环境中验证 puppeteer能让你少走点弯路。这点可能在自己开发用的电脑上不明显,但是在部署环境中就有可能踩坑。
本文用了一个简单的node脚本来验证puppeteer,如果成功生成了百度的截屏baidu.png,预渲染插件的使用就成功一大半了。
const puppeteer =require('puppeteer');(async()=>{const browser =await puppeteer.launch({args:['--no-sandbox','--disable-setuid-sandbox']});const page =await browser.newPage();await page.goto('https://www.baidu.com');await page.screenshot({path:'baidu.png'});await browser.close();})();
在 CentOS 7.2 环境中验证就遇到了缺少了依赖库的错误。
/chrome-linux/chrome: error while loading shared libraries: libXss.so.1: cannot open shared object file: No such file or directoryTROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md
按照 TROUBLESHOOTING 的提示 安装相应的依赖库
> yum installpango.x86_64libXcomposite.x86_64libXcursor.x86_64libXdamage.x86_64libXext.x86_64libXi.x86_64libXtst.x86_64cups-libs.x86_64libXScrnSaver.x86_64libXrandr.x86_64GConf2.x86_64alsa-lib.x86_64atk.x86_64gtk3.x86_64ipa-gothic-fontsxorg-x11-fonts-100dpixorg-x11-fonts-75dpixorg-x11-utilsxorg-x11-fonts-cyrillicxorg-x11-fonts-Type1xorg-x11-fonts-misc -y> yum update nss -y
如果在上述依赖库的安装过程还遇到类似以下报错
Error: Protected multilib versions: libXcursor-1.1.15-1.tl2.x86_64 != libXcursor-1.1.14-2.1.el7.i686Error: Protected multilib versions: libXi-1.7.9-1.tl2.x86_64 != libXi-1.7.4-2.el7.i686Error: Protected multilib versions: libXtst-1.2.3-1.tl2.x86_64 != libXtst-1.2.2-2.1.el7.i686
那么先可以删除报错的依赖库再安装
> yum removelibXcursor-1.1.14-2.1.el7.i686libXi-1.7.4-2.el7.i686libXtst-1.2.2-2.1.el7.i686 -y
预渲染配置
prerender-spa-plugin的用法在官方文档有着很详细的说明,这里挑几个主要的配置项说下。(如果webpack中有用到 html-webpack-plugin 插件,一般是在此之后再配置 prerender-spa-plugin)
const path =require('path')constPrerenderSPAPlugin=require('prerender-spa-plugin')constRenderer=PrerenderSPAPlugin.PuppeteerRenderermodule.exports ={plugins:[...newHtmlWebpackPlugin(),...newPrerenderSPAPlugin({// 必填 - webpack输出用于预渲染的html文件的路径.staticDir: path.join(__dirname,'dist'),// 必填 - 需要预渲染的vue-router路由.routes:['/','/about'],// 可选 - 预渲染的html文件路径。默认为 path.join(staticDir, 'index.html')indexPath: path.join(__dirname,'dist/index.html'),// 可选 - 对html文件内容以及生成的最终路径进行自定义处理postProcess(renderedRoute){// 删除html中的空白字符renderedRoute.html = renderedRoute.html.split(/>[\s]+gmi).join('><');// 将生成的html重命名为prerender.htmlrenderedRoute.outputPath = path.join(__dirname,'dist', renderedRoute.route,'prerender.html');return renderedRoute},// The actual renderer to use.renderer:newRenderer({// puppeteer配置参数args:['--no-sandbox','--disable-setuid-sandbox'],// 当设置为false时,可以看到渲染时调用的浏览器,在调试页面时非常有用headless:true,// 可选 - 当 document 触发以下事件时才开始渲染页面,使用vue组件时建议配置renderAfterDocumentEvent:'render-event'})})]}
配置了 renderAfterDocumentEvent: 'render-event'时,vue组件需要进行相应的修改
newVue({el:'#app',...mounted(){// 通知 prerender-spa-plugin 可以渲染了document.dispatchEvent(newEvent('render-event'));}});
踩坑
经过上面的步骤,prerender-spa-plugin插件的配置算是完成了,但并不代表就一切顺利,下面就记录几个遇到的问题。
渲染的页面成功生成,但是页面运行后却是静态页面,相应的 js 不起作用
这个问题是 Vue主组件模板也需要设置跟el配置项一样的 id。
// App.vue<div id="app">div>template>
编译过程中一直卡死
这个问题一般是渲染的页面出错或者请求的 css/js 文件没有正常加载,导致没有触发renderAfterDocumentEvent配置的事件名。
用浏览器打开渲染好的页面来排查报错。
在编译环境中,对请求的 css/js 进行逐一测试,看是否能正常加载(比如在Linux中使用curl命令)。
参考
setting-up-chrome-linux-sandbox
prerender-spa-plugin
服务器端渲染 vs 预渲染 (SSR vs Prerendering)
分享前端好文,点亮 在看 
