• webpack splitChunks解析


    module、chunk和bundle

    要理解splitChunks,先要理解webpack的提出的几个概念,module、chunk和bundle。

    • module:每个import引入的文件就是一个模块(也就是直接手写的代码)
    • chunk:当module源文件传到webpack进行打包时,webpack会根据文件引用关系生成chunk(也就是module在webpack处理时是chunk)
    • bundle:是对chunk进行压缩等处理后的产出(也就是打包后可以直接运行的文件)
      在这里插入图片描述

    webapck拆分出的chunk有四种:

    • 根据入口文件拆分
    • 根据异步文件拆分(import(‘…’))
    • 根据spliteChunk拆分
    • 还有一些运行时runtimeChunk,负责
      • 形如 import('abc').then(res=>{}) 这种异步加载的代码,在webpack中即为运行时代码
      • 每次更改所谓的运行时代码文件时,打包构建时app.js的hash值是不会改变的。如果每次项目更新都会更改app.js的hash值,那么用户端浏览器每次都需要重新加载变化的app.js,如果项目大切优化分包没做好的话会导致第一次加载很耗时,导致用户体验变差。现在设置了runtimeChunk,就解决了这样的问题。所以 这样做的目的是避免文件的频繁变更导致浏览器缓存失效,所以其是更好的利用缓存。提升用户体验。

    splitChunks

    默认配置:

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          chunks: 'async',
          minSize: 20000,
          minRemainingSize: 0,
          minChunks: 1,
          maxAsyncRequests: 30,
          maxInitialRequests: 30,
          enforceSizeThreshold: 50000,
          cacheGroups: {
            defaultVendors: {
              test: /[\\/]node_modules[\\/]/,
              priority: -10,
              reuseExistingChunk: true,
            },
            default: {
              minChunks: 2,
              priority: -20,
              reuseExistingChunk: true,
            },
          },
        },
      },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    假如我们有这样一个配置

    module.exports = {
     entry: {
          app: './src/index'
     },
     output: {
       path: path.resolve(__dirname, 'dist'),
       filename: '[name].[hash:8].bundle.js', // 用于以entry为入口的chunk
       chunkFilename: '[name].[hash:16].bundle.js' // 用于动态加载的chunk
     }
    }
    
    // .src/index.js
    const test = 123
    console.log(test)
    import _ from 'lodash'
    setTimeout(()=> {
        import(/* webpackChunkName: 'test' */ './test')
        import(/* webpackChunkName: 'math' */ './math')
    }, 2000)
    
    // ./test.js
    import './helper'
    
    // ./math.js
    import './helper'
    
    // ./helper.js
    // 从jQuery官网download的源码,helper.js Size > 30kb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    默认在build的时候,webpack会将lodash和业务逻辑都打包到一个bundle中,这个bundle非常的大
    在这里插入图片描述

    splitChunks.chunks

    async,表明只能分离异步的模块
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RhjjxFS6-1661777263263)(/tencent/api/attachments/s3/url?attachmentid=756452)]

    • app.js下的bundle包含了lodash模块,而math和test两个文件由于share了同一个helper,并且这个helper的size大于30kb,因此被分离出来,成为一个新的bundle

    chunks:initial

    当为initial时,只能分离初始化的模块,异步的模块无法分离
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZ1VCcBn-1661777263263)(/tencent/api/attachments/s3/url?attachmentid=756453)]

    • app.js里的lodash被分离成一个bundle,而math和test里的js并没有分离出来,没有处理异步模块内的内容

    chunks:all

    将初始化或者异步的模块都分离出来
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2CxVQJpL-1661777263264)(/tencent/api/attachments/s3/url?attachmentid=756455)]

    • lodash和helper都被分离成单个bundle了

    当splitChunks.chunk为一个函数时,可以自行选择哪些chunk需要被分离

    optimization: {
     splitChunks: {
       chunks (chunk) {
          return chunk.name !== 'test' && chunk.name !== 'math'
       }
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • lodash被分离成单个bundle,而helper并没有被分离出来
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UoL7SIw3-1661777263265)(/tencent/api/attachments/s3/url?attachmentid=756478)]

    splitChunks.maxAsyncRequests

    异步文件的最大并行请求数量

    optimization: {
     splitChunks: {
       maxAsyncRequests: 1 // 2
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在build的时候会发现,这时候webpack并没有帮我们做codeSplitting
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LI5IvBPL-1661777263265)(/tencent/api/attachments/s3/url?attachmentid=756498)]

    将maxAsyncRequests改成2时,helper里的内容就会分离成一个单独的bundle。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AByCnm32-1661777263265)(/tencent/api/attachments/s3/url?attachmentid=756507)]

    splitChunks.maxInitialRequests

    entry的最大并行请求数,默认是3个。这个选项主要适用于多页应用的项目

    maxInitialRequest、maxAsyncRequests 、maxSize 、 minSize的优先级

    maxInitialRequest/maxAsyncRequests < maxSize < minSize .

    抽离案例

    Vendors

    chunk-a: react, react-dom, 一些组件1
    chunk-b: react, react-dom, 一些组件2
    chunk-c: angular, 一些组件3
    chunk-d: angular, 一些组件4
    
    webpack4 会自动创建两个vendor chunks,结果如下:
    vendors~chunk-a~chunk-b: react, react-dom
    vendors~chunk-c~chunk-d: angular
    chunk-a 到 chunk-d: 只包含各自的组件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    重复的vendors

    chunk-a: react, react-dom, 一些组件1
    chunk-b: react, react-dom, lodash, 一些组件2
    chunk-c: react, react-dom, lodash, 一些组件3
    
    webpack4同样也会创建两个vendors chunks,结果如下:
    vendors~chunk-a~chunk-b~chunk-c: react, react-dom
    vendors~chunk-b~chunk-c: lodash
    chunk-a 到 chunk-c: 只只包含各自的组件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    共享的modules

    chunk-a: vue, 一些组件1, 一些被共享的业务组件(非node_modules资源)
    chunk-b: vue, 另一些组件2, 一些被共享的业务组件
    chunk-c: vue, 另一些组件3, 一些被共享的业务组件
    
    假定被共享的组件大小超过30kb,那么webpack4会创建一个venrdors chunk和一个commons chunk,结果如下:
    vendors~chunk-a~chunk-b~chunk-c: vue
    comons-chunk-a~chunk-b~chunk-c: 一些被共享的业务组件
    chunk-a 到 chunk-c: 只包含各自的组件
    当被共享的业务组件大小小于30kb时,webpack4会将他们重复的模块放到chunk-a到chunk-c中,而不是分离出一个common chunk来。我们认为,下载一个体积小于30kb的chunk而导致额外的http请求,是不值得的。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    多个分享的模块

    chunk-a: react, react-dom, 一些组件1, 一些共享的react组件
    chunk-b: react, react-dom, angular, 一些组件2
    chunk-c: react, react-dom, angular, 一些组件3, 一些共享的react组件, 一些共享的angular组件
    chunk-d: angular, 一些组件4, 一些共享的angular组件
    
    webpack4会创建两个vendors chunks和两个commons chunks
    vendors~chunk-a~chunk-b~chunk-c: react, react-dom
    vendors~chunk-b~chunk-c~chunk-d: angular
    commons~chunk-a~chunk-c: 一些共享的react组件
    commons~chunk-c~chunk-d: 一些共享的angular组件
    chunk-a to chunk-d: 各自的组件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    配置解析

    • chunks:可用值为“all”、“async”、“initial”,默认值是“async”

      • all:拆分同步和异步文件
      • async:只对异步文件作处理
      • initial:只对入口文件进行拆分,不去处理异步文件里的模块
    • minSize:控制最小包的大小,大于这个值才会去拆分,如果拆分的公共模块小于这个大小,那就复制成多份,直接打包到引用该模块的包里

    • minChunks:模块的重复调用次数大于等于minChunks值时,就会满足这项拆包条件,但只看入口模块导入的,不看动态加载模块中导入的(import(‘…’)),即使设置的chunks为“all”。

    • maxInitialRequests:入口文件最大请求的文件数量(import等方式)

      • 入口文件本身算一个请求
      • 入口文件动态加载的模块不算在内
      • 通过runtimeChunk拆分出来的runtime文件不算在内
      • 只算js,css不算在内
      • 如果同时有两个模块满足cacheGroups的拆分规则,但maxInitialRequests只允许再拆分一个,那么会拆出体积更大的那个模块。
    • maxAsyncRequests:用于限制异步模块内部的并行最大请求数

      • import文件本身算一个请求
      • 只算js、css不算在内
      • 如果同时有两个模块满足cacheGroups的规则需要拆分,但maxAsyncRequests只允许拆分一个时,那么会拆出体积更大的那个模块。
    • name:主要用于分离chunks后的名字,可以是字符串或者函数,相同name会合并成一个chunk

    • splitChunks.cacheGroups

      • 可以继承或者重写splitChunks对象下的属性,但是test、priority和reuseExistingChunk只能配置在cacheGroup对象中
      • 每个添加的对象都有默认配置,如果想禁用此配置,可以将其设置为false
  • 相关阅读:
    虹科分享 | MKA:基于先进车载网络安全解决方案的密钥协议
    深度神经网络的激活函数,神经网络模拟任意函数
    整理一些mysql常用的命令
    leetcode 90 子集II
    C语言实验四 循环结构程序设计(一)
    计算机毕业设计(42)java小程序毕设作品之小说电子书阅读小程序系统
    以clion为例记录一次基于docker环境配置开发
    HarmonyOS ArkUI实战开发-窗口模块(Window)
    JWT 登录
    git 恢复本地未提交的文件 local history
  • 原文地址:https://blog.csdn.net/weixin_43294560/article/details/126592522