文主要是介绍使用prerender-spa-plugin插件在针对前端代码进行预渲染。
预渲染(SSG)和服务端 渲染有一定的区别。
因为之前的网站是使用Vue开发的,这种前端JavaScript渲染的开发模式,对于搜索引擎来说非常的不友好,没有办法抓取到有效的信息。因此为了进行SEO,我们需要对页面进行一些预渲染。
预渲染比较适合静态或者变化不大的页面,能够通过部署前的一次静态渲染,将页面上大部分内容都渲染出来。这样搜索引擎在爬取的时候,就能够爬到相关的内容信息。
目前商企通官网情况列举如下:
希望能够通过预渲染,让页面在初次访问没有执行JavaScript时,就能够携带足够的信息,即将JavaScript渲染的内容提前渲染到HTML中。
发布期望不做过多的修改。
我们本次方案主要采用的是prerender-spa-plugin这个webpack的插件来实现的。
它的主要原理是启动浏览器,渲染完成后抓取HTML,然后再替换掉原有HTML。
我们需要实现预渲染,那么我们需要完成以下几件事情:
下面,我们一个一个来说下,我们如何做这个事情的。
首先,我们需要引入一个预渲染插件,执行命令:
这个命令除了安装插件本身以外,依赖了puppeteer,然后puppeteer又依赖落地chromium,所以最后我们其实是需要在依赖中安装一个chromium。
如果大家安装puppeteer非常慢或者经常失败,可以参考下这个文档中的方法:https://brickyang.github.io/2019/01/14/国内下载安装-Puppeteer-的方法/,指定puppeteer下载镜像。
安装完成后,我们就可以在webpack的配置文件中增加对应的配置了。
如果大家使用的也是vue-cli,那么我们需要增加的配置是在vue.config.js中,如果是直接修改webpack的配置,那么方法也是类似。
下面我们以vue.config.js的修改为例:
因为我们在项目中使用了webpack-chain,所以我们的语法是上面类似链式调用的方法。如果大家直接修改的话,就是采用vue的原来的修改配置的方式。
下面我简单的给大家介绍下,上面的一些配置的含义:
- headless:是否使用headless模式渲染,建议选择true。
- executablePath:指定chromium的路径(也可以是chrome)。这个配置在talos中是需要指定的,talos中的chrome地址默认是/usr/bin/google-chrome。
- renderAfterDocumentEvent:这个的意思是在哪个事件触发后,进行预渲染的抓取。这个事件是需要在代码中自己使用dispatchEvent来触发的,这样自己可以控制预渲染的时机。一般我们都是在最外层的组件的mounted钩子中触发,如果大家有其他需求也可以自己指定。
更多的可以看插件的官方文档。
开发完成后,我们可以在本地构建一次,看看是否能够生成符合我们预期的代码。
如果大家和我这个项目一样,在vue.config.js中传入publicPath指定第三方CDN域名,会将CSS、JavaScript、Image等资源传递到不同的域名上,类似配置如下:
如果没有预渲染,这种方案会在打包完成后分别上传至不同的CDN域名,在线上访问是没有问题的。
但是在本地,这个时候CSS和JS资源还没有上传到CDN中,浏览器无法加载对应的资源进行页面的渲染,这样的话会导致本地预渲染失败。
为了解决这个问题,有两个解决思路。
首先,我们需要安装一个新的NPM包,用来对文件中的内容进行替换(自己写正则也可以,不过用这个会方便一些),具体命令如下:
安装后,我们需要增加两个webpack的插件,分别作用在afterEmit和done这两个钩子节点上。如果想要了解为什么是这两个钩子节点,那么你可以阅读下webpack插件的开发章节。
上述代码就是我们需要增加的两个webpack的替换插件和对应的回调函数,接下来我们看下在webpack中怎么配置。
我们第一个替换插件,需要在预渲染插件前执行,在预渲染插件执行前,将HTML中的资源的地址替换成本地的相对路径;第二个则需要在替换后执行,这样将预渲染后端资源中的相对路径,再替换成CDN地址。
通过这两个插件,我们就可以完成在预渲染前替换掉路径完成预渲染,然后在预渲染后再完成替换保证线上可用。
通过上面的方式,我们应该已经得到了一个预渲染完成的HTML,接下来我们就是要验证下这个HTML是否符合预期了。
比较简单的验证方式,可以直接访问那个HTML文件,或者启动一个HTTP静态资源服务来验证。
验证的话,你可以使用curl来进行请求,这种情况下JavaScript不会执行,你可以看到HTML的源文件是什么。
这个是因为chrome的版本过低,导致预渲染失败。解决方案是升级chrome/chromium版本到最新(目前v93无问题)版本即可。
如果我们需要实现SSG(静态站点生成),那么我们可以使用prerender-spa-plugin这个插件来做,这个插件可以在本地启动chromium来抓取HTML内容,再写回HTML文件中,如我们我们需要对其中的静态资源文件进行处理,我们可以使用替换的插件,针对处理前后的内容进行替换,来达到我们的诉求。
直接替换压缩后代码虽然看起来有效,但是这个强依赖压缩的算法和内容顺序,强烈不推荐直接用脚本修改替换压缩后文件,最好是在webpack的done钩子回调中处理。