相关文章推荐
爱笑的热带鱼  ·  关于执行npm install ...·  1 周前    · 
高大的黑框眼镜  ·  npm ...·  1 周前    · 
坏坏的保温杯  ·  从根本上解决npm ...·  1 周前    · 
才高八斗的椅子  ·  ECharts ...·  1 周前    · 
酷酷的松鼠  ·  DataGridView拖动到TreeVie ...·  2 月前    · 
大鼻子的书包  ·  <tuple> 函式 | ...·  10 月前    · 

开箱即用的 SplitChunksPlugin 应该对大多数用户都很好用。

默认情况下,它只影响随需应变的块,因为更改初始块会影响运行项目时包含的应有脚本标记 HTML 文件。

webpack 将根据以下条件自动分割块:

  • 新块可被共享的,或者来自 node_modules 文件夹
  • 新块将大于 30kb (在 min+gz 之前)
  • 按需加载块时,并行请求的最大数量将小于或等于 5
  • 初始页面加载时并行请求的最大数量将小于或等于 3
  • 当试图满足后两个条件时,更大的块是首选。

    webpack为希望对该功能有更多控制的开发人员提供了一组选项。

    选择默认配置是为了适应 web 性能最佳实践,但是不同项目的最佳策略可能有所不同。如果您正在更改配置,您应该度量更改的影响,以确保有真正的好处。

    optimization.splitChunks

    下面这个对象表示 SplitChunksPlugin 的默认行为:

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          chunks: 'async',
          minSize: 30000,
          maxSize: 0,
          minChunks: 1,
          maxAsyncRequests: 5,
          maxInitialRequests: 3,
          automaticNameDelimiter: '~',
          name: true,
          cacheGroups: {
            vendors: {
              test: /[\\/]node_modules[\\/]/,
              priority: -10
            default: {
              minChunks: 2,
              priority: -20,
              reuseExistingChunk: true
    

    splitChunks.automaticNameDelimiter

    string

    默认情况下,webpack 将使用块的来源和名称生成名称(例如,vendors~main.js )。此选项允许您指定用于生成名称的分隔符。

    译者注:来源是指,这个块是来源于哪一个入口文件,如果是多入口公用,那么名字会加上这几个入口的名字:

    entry: {
        polyfill: './src/utils/polyfill.js',
        main: './src/main.js',
        app: './src/index.js',
    

    三个入口均引入了 vue 模块,最后打包的结果文件为 vendors~app~main~polyfill.8fe99da0cdc25ac2ef2f.bundle

    splitChunks.chunks

    function (chunk) | string

    该选项表示将选择哪些块进行优化。当提供一个字符串时,有效值为 allasyncinitialall 的 功能特别强大,因为它意味着即使在异步块和非异步块之间也可以共享块。

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          // 包含所有类型的块
          chunks: 'all'
    

    或者,您可以提供一个函数来进行更多的控制。返回值将指示是否包含每个块。

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          chunks (chunk) {
            // 排除 `my-excluded-chunk`
            return chunk.name !== 'my-excluded-chunk';
    

    您可以将此配置与 HtmlWebpackPlugin 组合使用。它将为您注入所有生成的 vendor块。

    splitChunks.maxAsyncRequests

    number

    按需加载时并行请求的最大数量。

    splitChunks.maxInitialRequests

    number

    入口点处并行请求的最大数量。

    splitChunks.minChunks

    number

    模块进行分割前必须共享的块的最小数量。

    splitChunks.minSize

    number

    生成块的最小大小(以字节为单位)。

    splitChunks.maxSize

    number

    使用 maxSize (全局:optimization.splitChunks.maxSize、每个缓存组:optimization.splitChunks.cacheGroups[x].maxSize、每个回退缓存组:optimization.splitChunks.fallbackCacheGroup.maxSize) 告诉 webpack 尝试将大于 maxSize 的块分割成更小的部分。分割出来的部分的尺寸至少为 minSize (仅次于 maxSize)。 该算法是确定性的,对模块的更改只会产生局部影响。因此,当使用长期缓存时,它是可用的,并且不需要记录。maxSize 只是一个提示,当拆分后模块大于 maxSize 或拆分会违反 minSize 时,可以不遵循 maxSize

    当块已经有名称时,每个部分将从该名称派生出一个新名称。取决于 optimization.splitChunks.hidePathInfo ,它将添加从第一个模块名或它的散列派生的键。

    maxSize 选项的目是用于 HTTP/2 和长期缓存。它增加了请求数,以便更好地缓存。它还可以用来减小文件大小,以便更快地重新构建。

    maxSizemaxInitialRequest/maxAsyncRequests 具有更高的优先级。实际优先级是 maxInitialRequest/maxAsyncRequests < maxSize < minSize

    splitChunks.name

    boolean: true | function (module, chunks, cacheGroupKey) | string

    分割块的名称。提供 true 将根据块和缓存组键自动生成名称。提供字符串或函数将允许您使用自定义名称。如果名称与入口点名称匹配,则将删除入口点。

    建议为生产构建将 splitChunks.name 设置为 false,这样就不会不必要地更改名称。

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          name (module, chunks, cacheGroupKey) {
            // generate a chunk name...
            return; //...
    

    当为不同的分割块分配相同的名称时,所有供应商模块都被放置到一个共享块中,但不建议这样做,因为这会导致下载更多的代码。

    splitChunks.cacheGroups

    缓存组可以继承和/或覆盖 splitChunks.* 中的任何选项。但是 testpriorityreuseExistingChunk 只能在缓存组级别配置。若要禁用任何默认缓存组,请将它们设置为 false

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          cacheGroups: {
            default: false
    

    splitChunks.cacheGroups.priority

    number

    一个模块可以属于多个缓存组。优化将优先选择具有较高 priority 的缓存组。默认组具有负优先级,以允许自定义组具有更高的优先级(自定义组的默认值为 0)。

    optimization: {
        splitChunks: {
          //...
          cacheGroups: {
            vendors1: {
              test: /[\\/]node_modules[\\/]/,
              priority: -10
            vendors2: {
              test: /[\\/]node_modules[\\/]/,
              priority: 1
    

    node_modules 的内容会被打包到的 vendors2 中

    splitChunks.cacheGroups.{cacheGroup}.reuseExistingChunk

    boolean

    如果当前块包含已经从主包中分离出来的模块,那么它将被重用,而不是生成一个新的模块。这可能会影响块的结果文件名。

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          cacheGroups: {
            vendors: {
              reuseExistingChunk: true
    

    splitChunks.cacheGroups.{cacheGroup}.test

    function (module, chunk) | RegExp | string

    控制此缓存组选择哪些模块。省略它将选择所有模块。它可以匹配绝对模块资源路径或块名称。当匹配块名称时,将对块中的所有模块进行选择。

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          cacheGroups: {
            vendors: {
              test(module, chunks) {
                //...
                return module.type === 'javascript/auto';
    

    splitChunks.cacheGroups.{cacheGroup}.filename

    string

    允许仅当块是初始块时重写文件名。 所有在 output.filename 可用的占位符在这里都是可用。

    可以在 splitChunks.filename 进行全局设置,但不建议这样做, 如果 splitChunks.chunks 未设置为 'initial',则可能导致错误。避免全局设置。

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          cacheGroups: {
            vendors: {
              filename: '[name].bundle.js'
    

    splitChunks.cacheGroups.{cacheGroup}.enforce

    boolean: false

    告诉 webpack 忽略 splitChunks.minSize, splitChunks.minChunks, splitChunks.maxAsyncRequestssplitChunks.maxInitialRequests 选项,并始终为这个缓存组创建块。

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          cacheGroups: {
            vendors: {
              enforce: true
    

    Defaults: 示例 1

    // index.js
    import('./a'); // 动态导入
    
    // a.js
    import 'react';
    //...
    

    Result: 将创建一个包含 react 的单独块。在导入调用时,这个块与包含 ./a 的原始块并行加载。

  • 条件 1: 块包含来自 node_modules 的模块
  • 条件 2: react 大于 30kb
  • 条件 3: 导入调用的并行请求数为 2
  • 条件 4: 在初始页面加载时不影响请求
  • 这背后的原因是什么?react 可能不会像应用程序代码那样频繁更改。通过将它移动到一个单独的块中,这个块可以与应用程序代码分开缓存(假设您使用的是 chunkhash、records、Cache-Control 或其他长期缓存方法)。

    Defaults: 示例 2

    // entry.js
    // 动态导入
    import('./a');
    import('./b');
    
    // a.js
    import './helpers'; // helpers is 40kb in size
    //...
    
    // b.js
    import './helpers';
    import './more-helpers'; // more-helpers is also 40kb in size
    //...
    

    Result: 将创建一个包含 ./helpers 及其所有依赖项的单独块。在导入调用时,这个块与原始块并行加载。

  • 条件 1: 这个块在两个导入调用之间共享
  • 条件 2: helpers 超过 30kb
  • 条件 3: 导入调用的并行请求数为 2
  • 条件 4: 在初始页面加载时不影响请求
  • helpers 的内容放入每个块中,将导致其代码被下载两次。通过使用单独的块,这种情况只会发生一次。我们支付额外请求的成本,这可以看作是一种权衡。这就是最小大小为 30kb 的原因。

    Split Chunks: 示例 1

    创建一个 commons 块,其中包括入口点之间共享的所有代码。

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          cacheGroups: {
            commons: {
              name: 'commons',
              chunks: 'initial',
              minChunks: 2
    

    此配置会扩大初始包,建议在不立即需要模块时使用动态导入。

    Split Chunks: 示例 2

    创建一个 vendors 块,其中包含整个应用程序中来自 node_modules 的所有代码。

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          cacheGroups: {
            commons: {
              test: /[\\/]node_modules[\\/]/,
              name: 'vendors',
              chunks: 'all'
    

    这可能导致生成一个包含所有外部包的大块。建议只包含核心框架和实用程序,并动态加载其余依赖项。

    Split Chunks: 示例 3

    创建一个自定义 vendor 块,其中包含与 RegExp 匹配的某些 node_modules 包。

    webpack.config.js

    module.exports = {
      //...
      optimization: {
        splitChunks: {
          cacheGroups: {
            vendor: {
              test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
              name: 'vendor',
              chunks: 'all',
    

    这将导致将 reactreact-dom 分割成单独的块。如果不确定块中包含了哪些包,可以参考 Bundle Analysis 部分了解详细信息。