在当今的互联网环境下,用户体验俨然成为了革命的刚需。用户怎么判断哪家的产品好用呢?作为网页应用,加载速度一直都是给用户的第一印象。
当然,网页的优化方式有很多。比如 服务器环境(选择高速、高转发率框架 如 Ngnix。选择更先进的协议 如 Http2)、gzip压缩(需要服务器环境支持)、CDN加速静态资源访问
等等等等,都是很好的途径。以上方式,或多或少的需要依赖后端或者运维的支持。甚至会受到所在公司技术栈的制约。
文中提到的将是一种前端工程师可以自由把控的方式。它能让单(多)页应用实现公共部分单独打包,并通过对项目编译时的拆分,实现网页资源的多并发异步加载。
假设一个人吃一个汉堡包需要5min
那现在我把汉堡分成5份,并让5个人同时吃,理论上就能达到1min一个汉堡的速度啦~~
此处的汉堡就是我们的前端项目编译后的静态文件,5个人可以理解为浏览器同时分配的5个异步请求。
那么问题来了。编译的时候,我们怎么切好这个 ”汉堡” 呢?让我来有请本篇的主角:webpack splitchunksPlugin插件。
项目内安装
# NPM
npm install --save-dev webpack-bundle-analyzer
# Yarn
yarn add -D webpack-bundle-analyzer
在webpack配置文件中添加如下代码
...
let BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = merge(baseWebpackConfig, {
...,
plugins: [
...,
new BundleAnalyzerPlugin()
],
}
然后开始构建项目,接下来以我的项目为例。项目配置:webpack4.x + babel7.x + react16.x + mobx + ECharts + antd(已做按需加载)
控制台阻塞后,浏览器会自动打开 http://127.0.0.1:8888/。如果没跳出来,可以手动打开此链接
这就是具现化以后的分布图了。我们可以发现,这货比汉堡可复杂的多了吶
从工具上可以了解到有两个文件接近1MB,分别是
a:
b:
此时,这个工具的强大就体现出来了。两个大文件的组成部分都一目了然。
网页加载时,浏览器控制台输出是这样的,如下图
(这是初次加载的情况,以下的测试均不适用缓存。)
这里举例对a图片进行讲解。分析分析之后发现,echarts+zrender(echarts的依赖)和 moment库(本项目已经裁剪过,所以比较小)、antd组件 等等打包到了一起。导致了此文件体积异常。
知道了原因,接下来就要进行关键的一步了 — 分割代码
splitChunks: {
minSize: 30000,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: { // 项目基本框架等
name: 'vendors',
test: /[\\/]react|react-dom|react-router-dom|axios|mobx[\\/]/,
chunks: 'all',
priority: 100
},
commons: { // 其他同步加载公共包
chunks: 'all',
minChunks: 2,
name: 'commons',
priority: 80,
},
}
}
这里有很多参数,请参照文档 splitchunksPlugin Api文档 对号入座
文档阅读以后,让我来修改代码,成品如下:
splitChunks: {
minSize: 30000,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: { // 项目基本框架等
name: 'vendors',
test: /[\\/]react|react-dom|react-router-dom|axios|mobx[\\/]/,
chunks: 'all',
priority: 100
},
antdVenodr: { // 异步加载antd包
test: /(antd)/,
priority: 100,
name: 'antdVenodr',
chunks: 'async'
},
echartsVenodr: { // 异步加载echarts & zrender包
test: /(echarts|zrender)/,
priority: 100, // 高于async-commons优先级
name: 'echartsVenodr',
chunks: 'async'
},
'async-commons': { // 异步加载公共包、组件等
chunks: 'async',
minChunks: 2,
name: 'async-commons',
priority: 90,
},
commons: { // 其他同步加载公共包
chunks: 'all',
minChunks: 2,
name: 'commons',
priority: 80,
},
}
}
我把 antd、echarts单独拆了出来,并且还把公共包和组件分割出来。
然后别忘了在HtmlWebpackPlugin配置时chunk一下
就像这样:
chunks: ['commons', 'manifest', 'antdVenodr', 'echartsVenodr', 'async-commons', 'vendors', 'app']
如果是多页面的话就更加体现出这样做的价值了,我们可以按需chunk依赖,比如我有个login入口
chunks: ['commons', 'manifest', 'async-commons', 'vendors', 'login']
这样就进一步提升了登录页面的加载速度。
最后,看看效果吧~
再看看浏览器的加载情况
数据上看,这样已经快了一倍有余。而我的操作恰巧是多指派了”3个吃汉堡的人“。
那为什么不再多分几个文件呢?
因为实际操作的时候,考虑到 包与包之间的关联 和 合理拆分的逻辑,并不适合将文件拆的特别零散。
所以,剩下的优化就需要交给其他优化手段了(配合gzip食用,风味更佳)。
本篇介绍就到这里。PS:新的风暴(webpack5.x)已经出现,又是一轮新的学习和优化。只要项目还在,优化就不能停止。