CommonsChunkPlugin 详解,webpack4 改成optimization.splitChunks

CommonsChunkPlugin:
1. name和names:将符合条件的模块提取到指定name的chunk中. 如果name为不存在的chunk则创建新chunk,如果name指定的chunk存在,则继续往chunk中添加被提取的模块内容所有chunk的公共代码
2 filename:指定提取出的公共代码的文件名称可以带路径,不指定 则使用output配置项中文件名的占位符。未定义时使用name作为文件名。
3 chunks:可以指定要提取公共模块的源chunks,指定的chunk必须是公共chunk的子模块,如果没有指定则使用所有entry中定义的入口chunk。
4 minChunks:在一个模块被提取到公共chunk之前,它必须被最少minChunks个chunk所包含。(通俗的说就是一个模块至少要被minChunks个模块所引用,才能被提取到公共模块。)
该数字必须不小于2或者不大于chunks的个数。默认值等于chunks的个数
如果指定了Infinity,则创建一个公共chunk,但是不包含任何模块,内部是一些webpack生成的runtime代码和chunk自身包含的模块(如果chunk存在的话)。
5 children:children和chunks不能同时设置,因为它们都是指定source chunks的
6 async

注意:vender是我们提取出来的公共chunk,通常不会被修改,所以理应在每次编译后文件名保持一致
所以 抽离第三方库和自定义公共模块

[cc lang=”javascript”]
// 第一种方法minChunks设为Infinity
//Infinity:只有当入口文件(entry chunks) >= 3 才生效,用来在第三方库中分离自定义的公共模块
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: [‘vendor’,’runtime’], // 在vendor上继续抽离 webpack运行文件
filename: ‘[name].js’,
minChunks: Infinity // 抽离自定义公共模块
}),
new webpack.optimize.CommonsChunkPlugin({
name: ‘common’,
filename: ‘[name].js’,
chunks: [‘first’,’second’]
//从first.js和second.js中抽取commons chunk, 也可以用 children和async 异步加载公共模块
}),
][/cc]

[cc lang=”javascript”]
//module:当前chunk及其包含的模块
//count:当前chunk及其包含的模块被引用的次数
//minChunks作为函数会遍历每一个入口文件及其依赖的模块,返回一个布尔值,为true代表当前正在处理的文件(module.resource)合并到commons chunk中,为false则不合并。
const config = {
entry: {
first: ‘./src/first.js’,
second: ‘./src/second.js’,
//vendor: Object.keys(packagejson.dependencies)//获取生产环境依赖的库
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ‘vendor’,
filename: ‘[name].js’,
minChunks: function (module,count) {
console.log(module.resource,`引用次数${count}`);
//”有正在处理文件” + “这个文件是 .js 后缀” + “这个文件是在 node_modules 中”
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, ‘./node_modules’)) === 0
)
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: ‘runtime’,
filename: ‘[name].js’,
chunks: [‘vendor’]
}),
]
}[/cc]

[cc lang=”javascript”]

new webpack.optimize.CommonsChunkPlugin({
children: true,
async: ‘children-async’
})[/cc]

你设置之后,也得看children的脸色怎么来划分:
children为true,共同引用的模块就会被打包合并到名为children-async的公共模块,当你懒加载first或者second的时候并行加载这和children-async公共模块
children为false,共同引用的模块就会被打包到首屏加载的app.bundle当中,这就会导致首屏加载过长了,而且也不要用到,所以最好还是设为true

webpack 4

splitChunks

[cc lang="js"]

// b.js
import vue from "vue" 

// 入口js
import _ from "lodash"
import "./a.js" //同步加载
import ('./b.js') //异步加载
[/cc]

chunks:抽取公共模块的来源,只有三个值

 async:(动态加载模块) 只分割异步打包的代码,b.js 会打包出b和vue两个chunk, lodash 拆不出来

 initial:(入口模块),只从入口进行拆分,但是异步内部的引入将不再考虑,直接打包一起,会将vue和b的内容打在一起

 all:(全部模块入口和动态的) 分割异步同步代码(需要定义新规则,将同步的代码打包) 

[cc lang=”js”]
//同步代码分割配置
splitChunks: {
chunks: ‘all’,
cacheGroups: {
a : {
name: ‘a’,
chunks: ‘all’,
}
}
}
// 会生成 一个同步代码a.js 和 分离出的b.js 和 vue 两个 chunk
[/cc]

Function(chunk): chunk对象包含chunk本身的许多信息,有用的也就是chunk.name,可以通过name选择特定的模块来源,返回true则选中,否则不选中。

cacheGroups 自定义配置决定生成的文件,缓存策略

  • test : 限制范围,正则匹配文件夹或文件
  • name : 打包的chunks的名字
  • priority : 优先级,多个分组冲突时决定把代码放在哪块
  • enforce: 强制生成

maxAsyncRequests:  异步的按需加载模块最大的并行请求数,通过import()或者require.ensure()方式引入的模块,分离出来的包是异步加载的。default:5
maxInitialRequests: entry文件最大的并行请求数, 默认3
minSize: 生成新的chunk的最小体积,默认30000B
maxSize: 打包出来的新的chunk最大的文件大小,与minSize相对,超过这个值,将新的chunk再进一步拆分成更小的chunk,单位B,默认0。
automaticNameDelimiter: name连接符,分离出来的新chunk的名字,默认基于cacheGroupsKey,chunks来源的name来取,例:缓存组的cacheGroupsKey是vendor,来源chunk是的name是adminA,adminB,那么连接符是~,分离出的chunk名字是vendor~adminA~adminB.js。

name: Boolean | string | function (module, chunks, cacheGroupKey)

分离出来的chunk的取名规则。不能和入口文件同名,如果和入口文件同名,那么入口文件将会被移除,不会被打包

          Boolean :如果是true,基于cacheGroupsKey,chunks来源的name来取。如果是false,按照数字0排序。
         string : string作为name, string.js。
         function (module, chunks, cacheGroupKey)
              cacheGroupKey: 缓存组的键名;
              chunks: Array类型,splitChunks.chunks的数组集合,每一个chunk对象有很多属性,这里有用也就         只有chunks[i].name,即打包来源chunk的键名;
              module: 可能有用的值module.context,module.resource,module.type;module.context公共模块来源chunk的所在文件夹,例如通过 npm 下载的包chunks.context == path.resolve(__dirname , ‘node_modules’);,module.resource公共模块来源chunk的完整路径,module.type文件类型javascript/auto,css/auto。
            返回值: 返回值作为文件名,同样不能和入口文件同名,否则入口文件会被移除

!!@  如果你要做精细化的代码分离,需要配置缓存组cacheGroups,

cacheGroups拥有上面所有的属性,除此之外还有priority、reuseExistingChunk、test、enforce四个属性,并且缓存组能够覆盖上面所有的属性。

priority :优先级,default:0;如果两个缓存组都需要将某一公共模块打包,为了不重复打包,肯定只能打包进入其中之一,那么优先考虑priority 高的。
reuseExistingChunk:是否重用已经存在的模块,default:true;例:如果在当前缓存组需要抽离出 jquery.js,但是 jquery.js已经被其它缓存组抽取出来了,那么将会重用已经抽取出来的 jquery.js。
test:function (module, chunks) | RegExp | string 在chunks的基础上,精确的选择那些公共模块应该被打包。
enforce:忽略minSize、maxSize、maxAsyncRequests、maxInitalRequests等限制条件直接打包。

缓存组也有默认配置 default ,default的配置会覆盖splitChunks中的默认配置,并且其它缓存组的minSize的优先级低于default缓存组的优先级,所以默认配置最好还是在splitChunks配置,不要在缓存组配置:

[cc lang=”js”]
splitChunks: {
chunks: ‘all’, // initial、async和all
minSize: 30000, // 形成一个新代码块最小的体积
maxAsyncRequests: 5, // 按需加载时候最大的并行请求数
maxInitialRequests: 3, // 最大初始化请求数
automaticNameDelimiter: ‘~’, // 打包分割符
name: true,
cacheGroups: {
vendors: { // 项目基本框架等
chunks: ‘all’,
test: /[\\/]node_modules[\\/](vue|vue-resource|vuex|underscore|mint-ui|jsonp|axios|babel-polyfill)[\\/]/, // 需要加node_modules,不然打包不纯
priority: 100,
name: ‘vendors’,
},
‘async-commons’: { // 异步加载公共包、组件等
chunks: ‘async’,
minChunks: 2,
name: ‘async-commons’,
priority: 90,
},
commons: { // 其他同步加载公共包
chunks: ‘all’,
minChunks: 2,
name: ‘commons’,
priority: 80,
},
}
}
// 同样用到react 单priority 等级高, 只会打包到vendors 里
// 如果我们这里将commons的配置去掉,将会生成一个topic~home的包,我们配置了async-common提取出异步加载的公共包后,将会默认将同步加载的公共包打包生成以automaticNameDelimiter连接符‘~’生成的名字’topic~home’包,内容其实和commons包内容完全一样
[/cc]

最后
hash 是 build-specific ,即每次编译都不同——适用于开发阶段
chunkhash 是 chunk-specific,是根据每个 chunk 的内容计算出的 hash——适用于生产

问题
chunk 不能打包到html 里

Leave a Reply

Your email address will not be published. Required fields are marked *