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 directory
TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md
按照 TROUBLESHOOTING 的提示 安装相应的依赖库
> yum install
pango.x86_64
libXcomposite.x86_64
libXcursor.x86_64
libXdamage.x86_64
libXext.x86_64
libXi.x86_64
libXtst.x86_64
cups-libs.x86_64
libXScrnSaver.x86_64
libXrandr.x86_64
GConf2.x86_64
alsa-lib.x86_64
atk.x86_64
gtk3.x86_64
ipa-gothic-fonts
xorg-x11-fonts-100dpi
xorg-x11-fonts-75dpi
xorg-x11-utils
xorg-x11-fonts-cyrillic
xorg-x11-fonts-Type1
xorg-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.i686
Error: Protected multilib versions: libXi-1.7.9-1.tl2.x86_64 != libXi-1.7.4-2.el7.i686
Error: Protected multilib versions: libXtst-1.2.3-1.tl2.x86_64 != libXtst-1.2.2-2.1.el7.i686
那么先可以删除报错的依赖库再安装
> yum remove
libXcursor-1.1.14-2.1.el7.i686
libXi-1.7.4-2.el7.i686
libXtst-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.PuppeteerRenderer
module.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.html
renderedRoute.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)
分享前端好文,点亮 在看