共计 2254 个字符,预计需要花费 6 分钟才能阅读完成。
prerender-spa-plugin 预渲染:构建阶段生成匹配预渲染路径的 html 文件(注意:每个需要预渲染的路由都有一个对应的 html)。构建出来的 html 文件已有部分内容。
prerender-spa-plugin 使用
安装 prerender-spa-pluginnpm install prerender-spa-plugin –save
webpack.prod.config.js 中引入
const PrerenderSPAPlugin = require(‘prerender-spa-plugin’) const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, ‘../dist’),
// outputDir: path.join(__dirname, ‘../prerendered’),
indexPath: path.join(__dirname, ‘../dist’, ‘index.html’),
routes: [‘/mobile/home.html’, ‘/mobile/doctor_team.html’, ‘/mobile/about.html’],
renderer: new Renderer({
inject: {
foo: ‘bar’
},
headless: false,
renderAfterDocumentEvent: ‘render-active’
// renderAfterElementExists: ‘.container’,
// renderAfterTime: 5000
})
})
]
staticDir:代码打包目录
indexPath:模板页面
routes:要预渲染的页面路由
inject:默认挂在 window.__PRERENDER_INJECTED 对象上,可以通过 window.__PRERENDER_INJECTED.foo 在预渲染页面取值
headless:渲染时显示浏览器窗口。对调试很有用。
renderAfterDocumentEvent:等到事件触发去渲染,此处我理解为是 Puppeteer 获取页面的时机
renderAfterDocumentEvent 这个则很关键,这个是监听 document.dispatchEvent 事件,决定什么时候开始预渲染。需要在钩子函数中触发事件,如
new Vue({
el: ‘#app’,
router,
render: h => h(App),
mounted () {
// You’ll need this for renderAfterDocumentEvent.
document.dispatchEvent(new Event(‘render-active’))
}
});
renderAfterElementExists:等到 dom 元素出现时去渲染
renderAfterTime:5000ms 后去渲染
webpack 打包编译
结合项目,执行打包编译命令
npm run build:prod
在 dist 目录下生成以下页面,虽然生成了两层目录,但是还是映射到 ’/mobile/home.html’, ‘/mobile/doctor_team.html’, ‘/mobile/about.html’
查看打包以后的页面,body 内容已经渲染好了
启动 http-server 访问 http://127.0.0.1:8080/mobile/about.html,效果跟正常访问一致
原理
prerender-spa-plugin 利用了 Puppeteer 的爬取页面的功能。Puppeteer 是一个 Chrome 官方出品的 headlessChromenode 库。它提供了一系列的 API, 可以在无 UI 的情况下调用 Chrome 的功能, 适用于爬虫、自动化处理等各种场景。它很强大,所以很简单就能将运行时的 HTML 打包到文件中。原理是在 Webpack 构建阶段的最后,在本地启动一个 Puppeteer 的服务,访问配置了预渲染的路由,然后将 Puppeteer 中渲染的页面输出到 HTML 文件中,并建立路由对应的目录。
图片描述 (最多 50 字) 具体代码可以结合 render-puppeteer 下的代码来看
图片描述 (最多 50 字) 在 render.js 中,启动本地服务,通过 page.goto 依次访问
http://localhost:8000/mobile/about.html,
http://localhost:8000/mobile/home.html
http://localhost:8000/mobile/doctor_team.html
通过 page.content()获取 html
总结
结合项目实践了下这个插件,也有不少坑
1. 在 config/index.js 中 assetsPublicPath 原先写的是 /dist, 导致预渲染的页面 body 没有渲染出来,是空白页面,改成 / 就能预渲染出来,但是这样导致不需要预渲染的页面资源路径不对
2. 该插件在 webpack 此版本下不支持路由懒加载,
“webpack”: “^4.6.0”,
网上提到 npm i webpack@4.28.4 可以解决,果然升级了 webpack 版本后支持路由懒加载
3. 在需要请求动态数据的页面中,预渲染只能保证静态部分不更改,如果不想写死,要做动态数据代理,webpack 的 devserver 代理数据无效,需要用 nginx 或者其他代理工具代理线上数据