基本原理
-
不同与手动分包,自动分包是从 实际的角度 出发,从一个更加 宏观的角度 来控制分包,而一般不对具体哪个包要分出去进行控制,因此使用自动分包,不仅非常方便,而且更加贴合实际的开发需要;
-
要控制自动分包,关键是要配置一个合理的 分包策略 ,有了分包策略之后,不需要额外安装任何插件,webpack 会自动的按照策略进行分包;
-
从分包流程中至少可以看出以下几点:
- 分包策略至关重要,它决定了如何分包;
- 分包时 webpack 开启了一个 新的chunk ,对分离的模块进行打包;
- 打包结果中,公共的部分被提取出来形成了一个单独的文件,它是新 chunk 的产物;
实际上 webpack 在内部是使用 SplitChunksPlugin 进行分包的过去有一个库
CommonsChunkPlugin也可以实现分包,不过由于该库某些地方并不完善,到了webpack4
之后,已被 SplitChunksPlugin 取代
自动分包的流程
自动分包的原理其实并不复杂,主要经过以下步骤:
- 检查每个 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
- minSize:当分包达到多少字节后才允许被真正的拆分,默认值 30000
缓存组
-
之前配置的分包策略是全局的,而实际上,分包策略是基于缓存组的;每个缓存组提供一套独有的策略,webpack 按照缓存组的优先级依次处理每个缓存组,被缓存组处理过的分包不需要再次分包;
-
默认情况下 webpack 提供了两个缓存组:
module.exports = { optimization:{ splitChunks: { //全局配置 cacheGroups: { // 属性名是缓存组名称,会影响到分包的 chunk 名 // 属性值是缓存组的配置,缓存组继承所有的全局配置,也有自己特殊的配置 vendors: { test: /[\\/]node_modules[\\/]/, // 当匹配到相应模块时,将这些模块进行单独打包 priority: -10 // 缓存组优先级,优先级越高,该策略越先进行处理,默认值为 0 }, default: { minChunks: 2, // 覆盖全局配置,将最小 chunk 引用数改为 2 priority: -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-plugin@next
-
做出以下配置即可,它会自动的找到被 index 分离出去的 chunk 并完成引用
new HtmlWebpackPlugin({ template: "./public/index.html", chunks: ["index"] })
vue3🛫 Suspense 组件
上一篇