vue.js 实践总结(三)Skeleton 骨架屏渲染

应用场景

简单来讲,骨架屏(skeleton screen) 就是一个页面从html 下载完成到 js 下载完成而且执行数据渲染这两个时间点之间暂时渲染页面基本结构的方案。php

就个人理解,骨架屏优化是有必定场景的,包括且不限于如下几种状况:html

  • 有懒加载机制的SPA路由
  • 多页面程序的首页渲染
  • SPA 中的非懒加载路由,可是数据量很大,彻底load 并渲染数据须要花较长时间

https://huangxuan.me/2017/07/12/upgrading-eleme-to-pwa

上图形象地解释了两个多页面程序之间的切换,用Skeleton Screen 去优化用户观感的方案。前端

Skeleton 渲染是在前端项目编译时完成的,与之相对应的是组件在浏览器runtime实时渲染成DOM,从技术上讲就是在服务器端预先把组件布局和数据渲染成html 字符串而且注入html 文件中。这须要服务器端渲染(ssr) 的支持。如react 和 vue.js 这样依赖虚拟DOM 的前端框架自然是支持服务器端渲染的。由于只须要一个 JavaScript 在服务器端的执行环境(例如V8 引擎)就能够轻易建立虚拟Dom而且映射为DOM tree。基于虚拟dom的服务器端渲染,最先起源于react,能够参考 strikingly 的技术博客vue

服务器端渲染

服务器端渲染做为skeleton screen的基本技术栈,能够参考各前端框架的官方文档,例如 vue-ssr guide. 主要是依赖 vue-server-renderer 这个库来实现node

拿vue.js 组件来讲,在node.js 中渲染为 HTML 字符串能够简单分为几步:python

// 第 1 步:建立一个 Vue 实例
const Vue = require('vue')
const app = new Vue({
// el: 是不须要的,由于一旦设置目标 el,就会涉及document 操做
  template: `<div>Hello World</div>`
})

// 第 2 步:建立一个 renderer
const renderer = require('vue-server-renderer').createRenderer()

// 第 3 步:将 Vue 实例渲染为 HTML
renderer.renderToString(app, (err, html) => {
  if (err) throw err
  console.log(html)
  // => <div data-server-rendered="true">Hello World</div>
})
复制代码

上面的官方DEMO 很简单,直接在nodejs 脚本文件中定义vue 组件。但实际应用中咱们的组件通常都比较复杂,多是一个入口 app.vue,依赖了好几个组件,因此要用另外的方式去引入 new Vue 产生的 vm 对象. 这个vm 对象做为 renderer.renderToString 函数的第一个参数是最核心的。实际上经过跟踪 vue-server-renderer 的源码,ssr 仍是依靠vue组件的render 函数来完成大部分工做 ,render 函数是 vue 组件的核心函数。react

| installSSRHelpers(component); 
renderToString -> createRenderFunction -> | normalizeRender(component);  // get component render function
                                          | renderNode(component._render(), true, context); 
                                          // call component render to VNode.

复制代码

几个坑

  • document not defined

服务器端渲染并不等同于在服务器端启动一个浏览器进程,因此没法获取浏览器窗体中的window,document 等全局对象。一旦服务器端渲染的js 脚本中涉及到document 操做,就会报这个 document not defined 的错误。git

因此要么就在vue 组件中或者全部依赖包中用到document 的地方都要作检测,要么就在服务器端渲染以前给global 对象加上document 定义 github issue程序员

  • unexpected token =

在vue-server-renderer 的执行过程当中,提供了把vue 组件渲染成html 片断而且插入某个 template HTML 中的API, 在建立Renderer 的时候传入一个template。后来发现ssr 的 template 中是不能包含相似这种 <%= ddd > 符号的,也就是template 必须得符合vue 的template 语法github

// 最后ssr 就会输出 Vue 组件的内容,而且注入到template 中 注释 <!--vue-ssr-outlet--> 的地方

const renderer = createRenderer({
  template: require('fs').readFileSync('./index.template.html', 'utf-8')
})
const context = { title: 'Hello' }
renderer.renderToString(app, context, (err, html) => {
  // 页面模板中 {{ title }} 将会是 "Hello"
})
复制代码

具体参考 ssr 使用页面模板。 由于有的后端程序员习惯了 asp 或者 jsp 的template 语法,以 <%= 等做为数据插值表达式的开头,会引发 vue ssr 的编译失败。

写在后面

综上,此次我只是简单分析记录了下 Skeleton 骨架屏实现的第一部分,就是server side render,这是预先渲染的技术前提。实际上,这种后端拼接Html 字符串的活在php年代,python server中,甚至node.js server 中咱们早就干过了(ejs 或者 jade)。本质上都是拼接Html 字符串,提升SEO 和首屏响应

在Github 上有许多基于服务器端渲染的静态网站生成器或者 博客工具,能够实现比较流畅的浏览体验, 例如:vuepress.

关于骨架屏的实现,业内已经有很成熟的方案,既有基于 ssr 的,也有直接基于浏览器内核起个进程预渲染的,彻底不用vue 的ssr 技术栈。下一次再具体分享下后者

参考阅读:

vue ssr guide

饿了么升级PWA

vue.js 开发系列二:render 函数

essential-guide-to-improve-seo-in-single-page-application-vuejs

相关文章
相关标签/搜索