Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue预渲染插件prerender-spa-plugin使用全记录 #14

Open
masterkong opened this issue Apr 8, 2020 · 2 comments
Open

Vue预渲染插件prerender-spa-plugin使用全记录 #14

masterkong opened this issue Apr 8, 2020 · 2 comments

Comments

@masterkong
Copy link
Owner

masterkong commented Apr 8, 2020

Vue预渲染插件prerender-spa-plugin使用全记录

服务器端渲染 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')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer

module.exports = {
  plugins: [
    ...
    new HtmlWebpackPlugin(),
    ...
    new PrerenderSPAPlugin({
      // 必填 - 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: new Renderer({
        // puppeteer配置参数
        args: ['--no-sandbox', '--disable-setuid-sandbox'], 
        // 当设置为false时,可以看到渲染时调用的浏览器,在调试页面时非常有用
        headless: true,
        // 可选 - 当 document 触发以下事件时才开始渲染页面,使用vue组件时建议配置
        renderAfterDocumentEvent: 'render-event'
      })
    })
  ]
}

配置了 renderAfterDocumentEvent: 'render-event'时,vue组件需要进行相应的修改

new Vue({
    el: '#app',
    ...
    mounted() {
        // 通知 prerender-spa-plugin 可以渲染了
        document.dispatchEvent(new Event('render-event'));
    }
});

踩坑

经过上面的步骤,prerender-spa-plugin插件的配置算是完成了,但并不代表就一切顺利,下面就记录几个遇到的问题。

1、渲染的页面成功生成,但是页面运行后却是静态页面,相应的 js 不起作用

这个问题是 Vue主组件模板也需要设置跟el配置项一样的 id

// App.vue

<template>
    <div id="app">
       
    </div>
</template>

2、编译过程中一直卡死

这个问题一般是渲染的页面出错或者请求的 css/js 文件没有正常加载,导致没有触发renderAfterDocumentEvent配置的事件名。

  • 用浏览器打开渲染好的页面来排查报错。
  • 在编译环境中,对请求的 css/js 进行逐一测试,看是否能正常加载(比如在Linux中使用curl命令)。

参考

@qappleh
Copy link

qappleh commented Apr 26, 2020

你好 文章可以授权"深圳湾码农"公众号转载吗?会注明作者和原文链接

@masterkong
Copy link
Owner Author

你好 文章可以授权"深圳湾码农"公众号转载吗?会注明作者和原文链接

可以

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants