最近两周刚刚接手工程化的工作,领导希望能够集成一个可以预渲染html的插件来解决webpack生成的空白模板问题。

通过调研发现webpack有一个prerender-spa-plugin的插件完全可以满足需求,故将这个插件集成到我们内部的构建流程中。整个过程还是有很多坑的,主要我对node、webpack这些还是小白的阶段,所以犯了很多错误,特意记录一下。

为什么要使用prerender-spa-plugin

主要原因有两点:

1、SEO:SPA应用的SEO比较差,爬虫爬到的页面结构大多只有入口页,然而入口页又几乎没有什么内容,因此搜索排名很低。

2、首屏体验:由webpack生成的入口页基本上只有一个主js,本身页面没有内容,因此在这个js加载完成之前,用户看到的都是一片空白。为了解决这个问题,一般是把规定好的静态页给后台,用户请求直接返回的是静态页,这样在主js加载之前用户还是能看到一些东西的。但是这样也会有问题,比如我们想做一个Loading的组件放到首屏,就非常麻烦,同时也是又一个和后台沟通的成本(其实就是大佬不想总是依赖后台-_-)。所以如果我们自己能直接生成体验良好的首屏页面,那肯定是极好的。

这就是prerender-spa-plugin的作用,它能够直接生成拥有静态结构的html,可以尽情地往首屏里面放入你想展现的东西。

安装

执行npm i prerender-spa-plugin即可,但是如果不能够翻墙的话就会遇到一个坑。

prerender-spa-plugin插件是需要依赖puppeteer的,也就是谷歌出品的无头浏览器插件,这个插件会下载最新版的chromium(大约200M ),所以如果不能翻墙,下载的时候就报错了。


如图中所示,可以通过设置参数跳过该步骤,但是如果省略了,调用的时候还会报错。

网上大多搜到的解决办法都是针对使用puppeteer本身的,通过指定本机路径再启动,但是prerender-spa-plugin在puppeteer外层,因此并不适用。这个问题处理的过程比较长,我放到下面再描述,这里先讲能够翻墙的情况下之后的使用。

webpack中配置

使用的主要的目的就是取代build后生成的html,因此需要修改的就是webpack.prod.conf.js这个文件,一般在这文件中如果使用脚手架工具会有html-webpack-plugin的插件,如果有就不要动了,因为prereder的插件是需要这个插件生成的html作为模板的,只需要在html-webpack-plugin的配置后加上新的配置即可。

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const baseWebpackConfig = require('./webpack.base.conf')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRendererconst webpackConfig = merge(baseWebpackConfig, {plugins: [// vue-cli生成的配置中就已有这个了,不要动new HtmlWebpackPlugin({filename: config.build.index,template: 'index.html',inject: true,minify: {removeComments: true,collapseWhitespace: true,removeAttributeQuotes: true},chunksSortMode: 'dependency'}),// 在vue-cli生成的文件的基础上,只有下面这个才是我们要配置的new PrerenderSPAPlugin({// 生成文件的路径,也可以与webpakc打包的一致。// 下面这句话非常重要!!!// 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。staticDir: path.join(__dirname, '../dist'),// 对应自己的路由文件,比如index有参数,就需要写成 /index/param1。routes: ['/', '/index', '/skin', '/slimming', '/exercise', '/alPay', '/wxPay'],// 这个很重要,如果没有配置这段,也不会进行预编译renderer: new Renderer({inject: {foo: 'bar'},headless: false,// 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。renderAfterDocumentEvent: 'render-event'})})]
})

到此为止,如果只是个人使用的话,就全部OK了,之后在需要预渲染的页面的js中触发docurender-event事件(比如vue中就在main.js的mounted函数中加上dispatchEvent),执行npm run build 就会生成预渲染的html,至于具体的配置项,可以去github上的prerender-spa-plugin查看 https://github.com/chrisvfritz/prerender-spa-plugin

踩坑

首先我们的项目是要集成到所有开发人员都要是使用的工程化工具中,因此就需要考虑刚才安装时候的两个问题:
1、假设所有的开发人员都不能翻墙,要怎么下载这个插件?
2、200M大小的chromium是不是太大?如果每个项目都要装这么大的插件很显然会太臃肿。

针对这两个问题,我们最终讨论的方案如下:
1、将prerender-spa-plugin变成我们自己的组件(简称myPlugin)
2、将myPlugin中的puppeteer依赖指向全局的myPUppeteer(本来是指向它自己的puppeteer)
3、将prerender-spa-plugin中依赖的puppeteer组件也变成我们自己的(用于解除强依赖,简称myPuppeteer)
4、我个人将不同系统的最新版chromium下载到公司的ftp中
5、修改myPuppeteer组件里下载chromium的地址,指向ftp
6、在myPlugin中添加错误提示,当require不到puppeteer时提示开发者全局安装myPuppeteer

这样一通操作的最终效果:我们的开发人员只需要在第一次使用该插件时,全局安装一次myPuppeteer,并且不会有网络问题。

当然每个项目还是要安装myPlugin的

下面按照这个顺序说一下要怎么搞。

实现步骤

步骤一/二

首先要找到哪里依赖了puppeteer

1、prerender-spa-plugin里:


2、@prerender/renderer-puppeteer里:


所以我们需要在@prerender/renderer-puppeteer里替换掉依赖puppeteer的这句话

try{puppeteer = require('prerender-browser')
}catch(err){console.log("You are using prerender-html-plugin to generate html but no puppeteer installed");console.log("If you don't want this function, you can set prerender to false in marauder.config");console.log("If you want this function, you can run:1、npm install -g prerender-browser  2、npm link prerender-browser");
}

prerender-browser就是上文中的myPuppeteer组件。

try catch是为了能够在使用过程中可以在控制台输出报错语句。

这里可以看到我提示大家执行两句node命令

1、npm install -g prerender-browser

2、npm link prerender-browser

这里涉及到一个全局包的引用问题:
当我全局安装并且代码引用之后,我发现还是会报没有定义的错误。经过查询后发现require会从node_modules中查询所需的包,直到最顶层的全局变量。如果全局安装但并没有生效,就是因为环境变量中没有配置全局的node_modules路径。

所以在网上很多方法都是要去设置环境变量,但还有另一种简单的方法就是直接执行node link <package_name> 这个命令。npm link命令可以将一个任意位置的npm包链接到全局执行环境,这样就不会有引用无法找到的问题了。

步骤三/四/五

在puppeteer的BrowserFetcher.js文件中可以找到DEFAULT_DOWNLOAD_HOST和downloadURLs这两个变量,将这两个变量替换为公司内部可以访问的资源地址即可。

const DEFAULT_DOWNLOAD_HOST = 'http://www.fanqiangma.com';
const downloadURLs = {linux: '%s/chromium-browser-snapshots/Linux/chrome-linux.zip',mac: '%s/chromium-browser-snapshots/Mac/chrome-mac.zip',win32: '%s/chromium-browser-snapshots/Win32/chrome-win32.zip',win64: '%s/chromium-browser-snapshots/Win64/chrome-win32.zip',
};

这里还有两个坑:

1、在BrowserFetcher.js代码的下载地址上原本会拼上版本号,比如:

const url = util.format(downloadURLs[this._platform], this._downloadHost,revision);

revision就代表版本号,这个版本号是从puppeteer的package.json中读取的,这个参数即用来拼接下载的url,同时还用来指定chromium的执行地址。这里我们只需要修改下载地址,所以我将代码中需要拼接版本号的url都去掉了revision这个参数,否则会提示无法下载。

2、即便安装时能够下载了,但在运行时,会报无法关闭puppeteer实例的错误。看代码发现,puppeteer在启动的时候(launch函数)还需要指定到chromium的安装地址,这里还需要上面的revision参数,修改Puppeteer.js中的启动函数

  static launch(options) {options.executablePath = this.executablePath('revision');return Launcher.launch(options);}

这里的代码比较迷,我也没有太看懂,为什么只是修改了下载地址却没有自动指定启动目录,有兴趣的大佬可以探究一下。

TIPS:

提取和发布组件的时候遇到两个小问题:
1、将组件拆分成自己的组件之后,有一些依赖就需要咱们手动添加到package.json中了,这个大家根据提示一一加上就好。
2、在npm发布组件的时候遇到了一个非常白痴的错误,首先淘宝源是不能够发布组件的,必选换成npm源,但是我当时在网上搜到的大多数npm源都是http://www.npmjs.org。这个源安装依赖是不会有问题的,但是如果想要发布必须是 https://registry.npmjs.org,否则就会报错。这个真的是坑死我了,我一开始都没有怀疑过npm源的正确性,而且windos使用npm发包还真的就有issue。。。。。

结尾

到此,所有的工作就全部完成了,经过试验,我们组的小伙伴都可以愉快的生成静态页了。

这是我第一次写文章记录工作中的技术,也是第一次用markdown,可能写的不太好,啰嗦的地方或者没有提到的点还希望见谅,如果有问题欢迎指出。

参考文章:
1、 puppeteer 安装失败的解决办法
2、 vue项目做seo(prerender-spa-plugin预渲染)

预渲染插件prerender-spa-plugin使用总结相关推荐

  1. Vue SPA项目SEO优化之预渲染Prerender-spa-plugin

    目的 由于基于Vue的SPA项目普通的爬虫无法爬取项目的静态文本的内容,通过预渲染插件prerender-spa-plugin解决vue的SPA项目的SEO问题. 可以看到项目编译后的index.ht ...

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

    本文主要是介绍使用prerender-spa-plugin插件在针对前端代码进行预渲染. 预渲染(SSG)和服务端(SSR)渲染有一定的区别,大家想要了解的话可以看:https://segmentfa ...

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

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

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

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

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

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

  6. Vue2.x项目SPA的SEO解决方案(预渲染-Prerendering)

    Copyright 2019-06-03, Jachin QQ: 381558301 Email: 381558301@qq.com 前端最主要的任务除了是界面展示和业务逻辑处理,当然还有对Crawl ...

  7. ajax div 赋值重新渲染_优化向:单页应用多路由预渲染指南

    前言 Ajax 技术的出现,让我们的 Web 应用能够在不刷新的状态下显示不同页面的内容,这就是单页应用.在一个单页应用中,往往只有一个 html 文件,然后根据访问的 url 来匹配对应的路由脚本, ...

  8. 构建时预渲染:网页首帧优化实践

    前言 自JavaScript诞生以来,前端技术发展非常迅速.移动端白屏优化是前端界面体验的一个重要优化方向,Web 前端诞生了 SSR .CSR.预渲染等技术.在美团支付的前端技术体系里,通过预渲染提 ...

  9. 预渲染vue.js应用程序(使用node或laravel)

    服务器端渲染现在非常流行.但它也并非没有缺点.预渲染是一种替代方法,在某些情况下甚至可能更好.下面我们来看一下如何预渲染vue.js应用程序. 在本文中,我们将探讨预渲染如何与vue.js一起工作,并 ...

最新文章

  1. php自定义扩展函数,Laravel框架中扩展函数、扩展自定义类的方法
  2. (转)static 变量
  3. kibana 更新 索引模式_Kibana对索引动态加字段显示
  4. 底层技术革命是如何爆发的?_转
  5. CentOS7 搭建基于DPDK的FD.io VPP环境-1
  6. 6N+/-1素数测试法
  7. 使用xshell-ssh连接服务器被经常意外中断(Disconnected from remote host)
  8. MySQL索引常见面试题(2022版)
  9. php获取随机的六位数,php生成随机六位数密码代码
  10. 4-20mA电流输出设计方案
  11. MySQL Enterprise Backup使用简介
  12. window下编译ffmpeg--mys2下安装对应库编译ffmpeg
  13. 2020身高体重标准表儿童_2020年最新身高体重对照表来啦!快来看看您的娃达标没...
  14. gif软件(ShareX)
  15. 给HTML页面设置背景音乐
  16. 自适应均衡器的设计与仿真
  17. catalina.home和catalina.base
  18. 麻球繁衍(Tribbles 概率dp)
  19. input输入框设置输入值
  20. Windows cmd 命令行清空

热门文章

  1. 不小心点了计算机一键还原怎么操作,电脑系统如何一键还原,教您电脑系统一键还原的操作...
  2. iOS7不越狱干掉新浪微博客户端广告…
  3. matebook14装鸿蒙系统,华为将推出H6鸿蒙系统子母路由系统、MateBook 16 笔记本 和 MateView 显示器...
  4. 都在建设数据能力,爱数为什么强调全域?
  5. 这11位作家,要用AI写科幻小说了
  6. 监控硬盘与普通硬盘有什么分别,被删除视频恢复方法。
  7. qrcode生成二维码,canvas转化为图片
  8. 2019计算机文都考研百度云,2019文都考研全年集训营.pdf
  9. linux 永久修改pending signals的值
  10. 051 <css语法> 学习之: 常用标签(input等)