blog icon indicating copy to clipboard operation
blog copied to clipboard

预渲染(Prerendering)

Open rudyxu1102 opened this issue 5 years ago • 0 comments

什么是服务器端渲染 (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 不做预渲染

基本代码

app mainjs webpack

打包过程

打包过程会打开无头浏览器,访问插件配置好的路由/, /about, /contact

build

demo访问

_20190417115237

about页面的访问对比

不做预渲染,直接访问about页面

这样会先访问首页的index.html,然后在调用html5 的history的api跳转路由到about prerender-spa

使用prerender-spa-plugin插件做预渲染,直接访问about页面

prerender-dist

应用在什么地方

需要对数据几乎没有变化的页面进行SEO优化,例如 /, /about, /contact等。在webpack构建过程中,可以注入一个变量,这个变量可以判断是否在真实的浏览器环境中,通过这个变量,可以阻止在真实浏览器中去重新发送请求,因为数据已经在预渲染过程中已经获取到了。

showMessage () {
  if(window.__PRERENDER_INJECTED && window.__PRERENDER_INJECTED.foo =='bar') return;
  this.message = '我是测试预加载拦截';
}

预渲染的demo

官方demo集合

有什么作用

  • 优化静态页面的SEO。
  • 优化非静态页面meta、title的SEO,其他异步获取的数据无法优化SEO
  • 预渲染过程中,根据页面结构生成对应的骨架屏

需要注意的地方

  • 只支持 HTML5 history API,不支持hash模式
  • 无论您使用哪种客户端渲染库,都应该能够至少替换任何服务器渲染的内容或使用它进行差异化。
    • 对于Vue.js 1,replace: false在根组件上使用。
    • 对于Vue.js 2 确保根组件具有与其替换的预渲染元素相同的ID。否则你最终会得到重复的内容。

不适合的场景

  • 路由过多,假如预渲染成千上万的路由文件,构建时间将会很长
  • 不能很好地处理用户独特性路由: 比如有个路由是 /my-profile, 预渲染可能不会很好用, 因为这个内容页是根据用户信息变化的,所以页面内容也不是唯一确定的。

参考链接

rudyxu1102 avatar Apr 07 '19 14:04 rudyxu1102