Webpack 4 SplitChunksPlugin配置方案(转)

一般状况下咱们的 WebApp 是有咱们的自身代码和第三方库组成的,咱们自身的代码是会经常变更的,而第三方库除非有较大的版本升级,否则是不会变的,因此第三方库和咱们的代码须要分开打包,咱们能够给第三方库设置一个较长的强缓存时间,这样就不会频繁请求第三方库的代码了。javascript

那么如何提取第三方库呢?在 webpack4.x 中, SplitChunksPlugin 插件取代了 CommonsChunkPlugin 插件来进行公共模块抽取,咱们能够对SplitChunksPlugin 进行配置进行 拆包 操做。html

SplitChunksPlugin配置示意以下:前端

optimization: {
    splitChunks: { chunks: "initial", // 代码块类型 必须三选一: "initial"(初始化) | "all"(默认就是all) | "async"(动态加载) minSize: 0, // 最小尺寸,默认0 minChunks: 1, // 最小 chunk ,默认1 maxAsyncRequests: 1, // 最大异步请求数, 默认1 maxInitialRequests: 1, // 最大初始化请求书,默认1 name: () => {}, // 名称,此选项课接收 function cacheGroups: { // 缓存组会继承splitChunks的配置,可是test、priorty和reuseExistingChunk只能用于配置缓存组。 priority: "0", // 缓存组优先级,即权重 false | object | vendor: { // key 为entry中定义的 入口名称 chunks: "initial", // 必须三选一: "initial"(初始化) | "all" | "async"(默认就是异步) test: /react|lodash/, // 正则规则验证,若是符合就提取 chunk name: "vendor", // 要缓存的 分隔出来的 chunk 名称 minSize: 0, minChunks: 1, enforce: true, reuseExistingChunk: true // 可设置是否重用已用chunk 再也不建立新的chunk } } } } 复制代码

SplitChunksPlugin 的配置项不少,能够先去官网了解如何配置,咱们如今只简单列举了一下配置元素。vue

若是咱们想抽取第三方库能够这样简单配置java

splitChunks: {
      chunks: 'all', // initial、async和all minSize: 30000, // 造成一个新代码块最小的体积 maxAsyncRequests: 5, // 按需加载时候最大的并行请求数 maxInitialRequests: 3, // 最大初始化请求数 automaticNameDelimiter: '~', // 打包分割符 name: true, cacheGroups: { vendor: { name: "vendor", test: /[\\/]node_modules[\\/]/, //打包第三方库 chunks: "all", priority: 10 // 优先级 }, common: { // 打包其他的的公共代码 minChunks: 2, // 引入两次及以上被打包 name: 'common', // 分离包的名字 chunks: 'all', priority: 5 }, } }, 复制代码

这样彷佛大功告成了?并无,咱们的配置有很大的问题:node

  1. 咱们粗暴得将第三方库一块儿打包可行吗? 固然是有问题的,由于将第三方库一块打包,只要有一个库咱们升级或者引入一个新库,这个 chunk 就会变更,那么这个chunk 的变更性会很高,并不适合长期缓存,还有一点,咱们要提升首页加载速度,第一要务是减小首页加载依赖的代码量,请问像 react vue reudx 这种整个应用的基础库咱们是首页必需要依赖的以外,像 d3.js three.js这种特定页面才会出现的特殊库是不必在首屏加载的,因此咱们须要将应用基础库和特定依赖的库进行分离。
  2. 当 chunk 在强缓存期,可是服务器代码已经变更了咱们怎么通知客户端?上面咱们的示意图已经看到了,当命中的资源在缓存期内,浏览器是直接读取缓存而不会向服务器确认的,若是这个时候服务器代码已经变更了,怎么办?这个时候咱们不能将 index.html 缓存(反正webpack时代的 html 页面小到没有缓存的必要),须要每次引入 script 脚本的时候去服务器更新,并开启 hashchunk,它的做用是当 chunk 发生改变的时候会生成新的 hash 值,若是不变就不发生变更,这样当 index 加载后续 script资源时若是 hashchunk 没变就会命中缓存,若是改变了那么会从新去服务端加载新资源。

下图示意了如何将第三方库进行拆包,基础型的 react 等库与工具性的 lodash 和特定库 Echarts 进行拆分react

cacheGroups: {
        reactBase: { name: 'reactBase', test: (module) => { return /react|redux/.test(module.context); }, chunks: 'initial', priority: 10, }, utilBase: { name: 'utilBase', test: (module) => { return /rxjs|lodash/.test(module.context); }, chunks: 'initial', priority: 9, }, uiBase: { name: 'chartBase', test: (module) => { return /echarts/.test(module.context); }, chunks: 'initial', priority: 8, }, commons: { name: 'common', chunks: 'initial', priority: 2, minChunks: 2, }, } 复制代码

咱们对 chunk 进行 hash 化,正以下图所示,咱们变更 chunk2 相关的代码后,其它 chunk 都没有变化,只有 chunk2 的 hash 改变了webpack

output: {
    filename: mode === 'production' ? '[name].[chunkhash:8].js' : '[name].js', chunkFilename: mode === 'production' ? '[id].[chunkhash:8].chunk.js' : '[id].js', path: getPath(config.outputPath) } 复制代码

 

image.png image.png

 

咱们经过 http 缓存+webpack hash 缓存策略使得前端项目充分利用了缓存的优点,可是 webpack 之因此须要传说中的 webpack配置工程师 是有缘由的,由于 webpack 自己是玄学,仍是以上图为例,若是你 chunk2的相关代码去除了一个依赖或者引入了新的可是已经存在工程中依赖,会怎么样呢?git

咱们正常的指望是,只有 chunk2 发生变化了,可是事实上是大量不相干的 chunk 的 hash 发生了变更,这就致使咱们缓存策略失效了,下图是变动后的 hash,咱们用红圈圈起来的都是 hash 变更的,而事实上咱们只变更了 chunk2 相关的代码,为何会这样呢?github

 

image.png 缘由是 webpack 会给每一个 chunk 搭上 id,这个 id 是自增的,好比 chunk 0 中的id 为 0,一旦咱们引入新的依赖,chunk 的自增会被打乱,这个时候又由于 hashchunk 根据内容生成 hash,这就致使了 id 的变更导致 hashchunk 发生巨变,虽然代码内容根本没有变化。 image.png
这个问题咱们须要额外引入一个插件HashedModuleIdsPlugin,他用非自增的方式进行 chunk id 的命名,能够解决这个问题,虽然 webpack 号称 0 配置了,可是这个经常使用功能没有内置,要等到下个版本了。
image.png

 

webpack hash缓存相关内容建议阅读此文章 做为拓展

做者:寻找海蓝96 连接:https://juejin.im/post/5d00820b5188255ee806a1c7 来源:掘金 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。
相关文章
相关标签/搜索