Web 之 Webpack 异步加载(懒加载)分包和使用SplitChunksPlugin 进行简单拆解分包
目录
Web 之 Webpack 异步加载(懒加载)分包和使用SplitChunksPlugin 进行简单拆解分包
二、基础工程(未使用 SplitChunksPlugin 时)
一、简单介绍
Web 开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。
本节介绍,Web 前端开发中使用 webpack ,测试 webpack 懒加载分包和使用SplitChunksPlugin 进行简单分包整理,如果有不足之处,欢迎指出,或者你有更好的方法,欢迎留言。
操作环境:
- win 10
- node 16.14.0 版本
- npm 8.3.1 版本
- webpack: 5.73.0
- webpack-cli: 4.10.0
官网 SplitChunksPlugin 介绍:SplitChunksPlugin | webpack 中文文档
github 对 SplitChunksPlugin 介绍:GitHub - gexiaolin/SplitChunksPlugin: 文档翻译
最初,chunks(以及内部导入的模块)是通过内部 webpack 图谱中的父子关系关联的。
CommonsChunkPlugin
曾被用来避免他们之间的重复依赖,但是不可能再做进一步的优化。从 webpack v4 开始,移除了
CommonsChunkPlugin
,取而代之的是optimization.splitChunks
。module.exports = { //... optimization: { splitChunks: { chunks: 'async', // 仅提取按需载入的module minSize: 30000, // 提取出的新chunk在两次压缩(打包压缩和服务器压缩)之前要大于30kb maxSize: 0, // 提取出的新chunk在两次压缩之前要小于多少kb,默认为0,即不做限制 minChunks: 1, // 被提取的chunk最少需要被多少chunks共同引入 maxAsyncRequests: 5, // 最大按需载入chunks提取数 maxInitialRequests: 3, // 最大初始同步chunks提取数 automaticNameDelimiter: '~', // 默认的命名规则(使用~进行连接) name: true, cacheGroups: { // 缓存组配置,默认有vendors和default vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } } } } };
一些名词解释:
1、chunks:
- all: 不管文件是动态还是非动态载入,统一将文件分离。当页面首次载入会引入所有的包
- async: 将异步加载的文件分离,首次一般不引入,到需要异步引入的组件才会引入。
- initial:将异步和非异步的文件分离,如果一个文件被异步引入也被非异步引入,那它会被打包两次(注意和all区别),用于分离页面首次需要加载的包。
2、minSize: 文件最小打包体积,单位byte,默认30000
比如说某个项目下有三个入口文件,a.js和b.js和c.js都是100byte,当我们将minSize设置为301,那么webpack就会将他们打包成一个包,不会将他们拆分成为多个包。
比如说某个项目下有三个入口文件,a.js和b.js和c.js都是100byte,当我们将minSize设置为301,那么webpack就会将他们打包成一个包,不会将他们拆分成为多个包。
3、automaticNameDelimiter: 连接符
假设我们生成了一个公用文件名字叫vendor,a.js,和b.js都依赖他,并且我们设置的连接符是"~"那么,最终生成的就是 vendor~a~b.js
4、maxInitialRequests 入口点处的最大并行请求数,默认为3
如果我们设置为1,那么每个入口文件就只会打包成为一个文件
5、maxAsyncRequests 最大异步请求数量,默认5
如果我们设置为1,那么每个入口文件就只会打包成为一个文件
6、优先级关系
maxInitialRequest / maxAsyncRequests <maxSize <minSize。
7、cacheGroups 定制分割包的规则
test可以配置正则和写入function作为打包规则。其他属性均可继承splitChunks,这里必须说一下 priority,设置包的打包优先级,非常重要!
8、minChunks
最少引入的次数
二、基础工程(未使用 SplitChunksPlugin 时)
1、首先 npm init -y 进行基本的环境搭建,然后创建 src 文件夹,并添加一个 webpack.config.js 脚本
2、npm install lodash ,作为后面测试使用
3、在src 中添加文件夹 index.js\pageA.js\pageB.js文件,并添加简单代码
// index.js
import './pageA'
import './pageB'
console.log('this is index')
// pageA.js
console.log('this is pageA')
export default 'pageA'
// pageB.js
console.log('this is pageB')
export default 'pageB'
4、在 webpack.config.js 中添加代码,进行基本的代码打包
const path = require('path')
module.exports={
entry:{
index:"./src/index.js"
},
output:{
path:path.resolve(__dirname,'dist'),
filename:'[name].[hash:8].js'
},
mode:'development'
}
5、在控制台,使用 webpack 进行打包,生成 index.xxxxxx.js 5.08kb
6、添加 index.js 添加引入 lodash ,然后打包 ,生成 index.xxxxxx.js 555 kb
7、在控制台,安装npm install webpack-bundle-analyzer --save-dev,用来打包分析,webpack.config.js 添加 webpack-bundle-analyzer 插件
module.exports={
entry:{
index:"./src/index.js"
},
output:{
path:path.resolve(__dirname,'dist'),
filename:'[name].[hash:8].js'
},
mode:'development',
plugins:[
new require('webpack-bundle-analyzer').BundleAnalyzerPlugin()
]
}
8、运行webpack,浏览器打开 http://127.0.0.1:8888
三、懒加载分包的方式重新打包
1、index.js 使用懒加载的方式加载 pageA.js 和 pageB.js
2、webpak 就会把之前的 pageA.js 和 pageB.js 拆分出来
3、新建一个index.html ,引入懒加载打包生成的 index.xxxx.js 脚本,浏览器打印和加载资源如下,正常显示,以及按需加载 pageA
4、webpack-bundle-analyzer 包分析图如下
四、SplitChunksPlugin 插件分包
1、安装一个 npm install jquery 插件,在 pageA.js 和 pageB.js 中引入 jquery
2、在 webpack.config.js 中添加对应的 optimization / splitChunks 信息
const path = require('path')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports={
entry:{
index:"./src/index.js"
},
output:{
path:path.resolve(__dirname,'dist'),
filename:'[name].[hash:8].js'
},
mode:'development',
plugins:[
new BundleAnalyzerPlugin()
],
optimization: {
splitChunks: {
chunks: 'async', // 代码分割时对异步代码生效,all:所有代码有效,inital:同步代码有效
minSize: 30000, // 代码分割最小的模块大小,引入的模块大于 30000B 才做代码分割
minChunks: 1, // 引入的次数大于等于1时才进行代码分割
maxAsyncRequests: 6, // 最大的异步请求数量,也就是同时加载的模块最大模块数量
maxInitialRequests: 4, // 入口文件做代码分割最多分成 4 个 js 文件
cacheGroups: { // 缓存组配置,默认有vendors和default
vendors: {
test: /[\\/]node_modules[\\/]/, // 匹配需拆分chunk的目录
priority: -10, // 拆分优先级
name:'venders'
},
default: {
minChunks: 2, // 覆盖外层minChunks,用于提取被引用指定次数的公共模块,这里默认2次
priority: -20,
name:'common',
reuseExistingChunk: true // 是否重用已存在的chunk
}
},
}
}
}
3、根据这些规则,控制台 webpack 进行打包的时候,就会根据规则,进行分包
4、在 index.html 中引入Split 后的 index.xxxxxxx.js
5、把 lodash 从 index 中分离,在 webpack.config.js 中修改
const path = require('path')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports={
entry:{
index:"./src/index.js",
},
output:{
path:path.resolve(__dirname,'dist'),
filename:'[name].[hash:8].js'
},
mode:'development',
plugins:[
new BundleAnalyzerPlugin()
],
optimization: {
splitChunks: {
chunks: 'async', // 代码分割时对异步代码生效,all:所有代码有效,inital:同步代码有效
minSize: 30000, // 代码分割最小的模块大小,引入的模块大于 30000B 才做代码分割
minChunks: 1, // 引入的次数大于等于1时才进行代码分割
maxAsyncRequests: 6, // 最大的异步请求数量,也就是同时加载的模块最大模块数量
maxInitialRequests: 4, // 入口文件做代码分割最多分成 4 个 js 文件
cacheGroups: { // 缓存组配置,默认有vendors和default
vendors: {
test: /[\\/]node_modules[\\/]/, // 匹配需拆分chunk的目录
priority: -10, // 拆分优先级
name:'venders'
},
lodashVenodr: { // 将体积较大的lodash单独提取包,指定页面需要的时候再异步加载
test: /lodash/,
priority: -10,
name: 'lodashVenodr',
chunks: 'all'
},
default: {
minChunks: 2, // 覆盖外层minChunks,用于提取被引用指定次数的公共模块,这里默认2次
priority: -20,
name:'common',
reuseExistingChunk: true // 是否重用已存在的chunk
}
},
}
}
}
6、根据提示,在index.html 引入生成的 index.xxxxx.js,以及 lodashVendor.xxxxx.js
这里简单分包操作如此,当然不是包越小越多越好,而是,根据实际项目运行结果需要拆解分包