代码分割
到目前为止输出的build.js里面包含了javaScript和Css代码,同时项目中使用的依赖模块也会被打包到build.js中导致build.js比较庞大,在加载build.js的时候会耗时较多,导致页面加载缓慢。所以需要对输出文件进行合理分割,生成多个多类型文件,然后充分利用浏览器的并行请求机制,同时请求这些文件,提升页面的加载速度。
对Css的分割
使用Mini-css-extract-plugin对于Css代码的分割,其配置如下:
use: [
MiniCssExtractPlugin.loader,
'css-loader',
// 其他loader
]
还需要在plugins中进行如下配置:
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[hash:5].css',
chunkFilename: '[id].css',
}),
]
到此就实现了Css代码的抽离,同时专门生成了css文件夹用于存放抽离的Css文件,让目录结构更加规范。
对javaScript的分割
针对javaScript代码的分割可以分为两部分的分割,分别是是同步代码分割和异步代码分割。
通过SplitChunksPlugin实现同步代码分割,其默认配置如下:
module.exports = {
optimization: {
splitChunks: {
/**
* async只对异步代码分割
* initial只对同步代码分割
* all所有代码进行分割(推荐)
*/
chunks: 'async',
// 大于30000bit的模块才进行分割
minSize: 30000,
// 当模块大于maxSize进行二次分割,设置为0则不做二次分割
maxSize: 0,
// 模块被引入的次数大于等于minChunks才做代码分割
minChunks: 1,
// 异步加载的js文件最大数目为边界条件进行代码分割
maxAsyncRequests: 5,
//以初始加载的js文件最大数目为边界条件进行代码分割
maxInitialRequests: 3,
// 代码分割生成文件名称链接符号
automaticNameDelimiter: '~',
// 代码分割生成文件自动生成文件名
name: true,
// 代码分割缓存组,被分割代码文件通过缓存组输出为一个文件。
cacheGroups: {
// 第三方模块分割
vendors: {
// 正则匹配模块路径(作用范围规定)
test: /[\\/]node_modules[\\/]/,
// 优先级,优先级越高越先执行其对应的分割操作(-10》-20)
priority: -10
},
default: {
// 默认缓存组,一般设置priority优先级数值最小
minChunks: 2,
priority: -20,
// 表示是否复用存在的chunk
reuseExistingChunk: true
}
}
}
}
}
在项目中为了实现单页面,我们创建并使用了history.js,现在我们使用SplitChunks把它从build.js中分离出来,配置如下:
module.exports = {
optimization: {
splitChunks: {
// cacheGroups里面的配置可以覆盖掉splitChunks中的配置
cacheGroups: {
common: {
test: /utils\/history\.js/,
chunks: "all",
minChunks: 1,
minSize: 500,
filename: 'common/common.js'
}
}
}
}
}
现在在输出资源common目录下多了common.js,其内容就是history.js打包的结果,其大小为3.18Kib,同时build.js体积变小,说明代码分割成功。
值得注意的是,现在的构建效率与之前相比会变缓慢,原因是分割出来的代码也需要进行系统的I/O操作,多余的耗时几乎都是花在这上面。为了优化页面的加载,合理的代码分割是无法避免的,在不同的项目场景,开发人员需要认真考虑进行怎样的配置,才能做到开发人员和用户双赢。
异步代码分割跟同步代码分割配置大同小异,值得注意的是如果你使用了babel相关的模块来处理项目文件,那么要实现异步代码的分割,需要使用@babel/plugin-syntax-dynamic-import插件,其配置如下:
{
loader: 'babel-loader',
options: {
// 预设集合
presets: ['@babel/preset-env'],
// 插件集合
plugins: [
// 使用其他插件
"@babel/plugin-syntax-dynamic-import"
]
}
}
该插件能够使得Babel能够解析识别import()动态导入语法,配置以后,就可以实现按需加载代码的分割。
演示代码如下所示:
const btns = document.getElementById("home-dialog-btn");
btns.onclick = () => {
import('../../utils/dialog').then(res => {
console.log(res.default);
})
}