(编辑:jimmy 日期: 2025/10/24 浏览:2)
本文讲解的是最近在做的一个多页面项目,结合webpack4的splitChunks进行代码包分拆的过程
项目框架
项目有home和topic两个入口文件,主要包括:
两个入口文件都用react-loadable做了异步加载
import Loadable from 'react-loadable';
...
const LoadableLogin = Loadable({
loader: () => import('../../common/components/login'),
loading: Loading,
});
...
webpack部分配置相关如下:
module.exports = {
...
mode: 'production',
entry: { // 多入口
home: './src/home',
topic: './src/topic',
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production' "~"那么,最终生成的就是 vendor~a~b.js
maxInitialRequests 入口点处的最大并行请求数,默认为3
如果我们设置为1,那么每个入口文件就只会打包成为一个文件
maxAsyncRequests 最大异步请求数量,默认5
如果我们设置为1,那么每个入口文件就只会打包成为一个文件
优先级关系
maxInitialRequest / maxAsyncRequests <maxSize <minSize。
cacheGroups 定制分割包的规则
test可以配置正则和写入function作为打包规则。其他属性均可继承splitChunks,这里必须说一下 priority,设置包的打包优先级,非常重要! (后面结合实践)
minChunks
最少引入的次数
实践
我们以一个最简单的配置开始,将公共代码打包出来
splitChunks: {
chunks: 'all', // initial、async和all
minSize: 30000, // 形成一个新代码块最小的体积
maxAsyncRequests: 5, // 按需加载时候最大的并行请求数
maxInitialRequests: 3, // 最大初始化请求数
automaticNameDelimiter: '~', // 打包分割符
name: true,
cacheGroups: {
vendors: { // 打包两个页面的公共代码
minChunks: 2, // 引入两次及以上被打包
name: 'vendors', // 分离包的名字
chunks: 'all'
},
}
},
两个入口文件的公共代码被打包到vendor文件夹下面,包括echarts d3 amcharts等一些三方包和src下的公共代码。
这当然不是我们想要的结果!存在以下问题:
我们修改cacheGroups为:
cacheGroups: {
vendors: { // 项目基本框架等
chunks: 'all',
test: /(react|react-dom|react-dom-router|babel-polyfill|mobx)/,
priority: 100,
name: 'vendors',
},
'async-commons': { // 异步加载公共包、组件等
chunks: 'async',
minChunks: 2,
name: 'async-commons',
priority: 90,
},
commons: { // 其他同步加载公共包
chunks: 'all',
minChunks: 2,
name: 'commons',
priority: 80,
},
}
这次webpack帮我们打出来的包主要有:
这里说两个需要注意的地方:
ok!按照我们的要求,这样首次页面加载只会引入vendors,commons包,而不会引入async-common包,还是挺棒的!追求更精致的我们,再认真想想,是不是还可以做一些更好的优化?
到目前为止我们打包文件的打包是这样的:
用gzip压缩后,最大的async-common包有391kb。公司说最近因为一些状况,布置到生产后速度慢的时候,有时候只能有20kb/s的下载速度==。。。。于是继续split!
分析一下:
修改
cacheGroups: {
vendors: { // 基本框架
chunks: 'all',
test: /(react|react-dom|react-dom-router|babel-polyfill|mobx)/,
priority: 100,
name: 'vendors',
},
d3Venodr: { // 将体积较大的d3单独提取包,指定页面需要的时候再异步加载
test: /d3/,
priority: 100, // 设置高于async-commons,避免打包到async-common中
name: 'd3Venodr',
chunks: 'async'
},
echartsVenodr: { // 异步加载echarts包
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,
},
}
当然,每次修改后,需要在htmlWebpackPlugin中配置chunk需要的包
plugins: [
new HtmlWebpackPlugin({ // home页面
filename: 'home.html',
template: './template.html',
chunks: ['vendors', 'commons', 'home'],
}),
new HtmlWebpackPlugin({ // topic页面
filename: 'topic.html',
template: './template.html',
chunks: ['vendors', 'commons', 'topic'],
}),
],
后期还做了其他的拆分和优化,大概最大的包保持在100k左右,当然也不建议拆的特别小,因为浏览器http1可能一次性支持6次下载文件,太多可能会适得其反。大家可以根据自己的项目做不同的拆分方法,总而言之,就是为了让项目更完美的在线上运行,给用户更好的体验~
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。