详解如何在webpack中做预渲染降低首屏空白时间

一、浏览器渲染过程

1、用户打开页面,空白屏,等待html的返回

2、html下载完毕,开始解析html,初始渲染

3、下载css、js等资源,执行js渲染虚拟DOM

4、发起请求、获取数据,渲染内容

下面我们主要是讨论一下如何通过预渲染的方式降低空白屏的时间

缩小首屏载时间是一个重要的优化项,总结来主要有以下几种方式:

1、尽可能的缩小webpack或者其他打包工具生成的包的大小
2、使用服务端渲染的方式
3、使用预渲染的方式
4、使用gzip减小网络传输的流量大小
5、按照页面或者组件分块懒加载

二、传统页面开发

在React、Vue这种数据驱动的框架还没盛行的时候,一般我们都是直接在html上写dom结构的,要不就是直接服务端直出,所以我们在下载完html页面后,空白屏的时间是非常短的,因为dom是在html中的,并不是像现在以虚拟dom的方式写在js中,所以,我们不需要等待js下载完毕后才开始渲染页面,而是html下载完毕后直接渲染出dom结构。

如今我们运用Vue等框架进行开发的时候,一般在html结构都是下面这样的

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>title</title> </head> <body> <div></div> <script src="https://www.jb51.net/bound.js"></script> </body> </html>

在js资源没有下载完毕的情况下,页面一直都是处于空白的页面,一直要等到虚拟dom插入到id为app的div中,这时候白屏才消失开始展现页面,反正就是让人感觉特别慢就是了!

既然知道了白屏是怎么产生的,那我们下面就来尝试一下如何在webpack中集成预渲染的功能,来降低白屏的时间。

三、在webpack中集成预渲染功能

github:webpack中如何集成预渲染功能

这里我们尝试将一个使用vue编写的loading组件在webpack编译过程中将虚拟dom预渲染到html中,下面是loading组件的内容

<template> <div></div> </template> <script> export default {} </script> <style> .loading-img { position: fixed; top: 0; bottom: 0; right: 0; left: 0; margin: auto; display: inline-block; width: 60px; height: 60px; background: url(__inline__) no-repeat center center; background-size: contain; } </style>

上面__inline__是用于后面图片插入的标记,这里先不用管,其实这个组件就是一个简单的loading组件

最终我们想要的效果是,将这个vue组件的虚拟dom预渲染到html文件当中

<html> <head> <meta charset="UTF-8"> <title>test</title> <!-- pre-render-loading抽出的css --> <style> .loading-img { position: fixed; top: 0; bottom: 0; right: 0; left: 0; margin: auto; display: inline-block; width: 60px; height: 60px; <!-- 这里我们会将loading图编译成base64直接插入到html中 --> background: url(data:image/gif;base64,.....) no-repeat center center; background-size: contain; } </style> ... </head> <body> <div> <!-- loading base64图 --> <div></div> </div> ... </body> </html>

向上面那样,在html页面返回时编译成base64内嵌到html中的loading就会马上显示,大大降低了白屏的时间,基本可以达到秒开页面,这时候我们不需要等待js资源的下载以及虚拟dom的插入,当然这里loading中的内容可以是任何你想要预先渲染的模板

详解如何在webpack中做预渲染降低首屏空白时间

详解如何在webpack中做预渲染降低首屏空白时间

因为这里我们的loading组件是用vue写的,所以我们试着看看如何来做预渲染并集成到webpack中(可以合着仓库的代码一起看,代码挺简单的,只是一个demo)

这里我们先把vue单文件中的html与css单独抽离出来

// render-loading.js let vueAssets = null let vueTplPath = resolvePath('./src/loading/pre-render-loading.vue') const extractAssetsInVueTpl = (vueTplPath) => { let vueTpl = clearEnter(fs.readFileSync(vueTplPath).toString()) let html = /<template>(.*)<\/template>/g.exec(vueTpl)[1] let css = /<style>(.*)<\/style>/g.exec(vueTpl)[1] return { html, css } } vueAssets = extractAssetsInVueTpl(vueTplPath)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/2053a624e1ded053807791f6ee3fdc5a.html