Vue打包首屏优化

1. 前言

在最近的项目中遇到一个问题,我们用vue-cli搭建的工程部署后,需要将页面集成到别的厂商中去,集成完后发现网络好的情况都需要加载4~5秒,有时候达到了10秒的等待时间,这个期间会一直白屏,体验非常不友好,所以针对这个问题做一下优化。先来感受下未优化的情况,打包后的文件,vendor.js文件有1.9M,在网络不好的情况下,加载很耗时的,在移动端,受限于性能和网络,影响会放大。

1.png
在比较好的4G热点下,耗时4.32秒,平均是在4秒左右:

2.png

1.1 原因

造成这个的原因主要是打包后的vendor.js太大,但是Vue等主流的单页框架都是js渲染的html,所以必须要等到verdor.js加载完成后完整的界面才会显示。

1.2 解决方法

针对白屏的不友好体验,主要有以下的解决方案:

(1)给个loading的菊花转挡一下

(2)对页面的组件做异步加载

(3)webpack打包优化,减小打包文件的体积

(4)vue-router路由懒加载

(5)利用webpack插件进行页面预渲染

(6)使用服务端渲染首屏骨架页面,或者直接使用服务端渲染策略

以上解决方法实现难度逐级增加,项目是使用typescript开发的,所以要集成第(6)的话,成本有点大,排除,第(5)适用于静态网站,排除。根据项目的实际情况,选择了第(2)、(3)、(4)进行优化。

2. 页面组件异步加载

异步组件和路由懒加载都将组件分离,需要用到的时候再去加载。没有使用异步路由之前:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import AppChat from './components/AppChat.vue'
import WebChat from './components/WebChat.vue'
export default new Router({
routes: [
{
path: '/',
name: 'web',
component: WebChat
},
{
path: '/app',
name: 'app',
component: AppChat
},
{
path: '*',
name: '404',
redirect: '/'
}
]
})

将组件或路由改成异步组件:

1
2
const WebChat = () => import('./components/WebChat.vue')
const AppChat = (resolve:any) => require(['./components/AppChat.vue'], resolve)

打包后多出几个chunk,但似乎vendor的体积不变:

3.png
虽然多了文件和请求,但是传输的内容变少了,加载时间有所下降(2.93秒):

4.png
看来使用异步组件和路由懒加载能减少首屏加载时间,实际项目中应该多使用。

3. Webpack打包体积优化

3.1 使用BundleAnalyzerPlugin插件可视化包的依赖关系

使用树状图可视化展示webpack打包后的文件大小。参考文档:https://www.npmjs.com/package/webpack-bundle-analyzer。安装:

1
2
3
4
# NPM 
npm install --save-dev webpack-bundle-analyzer
# Yarn
yarn add -D webpack-bundle-analyzer

将插件添加到webpack中,因为使用的是vue-cli,所以应在vue.config.js中添加配置:

1
2
3
4
5
6
7
8
9
10
// vue.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
]
}
}

执行打包命令(npm run build)后,会自动打开浏览器:

5.png
显示了模块的依赖关系,其中体积最大的显示在最前面。看到这个依赖图,心里一惊,项目使用了ant-design-vue,但是只是使用了里面的message模块,不至于体积这么大,应该是导入的方法有问题:

1
2
3
4
import 'ant-design-vue/lib/message/style/index.css'
import message from 'ant-design-vue'
import Vue from 'vue'
Vue.use(message)

改成在prototype上添加属性:

1
2
3
import { message } from 'ant-design-vue'
import Vue from 'vue'
Vue.prototype.$message = message

再看看依赖图:

6.png
ant-design-vue的依赖已经减少了,同时打包的体积也减少了一倍多!

7.png
加载时间同样减少了很多,2秒不到!

8.png
到此,代码方面的优化差不多了,接下来优化下网络传输方面。

4. nginx开启gzip

配置nginx开启gzip压缩,压缩后文件变小,传输会更快,参考配置文档:http://nginx.org/en/docs/http/ngx_http_gzip_module.html

1
2
3
4
5
6
7
8
9
# nginx.config ,location 或者 http 节点下配置
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 8;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary off;
gzip_disable "MSIE [1-6]\.";
gzip_static on;#如果服务端有已经使用了gzip压缩的文件(文件名.gz),则直接使用压缩后的文件

我们只要关心gzip ongzip_types,就是将gzip压缩开启,并且将javascript文件添加到压缩的类型中。开启gzip有个问题,就是每次访问都会去压缩,导致cpu的占用会上升。

9.png
nginx开启压缩后立竿见影,秒级加载😊,同时可以看到响应头里面多了一个Content-Encoding:gzip。至此,优化应该算是结束了,等等,有人说过后端能做的东西前端也能做🤔,前端开启gzip !

5. 使用CompressionPlugin压缩bundle

CompressionPlugin 插件的作用是将webpack打包后的文件进行gzip压缩。参考文档:https://www.webpackjs.com/plugins/compression-webpack-plugin/。安装:

1
2
3
4
# NPM 
npm install --save-dev compression-webpack-plugin
# Yarn
yarn add -D compression-webpack-plugin

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// vue.config.js
const CompressionPlugin = require('compression-webpack-plugin')

module.exports = {
configureWebpack: {
plugins: [
new CompressionPlugin({
test: /./, //压缩所有文件
filename: '[path]', //输出文件路径,这里是直接替换原文件
minRatio: 2 // 最低压缩率,压缩率低于这个才压缩,之所以设置大于1的数值是要压缩所有的文件
})
]
}
}

使用gzip压缩后文件变小:

10.png
vendor已经只有两百kb了,浏览器加载一波试试:

image-20190625142625241.png
这是什么玩意儿?🤔怎么会有乱码呢?而且文件也没有加载全啊?Content-Encoding怎么会是空的呢?我明明是用gzip压缩了的啊?赶紧打开打包后的index.html看看:

image-20190625142745044.png
竟然提示我编码不对😓,哦,原来这是gzip压缩后的文件,需要先解压缩后才能看呀!那我要怎么让浏览器解压呢?手动添加Content-Encoding=gzip响应头!

1
2
# nginx.config ,location 或者 http 节点下配置
add_header Content-Encoding gzip;

刷新浏览器看看!

image-20190625143210990.png
不管是图片还是脚本文件都使用了gzip压缩,好像加载时间又变少了呢!而且使用这种方法,不需要nginx开启gzip,性能得到加速!

6. 时间轴回放

从时间轴的顺序看一下优化的结果:

优化方法 请求数 请求大小 加载时间
未优化 8 1.9 Mb 4.32 s
异步组件 10 1.88 Mb 2.93 s
Vue.use优化 10 901.21 kb 1.56 s
nginx-gzip 10 305.26 kb 674 ms
前端-gzip 10 300.07 kb 521ms

PC端的性能强于移动端,移动端的结果会放大,按照最后的结果,移动端勉强能做到秒开😅,要是遇到极端网络就… 都5G时代了,你差这点流量吗?


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!