blog
blog copied to clipboard
预渲染(Prerendering)
什么是服务器端渲染 (SSR)?
服务端在返回 html 之前,先把数据填充好,再给客户端,客户端只负责解析 HTML 。
为什么使用服务器端渲染 (SSR)?
与传统 SPA (单页应用程序) 相比,服务器端渲染 (SSR) 的优势主要在于:
- 更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
请注意,截至目前,Google 和 Bing 可以很好对同步 JavaScript 应用程序进行索引。在这里,同步是关键。如果你的应用程序初始展示 loading 菊花图,然后通过 Ajax 获取内容,抓取工具并不会等待异步完成后再行抓取页面内容。也就是说,如果 SEO 对你的站点至关重要,而你的页面又是异步获取内容,则你可能需要服务器端渲染(SSR)解决此问题。
- 更快的内容到达时间 (time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备。无需等待所有的 JavaScript 都完成下载并执行,才显示服务器渲染的标记,所以你的用户将会更快速地看到完整渲染的页面。通常可以产生更好的用户体验,并且对于那些「内容到达时间(time-to-content) 与转化率直接相关」的应用程序而言,服务器端渲染 (SSR) 至关重要。
使用服务器端渲染 (SSR) 时还需要有一些权衡之处:
-
开发条件所限。浏览器特定的代码,只能在某些生命周期钩子函数 (lifecycle hook) 中使用;一些外部扩展库 (external library) 可能需要特殊处理,才能在服务器渲染应用程序中运行。
-
涉及构建设置和部署的更多要求。与可以部署在任何静态文件服务器上的完全静态单页面应用程序 (SPA) 不同,服务器渲染应用程序,需要处于 Node.js server 运行环境。
-
更多的服务器端负载。在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用 CPU 资源 (CPU-intensive - CPU 密集),因此如果你预料在高流量环境 (high traffic) 下使用,请准备相应的服务器负载,并明智地采用缓存策略。
服务器端渲染 vs 预渲染 (SSR vs Prerendering)
预渲染是编译时提前渲染一次, 服务器端渲染ssr是用户每次请求服务器,服务器把相应的内容填进去。
预渲染
使用prerender-spa-plugin
插件进行预渲染,使用预渲染方式,在构建时 (build time) 简单地生成针对特定路由的静态 HTML。
通过webpack的plugin引入,如下:
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: [ '/', '/about', '/contact' ],
renderer: new Renderer({
inject: {
foo: 'bar'
},
renderAfterDocumentEvent: 'render-event'
})
})
]
原理
prerender-spa-plugin这个插件是在webpack构建过程中,依赖puppeteer操作chromium这个真正的浏览器内核对SPA跑了一遍,生成一个静态的HTML,里面是已经填好的dom节点和数据,相当于提前在浏览器中跑了一遍,给用户直接返回有内容的html文档。
简单的说,在webpack构建过程中,SPA已经访问配置了预渲染的路由,并填充数据输出到对应的路由html中。
利用官方的实例进行编译结果如下
预渲染 Vs 不做预渲染
基本代码
打包过程
打包过程会打开无头浏览器,访问插件配置好的路由/, /about, /contact
demo访问
about页面的访问对比
不做预渲染,直接访问about页面
这样会先访问首页的index.html,然后在调用html5 的history的api跳转路由到about
使用prerender-spa-plugin
插件做预渲染,直接访问about页面
应用在什么地方
需要对数据几乎没有变化的页面进行SEO优化,例如 /, /about, /contact等。在webpack构建过程中,可以注入一个变量,这个变量可以判断是否在真实的浏览器环境中
,通过这个变量,可以阻止在真实浏览器中去重新发送请求,因为数据已经在预渲染过程中已经获取到了。
showMessage () {
if(window.__PRERENDER_INJECTED && window.__PRERENDER_INJECTED.foo =='bar') return;
this.message = '我是测试预加载拦截';
}
预渲染的demo
有什么作用
- 优化静态页面的SEO。
- 优化非静态页面meta、title的SEO,其他异步获取的数据无法优化SEO
- 预渲染过程中,根据页面结构生成对应的骨架屏
需要注意的地方
- 只支持 HTML5 history API,不支持hash模式
- 无论您使用哪种客户端渲染库,都应该能够至少替换任何服务器渲染的内容或使用它进行差异化。
- 对于Vue.js 1,replace: false在根组件上使用。
- 对于Vue.js 2 确保根组件具有与其替换的预渲染元素相同的ID。否则你最终会得到重复的内容。
不适合的场景
- 路由过多,假如预渲染成千上万的路由文件,构建时间将会很长
- 不能很好地处理用户独特性路由: 比如有个路由是 /my-profile, 预渲染可能不会很好用, 因为这个内容页是根据用户信息变化的,所以页面内容也不是唯一确定的。