本文大约1500字,看完本文大概须要10分钟,动手尝试须要1小时,若有错误,请指正。vue
webpack4出了两个月,发现你们包括我对splitChunk的使用都仍是在摸索阶段。我也看了挺多别人的配置demo,都以为不太满意或者没获得太好的解惑,issue 下面的问题也没什么人回复,只能本身操做了,顺便记录下来,若是你们有更好的,欢迎评论区留下地址。node
若是你对这些配置仍是不熟悉的话,一拉到底,看看文档react
先总览一下全部配置,后续会根据demo跑一遍常见的需求。webpack
optimization: {
splitChunks: {
chunks: "async", // 必须三选一: "initial" | "all"(推荐) | "async" (默认就是async)
minSize: 30000, // 最小尺寸,30000
minChunks: 1, // 最小 chunk ,默认1
maxAsyncRequests: 5, // 最大异步请求数, 默认5
maxInitialRequests : 3, // 最大初始化请求书,默认3
automaticNameDelimiter: '~',// 打包分隔符
name: function(){}, // 打包后的名称,此选项可接收 function
cacheGroups:{ // 这里开始设置缓存的 chunks
priority: 0, // 缓存组优先级
vendor: { // key 为entry中定义的 入口名称
chunks: "initial", // 必须三选一: "initial" | "all" | "async"(默认就是async)
test: /react|lodash/, // 正则规则验证,若是符合就提取 chunk
name: "vendor", // 要缓存的 分隔出来的 chunk 名称
minSize: 30000,
minChunks: 1,
enforce: true,
maxAsyncRequests: 5, // 最大异步请求数, 默认1
maxInitialRequests : 3, // 最大初始化请求书,默认1
reuseExistingChunk: true // 可设置是否重用该chunk
}
}
}
},
复制代码
接下来看看第一个例子git
entry: {
pageA: "./pageA", // 引用utility1.js utility2.js
pageB: "./pageB", // 引用utility2.js utility3.js
pageC: "./pageC" // 引用utility2.js utility3.js
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
chunks: "initial",
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0 // This is example is too small to create commons chunks
}
}
}
},
复制代码
结果如图,一切都很正常 commons~pageA~pageB~pageC.js 文件就是utility2.js commons~pageB~pageC.js,根据上述代码,这里的utility2被引用了三次,首先就被抽离了commons~pageA~pageB~pageC.js,而后utility3被引用了两次就放到了commons~pageB~pageC.js,最后只剩下被引用一次的utility1.js,就直接放到了pageA.js里面,若是这里的utility1.js的也是两次,他仍是会新建一个chunk放进去,而不是合并到commons~pageB~pageC.js,除非同入口引用才会合并。github
mpageA.js pageB.js pageC.jsweb
这里有个地方是须要优化一下的,就是pageA.js pageB.js pageC.js的代码很少,可是打出来的包很大,确定是一些webpack的运行文件,直接加上 runtimeChunksegmentfault
runtimeChunk: "single"
// 等价于
runtimeChunk: {
name: "manifest"
}
复制代码
如今就行了缓存
引用第三方模块 pageA引用vue.js pageB引用react react-dombash
vendor: {
test: /node_modules/,
chunks: "initial",
name: "vendor",
priority: 10,
enforce: true
}
复制代码
可是,这样子的话,会把pageA pageB pageC全部的库都打包到一块儿vendor.js
假如我想拆分这个vendor.js为pageA-vendor.js pageB-vendor.js怎么办,我试了好久,试出一个最简单的办法,去掉手动的vendor,让插件自动处理。
splitChunks: {
chunks: "all",
cacheGroups: {
commons: {
chunks: "initial",
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0 // This is example is too small to create commons chunks
}
}
},
复制代码
后来,我把webpack mode改为production后,发现无论用了,一样的配置,在生产模式下,打包出来的东西有点匪夷所思,vendor-pageB.js被合并到了pageB.js里面了。
后来我折腾了很久也分析不出来为何,本身折腾出来一种方式,仍是老子手动来吧,自动化一边去
commons: {
chunks: "initial",
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0 // This is example is too small to create commons chunks
},
'vendor-pageA': {
test: /vue/, // 直接使用 test 来作路径匹配
chunks: "initial",
name: "vendor-pageA",
enforce: true,
},
'vendor-pageB': {
test: /react/, // 直接使用 test 来作路径匹配
chunks: "initial",
name: "vendor-pageB",
enforce: true,
},
复制代码
成功打包出来了本身想要的东西。
动态引入你们应该都不陌生,就是你们所说的懒加载,直接在pageA和pageB页面里动态引入common-async.js,在这里我先说说,splitChunk应该是能够自动化处理相似commonChunk里的async,child等状况的。
import(/* webpackChunkName: "common-async.js" */"./common-async").then(common => {
console.log(common);
})
复制代码
还不错,成功打包出来了
这时候再试试,在这个common-async.js里面在引入共同的代码f.js,看看会不会重复打包
f.js成功的被抽离出来了,其余文件也没有被重复打包,挺好的。
上面的例子里面配置了一个commons,这里的name能够本身设置,也能够不设置,我是没设置的,你能够试试设置了是什么样子的,而后你就会明白这个name其实在某些状况下仍是不设置的比较好。
commons: {
chunks: "initial",
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0 ,
name: "commons"
},
复制代码
可见,splitChunk在懒加载方面,自动化处理的挺不错的,但在多页面的配置(根据不一样的页面抽离不一样的vendor)里,他由于有本身的一套优化策略,每每会获得不是咱们想要的输出。这篇文章只是我初步的一些常识,我尚未深刻去看源码,后续有空可能会补上splitChunk源码分析,到时候就更清晰了