说明
- 这套笔记是对于
webpack 5.x进行阐述的。(webpack <= 4用法稍有不同)
概念
代码分割 (code spilting), 是指将一个体积比较大的入口脚本文件拆分成合适大小体积的若干个脚本文件。
代码分割的方式:
一、全局拆分库
将使用到的库或者框架拆分成 lib 导入
|- externals
|- lodash.js
|- src
|- index.js
|- webpack.config.js
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const config = {
mode: 'production',
entry: {
index: resolve(__dirname, 'src/index.js'),
lodash: resolve(__dirname, 'externals/lodash.js'),
},
output: {
path: resolve(__dirname, 'dist'),
filename: 'js/[name]-[contenthash].js',
publicPath: '/',
clean: true
},
plugins: {
new HtmlWebpackPlugin({
template: resolve(__dirname, 'public/index.html'),
favicon: resolve(__dirname, 'public/favicon.ico'),
title: 'Index',
chunks: ['lodash', 'index'],
minify: {
collapseWhitespace: true,
removeComments: true
}
})
}
};
module.exports = config;
externals/lodash.js
import _ from 'lodash';
window._ = _;
src/index.js
const arr = ['张三', '李四', '王五', '赵六', '田七'];
const arrStr = _.join(arr, '-');
console.log(arrStr);
二、动态导入(依赖的懒加载)
const oBtn = document.getElementsByTagName('button')[0];
const oDiv = document.getElementsByTagName('div')[0];
const arr = ['zhangsan', 'lisi', 'wangwu'];
oBtn.addEventListener('click', handleBtnClick, false);
function getLodash() {
return new Promise((resolve) => {
import('lodash').then(({ default: _ }) => {
resolve(_);
})
});
}
async function handleBtnClick() {
const _ = await getLodash();
const arrStr = _.join(arr, ' & ');
oDiv.textContent = arrStr;
}
三、optimization.splitChunks
splitChunks 是 webpack 提出的可以整体配置懒加载的选项,webpack 会根据 splitChunks 里面的选项要求进行打包。
举个例子:
module.exports = {
//...
optimization: { // 打包优化项 (usedExports, splitChunks, minimizer, ...)
splitChunks: {
chunks: 'async', // 需要分割的 chunk 类型 (全部, 异步, 同步)
minSize: 20000, // 代码快的大小至少为 xxx kb, 才需要进行代码分割
minRemainingSize: 0, // 最小的 chunk 剩余大小
minChunks: 1, // chunk 至少要被引入多少次才会进行代码分割
maxAsyncRequests: 30, // 最大的异步 chunk 请求数
maxInitialRequests: 30, // 最大的同步 chunk 请求数
enforceSizeThreshold: 50000, // 线程强制运行的大小
cacheGroups: { // 缓存组 (里面使用一组组对象对打包的 chunks 进行规则列举)
defaultVendors: { // 对 node_modules 中的依赖进行处理
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: { // 对 src 中的依赖进行处理
minChunks: 2, // 最小使用次数(超过这个次数才按照此规则进行代码分割)
priority: -20, // 打包优先级
reuseExistingChunk: true, // 使用沿用已有的 chunk
},
},
},
},
};
splitChunks 常用的配置项
| 配置名称 | 配置类型 | 配置描述 |
|---|---|---|
| splitChunks.automaticNameDelimiter | string | 生成 chunk 名称的分隔符 |
| splitChunks.chunks | string | 指定哪些 chunk 进行优化 ('initial' | 'async' | 'all') |
| splitChunks.minSize | number | 生成 chunk 的最小体积(以 bytes 为单位,默认为 20000)。 |
| splitChunks.maxSize | number | 生成的 chunk 的最小体积 (优先级低于 minSize) |
| splitChunks.maxAsyncRequests | number | 最大的并行请求异步 chunk 的数量 (默认为 30) |
| splitChunks.maxInitialRequests | number | 最大的并行请求同步 chunk 的数量 (默认为 30) |
| splitChunks.minChunks | number | chunk 最少使用多少次才会被进行代码分割 |
| splitChunks.enforceSizeThreshold | number | 强制执行拆分的体积阈值 |
| splitChunks.layer | number | 按模块层将模块分配给缓存组。 |
| splitChunks.name | string | 拆分 chunk 的名称。 |
| splitChunks.usedExports | boolean | 是否开启 tree-shaking ? |
| splitChunks.cacheGroups | object | 代码分割的规则缓存组 |