做用
虽然webpack4已经出来好久了,CommonsChunkPlugin也已经舍弃了,可是仍是有不少项目是经过webpack3来打包的,对CommonsChunkPlugin各个配置项的认识仍是比较模糊,这里作个详细的记录。vue
CommonsChunkPlugin经过将公共模块拆出来,最终合成的文件可以在最开始的时候加载一次,以便存到缓存中供后续使用。node
既然是将公共模块拆分出来,那么确定是要有多个被打包的模块,即公共模块的来源,包括 入口文件和 已近提取出来的公共模块,若是来源只有一个,那么就当即被打包成一个单独文件,不会抽取公共模块,由于一个chunk来源是不会出现公共模块的,这是webpack打包策略,只会出现各个组件的相互引用,这种状况用于提取第三方库等;若是来源不少个,那么会提取出公共的模块组成一个单独的文件,来源文件再各自打包成各自的单独文件
这里最重要的是搞清楚的就是配置项中各类chunk的概念和来源,咱们首先看看有哪些配置选项。再对配置项逐一解析。jquery
用法webpack
new webpack.optimize.CommonsChunkPlugin(options);
options选项及官方翻译web
{ name: string, // or names: string[], /*name或者names是入口文件中的chunk名称,公共模块chunk能够在入口文件中定义名称和所对应的模块,而后被选择; *name和names的不一样在于:name只选择一个入口chunk进行分开打包,names至关于name的遍历版, *对names数组中的chunk遍历,而后单独打包,此时options.filename不能是具体的名称,某则会出现相同的名称而报错, * */ // 若是该选项被忽略,同时 `options.async` 或者 `options.children` 被设置,全部的 chunk 都会被使用, // 不然 `options.filename` 会用于做为 chunk 名。 filename: string, /*文件的名字模板,可使用和output相同的占位符,如[hash:7],7表明7位hash符号,默认是20位; * 默认名字与`output.filename` 或者 `output.chunkFilename`相同*/ minChunks: number|Infinity|function(module, count) => boolean, // 在传入 公共chunk(commons chunk) 以前所须要包含的最少数量的 chunks 。 // 数量必须大于等于2,或者少于等于 chunks的数量 // 传入 `Infinity` 会立刻生成 公共chunk,但里面没有模块。 // 你能够传入一个 `function` ,以添加定制的逻辑(默认是 chunk 的数量) /*module.context表明chunk因此在的文件夹路劲, *module.resource表明该chunk的文件路劲 *count chunk被引入的次数*/ chunks: string[], // 经过 chunk name 去选择 chunks 的来源。chunk 必须是 公共chunk 的子模块。 // 若是被忽略,全部的,全部的 入口chunk (entry chunk) 都会被选择。 /*chunks和children是相同的做用,不一样的是chunks只选择特定的子模块抽取公共模块, *而children是选择全部的子模块*/ children: boolean, // 若是设置为 `true`,全部公共 chunk 的子模块都会被选择 /*将子模块的公共模块打包进父 chunk */ deepChildren: boolean, // 若是设置为 `true`,全部公共 chunk 的后代(子孙)模块都会被选择 async: boolean|string, // 若是设置为 `true`,一个异步的 公共chunk 会做为 `options.name` 的子模块,和 `options.chunks` 的兄弟模块被建立。 // 它会与 `options.chunks` 并行被加载。 minSize: number, // 在 公共chunk 被建立立以前,全部 公共模块 (common module) 的最少大小。 }
配置项介绍
不按照上面的顺序介绍,有些配置项很类似,容易弄混,按照我本身理解来解释。vue-router
1. filename
这是文件名的模板,和output.filename 或者 output.chunkFilename是一个意思,最终生成的文件名。数组
若是配置了这个项,以这个模板优先取名,不然,按照output.filename 或者 output.chunkFilename规则取名。缓存
2. name or names
这个抽取的公共模块的名字,这个和filename仍是有区别的,filename=name+hash+其它可能的配置项+ext。
example1: 这里adminA和adminB都引入的common.js,因此会抽取common.js做为公共模块。app
//adminA require("./common") console.log("adminA")
//adminA require("./common") console.log("adminB")
entry: { adminA: "./adminA", adminB: "./adminB", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "commons", }), ]
打包生成名为 commons的公共模块echarts
同时,若是这个name和入口文件的name相同,那么入口文件直接被选择为打包来源,即直接指定name所指定的入口文件为公共模块;这个在很明确公共模块是什么的时候颇有用,好比第三方库,能够直接指定。
names则是经过遍历names数组,执行屡次该插件,免去写多个相同的代码(若是有这个需求)。例:
example2: 增长adminC,可是没有引入common.js,只有adminA和adminB引入了。
//adminC console.log("adminC");
entry: { adminA: "./adminA", adminB: "./adminB", adminC: "./adminC", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, plugins: [ new BundleAnalyzerPlugin(), new webpack.optimize.CommonsChunkPlugin({ name: "commons", }), ]
虽然也生成了commons.js可是其实里面没有任何东西(文件很小),adminA和adminB文件仍是很大,也就是没有抽取公共模块:
能够用插件webpack-bundle-analyzer分析:common.js仍是存在adminA.js和adminB.js里面
这个时候在入口文件直接指定公共模块commons:
example3
entry: { adminA: "./adminA", adminB: "./adminB", adminC: "./adminC", //name和配置项的name相同 commons: './common.js' },
能够从文件大小看出来,公共模块已经抽取出来了。
3. minChunks
被其余模块引用的次数 (默认是3),只有知足这个引入次数条件才会被抽取,若是设置成 Infinity (无限大,不可能知足),那么会当即打包成一个独立模块,不会抽取公共模块,用于公共模块很明确的时候或者想直接打包某一chunk。
例如前面的example2,也能够不用在入口指定公共模块,主要是由于minChunk的默认值是3,而common.js只被adminA和adminB引入了,也就是只引入了两次,因此不会被打包,咱们这里将example2的minChunks设置2,再打包:
example4:
entry: { adminA: "./adminA", adminB: "./adminB", adminC: "./adminC", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, plugins: [ new BundleAnalyzerPlugin(), new webpack.optimize.CommonsChunkPlugin({ name: "commons", minChunks: 2 }), ]
从文件大小上能够看出,common.js已经抽取出来了:
minChunks也能够是一个函数,webpack会遍历全部来源chunk,逐一执行这个函数,函数返回true这个chunk才被提取为公共模块。这个函数用于更加精确的提取公共模块,如vue构建工具生成的配置文件,能够提取全部在文件夹node_modules中的模块:
example5:
//这里是提取全部的第三方插件,如我这里有vue,vue-router,echarts //可是echarts太庞大了,须要和vue,vuer-router分离 new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks(module) { /*module.context表明chunk因此在的文件夹路劲, *module.resource表明该chunk的文件路劲 *count chunk被引入的次数*/ return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../node_modules') ) === 0 ) }, chunks: ["app"] }), //分离vue,vue-router,echarts是按需引入的,不太方便按这种方式抽取。 new webpack.optimize.CommonsChunkPlugin({ name: 'vue', minChunks: function (module) { return (module.resource && /\.js$/.test(module.resource) && (/vue/).test(module.resource)) }, chunks: ['vendor'] }),
4. chunks
选择chunk来源,即选择要被抽取的模块来源,这个很好理解,即被选择的chunk来源才会被抽取公共模块。如:A和B同时引入C,而D没有引入C,那么就能够只选择A和B做为chunk来源,抽取A、B的公共模块C,不然C可能不会被抽取为公共模块。
eample6: adminA、adminB和adminC都引入common.js,可是chunks只选择adminA和B。
entry: { adminA: "./adminA", adminB: "./adminB", adminC: "./adminC", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, plugins: [ new BundleAnalyzerPlugin(), new webpack.optimize.CommonsChunkPlugin({ name: "commons", minChunks: 2, chunks: ['adminA', 'adminB'] }), ]
结果:adminA和adminB的common.js被抽取出来了,可是adminC的common.js没有被抽取出来(从大小上判断)。
5. children
children: webpack官方给出了一个案例,中文版是翻译过来的,可是我看了好久都没看明白,其实翻译是不够严谨的,案例中翻译说 一个 chunk的子模块会有公共模块,配置参数里面翻译是公共模块的子模块会有公共依赖,我想了很久,都没想出这个子模块是什么意思;实际上是 一个入口的模块的子模块,子模块指的是 异步加载模块、经过代码分割功能从这个入口chunk分离出来的chunk,在模块中使用import()或者require.ensure(),会单独打包这一部分模块。
eample7: adminA经过代码分割功能,异步加载childA和childB,childA和childB都引入了jquery和common。
//adminA.js import('./childA'); import('./childB'); console.log("adminA");
//chuildA import './jquery'; import './common'; console.log('childA');
//chuildB import './jquery'; import './common'; console.log('childB');
//webpack.config.js entry: { adminA: "./adminA", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js", chunkFilename: '[name].chunk.js' }, plugins: []
不优化的打包结果:生成了两个异步的chunk,0和1,就是childA和childB。childA和childB都引入了common.js和jquery.js,体积很大。
咱们试着优化,看能不能把异步加载的模块的公共模块抽取出来:
eample8:
//webpack.config.js entry: { adminA: "./adminA", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js", chunkFilename: '[name].chunk.js' }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "commons", minChunks: 2 }),
]
结果:common.js和jquery.js并无抽取出来成为公共模块,只是抽取了webpack代码分离功能的代码,由于代码分离出来的chunk,并不在chunk来源选择范围内(忽略了chunks选项,那么默认是所有的chunk来源,可是排除代码分离的chunk)。
咱们加上children:true,而且须要把name设置成入口chunk的name,此处是adminA:
eample9:
//webpack.config.js entry: { adminA: "./adminA", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js", chunkFilename: '[name].chunk.js' }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "adminA", minChunks: 2, children: true }),
]
结果:common.js和jquery.js被打包进了adminA,也就是代码分离后子模块的公共模块被打包进了父模块。减小了整体体积。可是会增长初始加载时间(即加载adminA的时间会延长),若是分离子模块的公共代码不少,而且预计到用户会加载不少子模块(代码分离的子模块),能够这样作。固然,还有另一种方法,就是async.
6.async
async: 就是把代码分离模块的公共模块抽取出来。不一样于上面children:true是把公共模块抽取放到父模块中,async:true把公共模块单独抽取出来做为一个公共模块,和以前抽取公共模块是同样的,只不过这个抽取的是分离代码的公共模块。
再看**example10:**在example9的基础上加上async,async能够取值Boolean值也能够是string,若是是string,那么这个string值做为chunk打包后的name,若是是Boolean值,那么打包后的name就是0。
一样,这里的options.name要和入口chunk的name匹配
entry: { adminA: "./adminA", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js", chunkFilename: '[name].chunk.js' }, plugins: [ new BundleAnalyzerPlugin(), new webpack.optimize.CommonsChunkPlugin({ //要和入口chunk的name匹配 name: "adminA", minChunks: 2, children: true, async: "async-chunk" }), ]
名为async-chunk.chunk.js就是咱们分离代码的公共模块。
7.minSize
抽取公共代码以前,应该知足的文件的大小。若是抽取出来的公共代码文件大小只有几kb,这样会增长请求次数,还不如不抽取。
8.deepChildren
这个目前还不知道有什么用,和children差很少,children选择的是直接子代,deepChildren选择的是全部后代,可是目前我并无发现它有什么用。
原文连接:https://blog.csdn.net/zy444263/article/details/85252477