4.10.1 如何通过 Webpack 提取公共代码
问题一:如何通过 Webpack 提取公共代码?
1.抽离出公共部分common
Webpack 内置了专门用于提取多个 Chunk 中公共部分的插件 CommonsChunkPlugin,CommonsChunkPlugin 大致使用方法如下:
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
new CommonsChunkPlugin({
// 从哪些 Chunk 中提取
chunks: ['a', 'b'],
// 提取出的公共部分形成一个新的 Chunk,这个新 Chunk 的名称
name: 'common'
})
以上配置就能从网页 A 和网页 B 中抽离出公共部分,放到 common 中。
每个 CommonsChunkPlugin 实例都会生成一个新的 Chunk,这个新 Chunk 中包含了被提取出的代码,在使用过程中必须指定name属性,以告诉插件新生成的 Chunk 的名称。 其中chunks属性指明从哪些已有的 Chunk 中提取,如果不填该属性,则默认会从所有已知的 Chunk 中提取。
Chunk 是一系列文件的集合,一个 Chunk 中会包含这个 Chunk 的入口文件和入口文件依赖的文件。
2.基础运行库从 common 中抽离到 base 中去
首先需要先配置一个 Chunk,这个 Chunk 中只依赖所有页面都依赖的基础库以及所有页面都使用的样式,为此需要在项目中写一个文件base.js来描述 base Chunk 所依赖的模块,文件内容如下:
// 所有页面都依赖的基础库
import 'react';
import 'react-dom';
// 所有页面都使用的样式
import './base.css';
接着再修改 Webpack 配置,在 entry 中加入 base,相关修改如下:
module.exports = {
entry: {
base: './base.js'
},
};
以上就完成了对新 Chunk base 的配置。
为了从 common 中提取出 base 也包含的部分,还需要配置一个 CommonsChunkPlugin,相关代码如下:
new CommonsChunkPlugin({
// 从 common 和 base 两个现成的 Chunk 中提取公共的部分
chunks: ['common', 'base'],
// 把公共的部分放到 base 中
name: 'base'
})
由于 common 和 base 公共的部分就是 base 目前已经包含的部分,所以这样配置后 common 将会变小,而 base 将保持不变。
以上都配置好后重新执行构建,你将会得到四个文件,它们分别是:
base.js:所有网页都依赖的基础库组成的代码;
common.js:网页A、B都需要的,但又不在base.js文件中出现过的代码;
a.js:网页 A 单独需要的代码;
b.js:网页 B 单独需要的代码。
为了让网页正常运行,以网页 A 为例,你需要在其 HTML 中按照以下顺序引入以下文件才能让网页正常运行:
<script src="base.js"></script>
<script src="common.js"></script>
<script src="a.js"></script>
以上就完成了提取公共代码需要的所有步骤。
注意:针对 CSS 资源,以上理论和方法同样有效,也就是说你也可以对 CSS 文件做同样的优化。
问题二:可能会出现common.js中没有代码的情况?
原因是去掉基础运行库外很难再找到所有页面都会用上的模块。
在出现这种情况时,你可以采取以下做法之一:
CommonsChunkPlugin 提供一个选项minChunks,表示文件要被提取出来时需要在指定的 Chunks 中最小出现最小次数。 假如minChunks=2、chunks=['a','b','c','d'],任何一个文件只要在['a','b','c','d']中任意两个以上的 Chunk 中都出现过,这个文件就会被提取出来。 你可以根据自己的需求去调整 minChunks 的值,minChunks 越小越多的文件会被提取到common.js中去,但这也会导致部分页面加载的不相关的资源越多; minChunks 越大越少的文件会被提取到common.js中去,但这会导致common.js变小、效果变弱。
根据各个页面之间的相关性选取其中的部分页面用 CommonsChunkPlugin 去提取这部分被选出的页面的公共部分,而不是提取所有页面的公共部分,而且这样的操作可以叠加多次。 这样做的效果会很好,但缺点是配置复杂,你需要根据页面之间的关系去思考如何配置,该方法不通用。