本文主要是介绍使用prerender-spa-plugin插件在针对前端代码进行预渲染。

预渲染(SSG)和服务端(SSR)渲染有一定的区别,大家想要了解的话可以看:https://segmentfault.com/a/1190000023469150。

背景

因为之前的网站是使用Vue开发的,这种前端JavaScript渲染的开发模式,对于搜索引擎来说非常的不友好,没有办法抓取到有效的信息。因此为了进行SEO,我们需要对页面进行一些预渲染。

预渲染比较适合静态或者变化不大的页面,能够通过部署前的一次静态渲染,将页面上大部分内容都渲染出来。这样搜索引擎在爬取的时候,就能够爬到相关的内容信息。

现状

目前商企通官网情况列举如下:

  • 技术栈使用的是Vue,脚手架使用的是vue-cli,使用JavaScript前端渲染方案(这个方案对技术栈没有要求,兼容所有方案)

  • 发布工具使用的是公司的工具,打包过程中,HTML资源传递到A域名下,CSS、JS、Image等资源传递到B域名下。

目标

希望能够通过预渲染,让页面在初次访问没有执行JavaScript时,就能够携带足够的信息,即将JavaScript渲染的内容提前渲染到HTML中。

发布期望不做过多的修改。

方案

我们本次方案主要采用的是prerender-spa-plugin这个webpack的插件来实现的。

它的主要原理是启动浏览器,渲染完成后抓取HTML,然后再替换掉原有HTML。

我们需要实现预渲染,那么我们需要完成以下几件事情:

  1. 插件引入和配置。

  2. 本地验证。

  3. 改造打包构建流程。

  4. 线上验证。

下面,我们一个一个来说下,我们如何做这个事情的。

插件引入和配置

首先,我们需要引入一个预渲染插件,执行命令:

mnpm i prerender-spa-plugin -D

这个命令除了安装插件本身以外,依赖了puppeteer,然后puppeteer又依赖落地chromium,所以最后我们其实是需要在依赖中安装一个chromium。

如果大家安装puppeteer非常慢或者经常失败,可以参考下这个文档中的方法:https://brickyang.github.io/2019/01/14/国内下载安装-Puppeteer-的方法/,指定puppeteer下载镜像。

安装完成后,我们就可以在webpack的配置文件中增加对应的配置了。

如果大家使用的也是vue-cli,那么我们需要增加的配置是在vue.config.js中,如果是直接修改webpack的配置,那么方法也是类似。

下面我们以vue.config.js的修改为例:

const PrerenderSPAPlugin = require('prerender-spa-plugin');module.exports = {...,configureWebpack: {...,chainWebpack: config => {config.plugin('prerender').use(PrerenderSPAPlugin, [{staticDir: path.join(__dirname, 'build'),routes: ['/','/product','/case','/about','/register',],renderer: new Renderer({headless: true,executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',// 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。renderAfterDocumentEvent: 'render-event',}),},]);}}
}

因为我们在项目中使用了webpack-chain,所以我们的语法是上面类似链式调用的方法。如果大家直接修改的话,就是采用vue的原来的修改配置的方式。

下面我简单的给大家介绍下,上面的一些配置的含义:

  • staticDir:这个指的是输出预渲染文件的目录。

  • routes:这个指的是需要预渲染的路由。这里需要注意的是,vue的hash路由策略是没有办法进行预渲染的,所以如果要进行预渲染,需要改成history路由,然后预渲染后会变成多个HTML文件,每个文件都带全量路由功能,只是默认路由不一样而已。

  • renderer:这个是可以传入的puppeteer的配置,我说下我用过的这几个配置:

    • headless:是否使用headless模式渲染,建议选择true。

    • executablePath:指定chromium的路径(也可以是chrome)。这个配置在talos中是需要指定的,talos中的chrome地址默认是/usr/bin/google-chrome。

    • renderAfterDocumentEvent:这个的意思是在哪个事件触发后,进行预渲染的抓取。这个事件是需要在代码中自己使用dispatchEvent来触发的,这样自己可以控制预渲染的时机。一般我们都是在最外层的组件的mounted钩子中触发,如果大家有其他需求也可以自己指定。

更多的可以看插件的官方文档。

开发完成后,我们可以在本地构建一次,看看是否能够生成符合我们预期的代码。

vue.config.js指定publicPath导致预渲染失败问题

如果大家和我这个项目一样,在vue.config.js中传入publicPath指定第三方CDN域名,会将CSS、JavaScript、Image等资源传递到不同的域名上,类似配置如下:

module.exports = {...,publicPath: `//awp-assets.cdn.net/${projectPath}`,...,
};

如果没有预渲染,这种方案会在打包完成后分别上传至不同的CDN域名,在线上访问是没有问题的。

但是在本地,这个时候CSS和JS资源还没有上传到CDN中,浏览器无法加载对应的资源进行页面的渲染,这样的话会导致本地预渲染失败。

为了解决这个问题,有两个解决思路。

  1. 【推荐】调整打包的策略,将非HTML资源也上传至同一个CDN域名下,这样的话,我们就可以使用相对路径来访问这些资源,不需要传递新域名给publicPath,这样我们在本地构建的时候就可以访问到这些值。这个是个比较靠谱合理的方法,比较推荐。

  2. (如果上面那个方法实在无法实现,那么可以考虑这个方案)在预渲染之前,资源是在本地可以通过相对路径访问到的,这个时候使用替换的方式把HTML中的资源文件地址替换掉,然后预渲染完成后再替换回来。这个方法比较hack,但是经过实际验证确实是可以生效。具体的做法是自己写一个简单的webpack插件。

首先,我们需要安装一个新的NPM包,用来对文件中的内容进行替换(自己写正则也可以,不过用这个会方便一些),具体命令如下:

mnpm i replace-in-file

安装后,我们需要增加两个webpack的插件,分别作用在afterEmit和done这两个钩子节点上。如果想要了解为什么是这两个钩子节点,那么你可以阅读下webpack插件的开发章节。

const replace = require('replace-in-file');let publicPath = `//awp-assets.cdn.net/${projectPath}`;// 第1个替换插件,主要是将原先打包过程中带有CDN域名的路径替换成相对路径
function ReplacePathInHTMLPlugin1(cb) {this.apply = compiler => {if (compiler.hooks && compiler.hooks.afterEmit) {compiler.hooks.afterEmit.tap('replace-url', cb);}};
}function replacePluginCallback1() {replace({files: path.join(__dirname, '/build/**/*.html'),from: new RegExp(publicPath.replace(/([./])/g, (match, p1) => {return `\\${p1}`;}),'g'),to: '',}).then(results => {console.log('replace HTML static resources success', results);}).catch(e => {console.log('replace HTML static resources fail', e);});
}// 第2个替换插件,主要是将预渲染后的HTML文件中的相对路径替换成带有CDN域名的路径
function ReplacePathInHTMLPlugin2(cb) {this.apply = compiler => {if (compiler.hooks && compiler.hooks.done) {compiler.hooks.done.tap('replace-url', cb);}};
}function replacePluginCallback2() {replace({files: path.join(__dirname, '/build/**/*.html'),from: [/href="\/css/g, /href="\/js/g, /src="\/js/g, /href="\/favicon.ico"/g],to: [`href="${publicPath}/css`,`href="${publicPath}/js`,`src="${publicPath}/js`,`href="${publicPath}/favicon.ico"`,],}).then(results => {console.log('replace HTML static resources success', results);}).catch(e => {console.log('replace HTML static resources fail', e);});
}

上述代码就是我们需要增加的两个webpack的替换插件和对应的回调函数,接下来我们看下在webpack中怎么配置。

module.exports = {publicPath,outputDir,crossorigin: 'anonymous',chainWebpack: config => {config.plugin('replaceInHTML').use(new ReplacePathInHTMLPlugin1(replacePluginCallback));config.plugin('prerender').use(PrerenderSPAPlugin, [{staticDir: path.join(__dirname, 'build'),// 我们应该只会使用根路径,因为是hash路由,所以其他页面预渲染没有意义,因此不进行预渲染routes: ['/'],renderer: new Renderer({headless: true,executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',// 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。renderAfterDocumentEvent: 'render-event',}),},]);config.plugin('replaceInHTML2').use(new ReplacePathInHTMLPlugin2(replacePluginCallback2));}

我们第一个替换插件,需要在预渲染插件前执行,在预渲染插件执行前,将HTML中的资源的地址替换成本地的相对路径;第二个则需要在替换后执行,这样将预渲染后端资源中的相对路径,再替换成CDN地址。

通过这两个插件,我们就可以完成在预渲染前替换掉路径完成预渲染,然后在预渲染后再完成替换保证线上可用。

本地验证

通过上面的方式,我们应该已经得到了一个预渲染完成的HTML,接下来我们就是要验证下这个HTML是否符合预期了。

比较简单的验证方式,可以直接访问那个HTML文件,或者启动一个HTTP静态资源服务来验证。

验证的话,你可以使用curl来进行请求,这种情况下JavaScript不会执行,你可以看到HTML的源文件是什么。

FAQ

  1. 在chrome版本比较低的情况下(比如v73),会提示渲染失败?

这个是因为chrome的版本过低,导致预渲染失败。解决方案是升级chrome/chromium版本到最新(目前v93无问题)版本即可。

总结

如果我们需要实现SSG(静态站点生成),那么我们可以使用prerender-spa-plugin这个插件来做,这个插件可以在本地启动chromium来抓取HTML内容,再写回HTML文件中,如我们我们需要对其中的静态资源文件进行处理,我们可以使用替换的插件,针对处理前后的内容进行替换,来达到我们的诉求。

直接替换压缩后代码虽然看起来有效,但是这个强依赖压缩的算法和内容顺序,强烈不推荐直接用脚本修改替换压缩后文件,最好是在webpack的done钩子回调中处理。

如何使用prerender-spa-plugin插件对页面进行预渲染相关推荐

  1. 如何使用prerender-spa-plugin插件,对页面进行预渲染

    背景 因为之前的网站是使用Vue开发的,这种前端JavaScript渲染的开发模式,对于搜索引擎来说非常的不友好,没有办法抓取到有效的信息.因此为了进行SEO,我们需要对页面进行一些预渲染. 预渲染比 ...

  2. 关于前端spa项目seo优化改造方案(预渲染,ssr,nuxt比较)

    目前的的前端项目为基于vuecli3搭建的spa项目,由于需求提出需要对首页,部分内容页面做seo优化,涉及到前端项目的框架和部分页面的改造. 目录 SEO简介 关于收录 关于链接 一.预渲染 二.s ...

  3. vue使用prerender预渲染配合vue-meta实现单页面实现SEO优化

    公司项目在已在开发完成的情况下通知需要做SEO优化.因为项目使用的是vue做的单页面应用,顿时人都不好了,只好网上搜罗出来一些配置(其实是另一个带我的老大哥他做的,但是他要走了,工作交接给我, 我需要 ...

  4. prerender html5,HTML5 VUE单页应用 SEO 优化之 预渲染(prerender-spa-plugin)

    前言:当前 SPA 架构流行的趋势如日中天,前后端分离的业务模式已经成为互联网开发的主流方式,但是 单页面 应用始终存在一个痛点,那就是 SEO, 对于那些需要推广,希望能在百度搜索时排名靠前的网站而 ...

  5. nextjs系列教程(四):页面预渲染-SSG

    NextJs 页面预渲染方案 1.1 预渲染介绍 原因: 浏览器访问网站的流程是首先对React组件做初始化渲染,此是页面并没有展示接口数据,只是对初始的state数据进行渲染.然后通过 useEff ...

  6. Mybatis Plugin插件安装破解及使用

    为什么80%的码农都做不了架构师?>>>    Mybatis Plugin 一.Mybatis Plugin插件是什么 提供Mapper接口与配置文件中对应SQL的导航 编辑XML ...

  7. 如何写一个Jquery 的Plugin插件

    JQuery Plugin插件,如果大家不明白什么是JQuery插件或都不清楚如何编写可以查看其官方的网站:jQuery Authoring Guidelines 好了,下面有一些我觉得想做一个好的插 ...

  8. Jenkins的HTML Publisher Plugin插件添加与配置(插件的下载、安装、更新、配置)

    1.搜索插件HTML Publisher Plugin,找不到 2.在资源库中搜索 链接下载地址:http://updates.jenkins-ci.org/download/plugins/ 在这里 ...

  9. 优酷iOS插件化页面架构方法

    Python实战社群 Java实战社群 长按识别下方二维码,按需求添加 扫码关注添加客服 进Python社群▲ 扫码关注添加客服 进Java社群▲ 作者 | iOS一叶  来源 | 掘金,点击阅读原文 ...

最新文章

  1. Python3学习笔记-字符串和编码
  2. [Android Pro] Android源码编译后,再重编译所需要做的清理工作
  3. Oracle查询给表起别名
  4. python面试题及答案bt_公布上期Python笔试题答案,附带源码与运行结果
  5. view渐变色,透明度渐变
  6. CCIE-LAB-第十五篇-IPV6-BGP+VPN6+RT
  7. jQuery --- grep
  8. 解决 wamp网站访问慢的问题
  9. php 伪静态规则,在线将Apache Rewrite Rules伪静态规则转换为Nginx Rewrite伪静态规则...
  10. Windows环境下的NodeJS+NPM+Bower安装配置步骤
  11. anaconda使用github代码_使用这几款插件,能让你在GitHub看代码的效率翻倍
  12. B站陈睿:70 后也正在爱上哔哩哔哩
  13. 持有对象---Arrays.asList()和Collections.addAll()的性能比较
  14. 修改wifi密码后连接不上服务器,WiFi修改密码后,手机电脑连接不上
  15. 22.搜索大纲及重定向(Search Synonyms and Re-directs)
  16. 计算机打字键盘亮怎么设置,键盘指示灯亮着却不能打字的解决方法
  17. 三个小李子讲述安卓动画用法
  18. 使用Python进行12306抢票
  19. 我的世界java邮箱和密码_java实现邮箱找密码
  20. 请收起你的善良,越是心地善良的女人,通常命越差

热门文章

  1. 计算机一级中级实务难度,中级会计职称机考模式不适应怎么办?如何提高应试能力?...
  2. 微信小程序开发——项目组成员合作开发问题 no merge base found
  3. yum安装本地rpm包
  4. 神经网络与深度学习 作业8:RNN - 简单循环网络
  5. 【非真实渲染】【卡通渲染技术点介绍】
  6. 大学生学习指导课程材料
  7. Mercer's Theorem的证明
  8. <2021SC@SDUSC>【Overload游戏引擎】OvUI源码模块分析(一)——Core
  9. SYS-2722双域sys2722系统两级联音频分析仪
  10. 计算机代码可以在哪里查到,计算机的6 位数安全代码在哪里查看