基本原理
不同于手动分包,自动分包是从实际的角度出发,从一个更加宏伟的角度来控制分包,而一般不对哪个包要分出去进行控制
因此使用自动分包,不仅非常方便,而且更加贴合实际开发的需要
要控制自动分包,关键是要配置一个合理的分包策略
有了分包策略以后,不要额外的插件,wepack会自动按照分包策略进行分包
实际上,wepack内部使用的是
SplitChunksPlugin进行分包的 过去有一个库CommonsChunksPlugin也可以进行分包,不过由于该库的某些地方并不完善,到了webpack4以后,已经被SplitChunksPlugin取代
从分包流程中至少可以看出以下几点
- 分包策略至关重要,它决定如何分包
- 分包的时候,webpack开启一个新的chunk,对分离的模块进行打包
- 打包的结果中,公共的模块会被提取出来形成一个单独的文件,它是新chunk的产物
分包策略的基本配置
webpack提供了optimization的配置项,用于配置一下优化信息
其中splitChunks是分包的配置
module.exports={optimization:{splitChunks:{//分包策略}}}
事实上,分包策略具有默认的配置,我们只要轻微的改动,即可应对大部分的场景
chunks
该配置项用于配置需要应用分包策略的chunk
我们知道,分包是从已有的chunk中分离出来的新的chunk,那么哪些chunk需要分离呢
chunks有三个值,分别是:
- all: 对所有的chunk都要应用分包
- async: [默认] 仅针对异步的chunk应用分包策略
- initial: 仅针对普通的chunk应用的分包策略
所以,你只需要配置chunks为all即可
- maxSize
该配置可以控制包的最大字节数
如果某个包(包括分出来的包)超过了该值,则webpack会尽可能将其分离为多个包
但是不要忽略的是,分包的基础单位是模块,如果一个完整的模块超过了该体积,它是无法做到切割的,因此,尽管使用了这个配置,完全有可能某个包还是会超过这个体积
另外,该配置看上去很美妙,实际意义不大,
因为分包的目的是提取大量的公共代码,从而减少总的体积和充分利用浏览器缓存
虽然该配置可以吧一些包进行再切分,但实际上的总体积和传输量并没有发生变化
如果要进一步减少公共模块的体积,只能是压缩好
tree shaking
分包策略的其他配置
如果不想使用其他配置的默认值,可以进行手动的配置
- automaticNameDelimiter: 新chunk名称的分隔符,默认值~
- minChunks: 一个模块被多少个chunk使用时,才会被分包,默认为1,不可为0
- minSize: 当分包达到多少个字节后才允许被真正的拆分,默认值30000
缓存组
之前配置的策略都是全局的
而实际上,分包策略是基于缓存组的
每一个缓存组提供一套独有的策略,webpack按照缓存组的优先级依次处理每个缓存组,被缓存组处理过的分包不需要再次分包
默认情况下,webpack提供了两个缓存组:
module.exports = {optimization:{splitChunks: {//全局配置cacheGroups: {// 属性名是缓存组名称,会影响到分包的chunk名// 属性值是缓存组的配置,缓存组继承所有的全局配置,也有自己特殊的配置vendors: {test: /[\\/]node_modules[\\/]/, // 当匹配到相应模块时,将这些模块进行单独打包priority: -10 // 缓存组优先级,优先级越高,该策略越先进行处理,默认值为0},default: {minChunks: 2, // 覆盖全局配置,将最小chunk引用数改为2priority: -20, // 优先级reuseExistingChunk: true // 重用已经被分离出去的chunk}}}}}
很多时候,缓存组对我们来说没什么意义,因为默认的缓存组就已经够用了
但是我们同样可以利用缓存组来完成一些事情,比如公共的样式抽离
module.exports = {optimization: {splitChunks: {chunks: "all",cacheGroups: {styles: {test: /\.css$/, // 匹配样式模块minSize: 0, // 覆盖默认的最小尺寸,这里仅仅是作为测试minChunks: 2 // 覆盖默认的最小chunk引用数}}}},module: {rules: [{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"] }]},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({template: "./public/index.html",chunks: ["index"]}),new MiniCssExtractPlugin({filename: "[name].[hash:5].css",// chunkFilename是配置来自于分割chunk的文件名chunkFilename: "common.[hash:5].css"})]}
配合多页应用程序
虽然现在单页应用是主流,但是免不了还是会遇到多页应用
由于多页应用需要为每个html页面指定需要的chunk,这就造成了问题
new HtmlWebpackPlugin({template:'./public/index.html',chunks:['index~other','vendors~index~other','index']})
我们必须手动指定被分离出去的chunk名称,这不是一种好案办法
幸好html-webpack-plugin的新版本中解决了这一问题
npm i -D html-webpack-pugin@next
作出如下配置即可:
new HtmlWebpackPlugin({template:'./public/index.html',chunks:['index'] // 应用跟 index chunk相关的模块})
原理
自动分包的原理其实并不复杂,主要经过一下介个步骤:
- 检查每个chunk编译结果
- 根据分包策略,找到哪些满足策略的模块
- 根据分包的策略,生成新的chunk打包这些模块(代码有所变化)
- 把打包出去的模块的从原始的包中移除,并修正原始的包代码
在代码层面,有以下变动
- 分包的代码中,加入一个全局变量,类型为数组,其中包含公共的模块的代码
- 原始包的代码中,使用数组的公共代码

