SplitChunksPlugin

원래 청크(및 그 안에 가져온 모듈)는 webpack 내부 그래프에서 부모-자식 관계로 연결되었습니다. CommonsChunkPlugin은 중복되는 의존성을 피하고자 사용되었지만, 추가 최적화는 불가능했습니다.

webpack v4부터 optimization.splitChunks를 위해 CommonsChunkPlugin은 제거되었습니다.

Defaults

즉시 사용 가능한 SplitChunksPlugin은 대부분의 사용자에게 잘 작동합니다.

초기 청크를 변경하면 HTML 파일이 프로젝트를 실행하기 위해 포함해야 하는 스크립트 태그에 영향을 미치기 때문에 기본적으로 on-demand 청크에만 영향을 미칩니다.

Webpack은 다음 조건에 따라 자동으로 청크를 분할합니다.

  • 새 청크를 공유 할 수 있거나 모듈이 node_modules 폴더에 있는 경우
  • 새 청크가 20kb보다 클 경우(min+gz 이전에)
  • 요청 시 청크를 로드할 때 최대 병렬 요청 수가 30개 이하일 경우
  • 초기 페이지 로드 시 최대 병렬 요청 수가 30개 이하일 경우

마지막 두 가지 조건을 충족하려고 할 때 더 큰 청크가 선호됩니다.

Configuration

Webpack은 이 기능에 대한 더 많은 제어를 원하는 개발자를 위해 옵션 세트를 제공합니다.

optimization.splitChunks

이 설정 객체는 SplitChunksPlugin의 기본 동작을 나타냅니다.

webpack.config.js

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,
        },
      },
    },
  },
};

splitChunks.automaticNameDelimiter

string = '~'

기본적으로 webpack은 출처와 청크 이름을 사용하여 이름을 생성합니다(예: vendors~main.js). 이 옵션을 사용하면 생성된 이름에 사용할 구분 기호를 지정할 수 있습니다.

splitChunks.chunks

string = 'async' function (chunk) RegExp

이것은 최적화를 위해 선택될 청크를 나타냅니다. 문자열이 제공될 때 유효한 값은 all, asyncinitial입니다. all을 제공하는 것은 비동기 청크와 동기 청크 간에도 청크를 공유할 수 있다는 것을 의미하기 때문에 특히 강력할 수 있습니다.

대체 캐시 그룹(splitChunks.fallbackCacheGroup.chunks)에도 적용됩니다.

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      // 모든 유형의 청크를 포함합니다.
      chunks: 'all',
    },
  },
};

또는 더 많은 제어를 위한 기능을 제공할 수 있습니다. 반환 값은 각 청크를 포함할지 여부를 나타냅니다.

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks(chunk) {
        // `my-excluded-chunk`를 제외합니다.
        return chunk.name !== 'my-excluded-chunk';
      },
    },
  },
};

Webpack 버전 5.86.0 이상을 사용하는 경우 정규식을 전달할 수도 있습니다.

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: /foo/,
    },
  },
};

splitChunks.maxAsyncRequests

number = 30

on-demand 로드 시의 최대 병렬 요청 수입니다.

splitChunks.maxInitialRequests

number = 30

엔트리 포인트의 최대 병렬 요청 수입니다.

splitChunks.defaultSizeTypes

[string] = ['javascript', 'unknown']

크기에 숫자를 사용할 때 적용되는 크기 유형을 설정합니다.

splitChunks.minChunks

number = 1

모듈이 분할 전에 청크 간에 공유되어야 하는 최소 개수입니다.

splitChunks.hidePathInfo

boolean

maxSize로 분할된 부분의 이름을 만들 때 경로 정보가 노출되지 않도록 합니다.

splitChunks.minSize

number = 20000 { [index: string]: number }

생성할 청크의 최소 byte 크기입니다.

splitChunks.minSizeReduction

number { [index: string]: number }

청크를 생성하는 데 필요한 기본 청크(번들)의 바이트 단위의 줄어들 최소 크기입니다. 즉, 청크로 분할해도 기본 청크(번들)의 크기가 주어진 바이트만큼 줄어들지 않으면 splitChunks.minSize 값을 충족하더라도 분할되지 않습니다.

splitChunks.enforceSizeThreshold

splitChunks.cacheGroups.{cacheGroup}.enforceSizeThreshold

number = 50000

분할이 적용되고 기타 제한(minRemainingSize, maxAsyncRequests, maxInitialRequests)이 무시되는 임계 크기 값입니다.

splitChunks.minRemainingSize

splitChunks.cacheGroups.{cacheGroup}.minRemainingSize

number = 0

splitChunks.minRemainingSize 옵션은 분할 후 남아있는 청크의 최소 크기가 제한을 초과하도록 하여 크기가 0인 모듈을 방지하기 위해 webpack 5에 도입되었습니다. 'development' 모드에서 기본값은 0입니다. 다른 경우 splitChunks.minRemainingSize는 기본적으로 splitChunks.minSize 값으로 설정되므로 심층 제어가 필요한 드문 경우를 제외하고는 수동으로 지정할 필요가 없습니다.

splitChunks.layer

splitChunks.cacheGroups.{cacheGroup}.layer

RegExp string function

모듈 계층별로 캐시 그룹에 모듈을 할당합니다.

splitChunks.maxSize

number = 0

maxSize를 사용하면(캐시 그룹 optimization.splitChunks.cacheGroups[x].maxSize당 전역적으로 optimization.splitChunks.maxSize 또는 대체 캐시 그룹 optimization.splitChunks.fallbackCacheGroup.maxSize의 경우) webpack이 maxSize byte보다 큰 청크를 더 작은 부분으로 분할하도록 합니다. 분할된 크기는 최소 minSize(maxSize 다음)입니다. 알고리즘은 결정론적이며 모듈 변경은 로컬에만 영향을 미칩니다. 따라서 장기 캐싱을 사용할 때 사용할 수 있으며 기록이 필요하지 않습니다. maxSize는 힌트일 뿐이며 모듈이 maxSize 보다 크거나 분할이 minSize를 벗어날 때 위반될 수 있습니다.

청크에 이미 이름이 있는 경우 각 부분은 해당 이름에서 파생된 새 이름을 얻습니다. optimization.splitChunks.hidePathInfo의 값에 따라 첫 번째 모듈 이름이나 해시에서 파생된 키를 추가합니다.

maxSize 옵션은 HTTP/2 및 장기 캐싱과 함께 사용하기 위한 것입니다. 더 나은 캐싱을 위해 요청수가 증가합니다. 빠른 재구축을 위해 파일 크기를 줄이는 데도 사용할 수 있습니다.

splitChunks.maxAsyncSize

number

maxSize와 마찬가지로 maxAsyncSize는 전역적으로(splitChunks.maxAsyncSize) 캐시 그룹(splitChunks.cacheGroups.{cacheGroup}.maxAsyncSize) 또는 대체 캐시 그룹(splitChunks.fallbackCacheGroup.maxAsyncSize)에 적용될 수 있습니다.

maxAsyncSizemaxSize의 차이점은 maxAsyncSize가 on-demand 로딩 청크에만 영향을 미친다는 점입니다.

splitChunks.maxInitialSize

number

maxSize와 마찬가지로 maxInitialSize는 전역적으로(splitChunks.maxInitialSize) 캐시 그룹(splitChunks.cacheGroups.{cacheGroup}.maxInitialSize) 또는 대체 캐시 그룹(splitChunks.fallbackCacheGroup.maxInitialSize)에 적용될 수 있습니다.

maxInitialSizemaxSize의 차이점은 maxInitialSize가 초기 로딩 청크 에만 영향을 미친다는 것입니다.

splitChunks.name

boolean = false function (module, chunks, cacheGroupKey) => string string

또한 splitChunks.cacheGroups.{cacheGroup}.name와 같이 각 캐시 그룹에 대해서도 사용 가능합니다.

이는 분할 청크의 이름입니다. false를 제공하면 청크의 이름이 동일하게 유지되므로 불필요하게 이름이 변경되지 않습니다. 프로덕션 빌드에 권장되는 값입니다.

문자열이나 함수를 제공하면 이름을 커스텀 할 수 있습니다. 항상 같은 문자열을 반환하는 문자열이나 함수를 지정하면 모든 공통 모듈과 vendor가 단일 청크로 병합됩니다. 이로 인해 초기 다운로드가 더 커지고 페이지 로드가 느려질 수 있습니다.

함수를 명시한 경우 청크의 이름을 선택하는 데 특히 유용한 chunk.name 속성(여기서 chunkchunks 배열의 요소)을 찾을 수 있습니다.

splitChunks.name엔트리 포인트와 일치하면 엔트리 포인트가 제거됩니다.

main.js

import _ from 'lodash';

console.log(_.join(['Hello', 'webpack'], ' '));

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          // 여기서 cacheGroupKey는 cacheGroup의 키로 `commons`입니다.
          name(module, chunks, cacheGroupKey) {
            const moduleFileName = module
              .identifier()
              .split('/')
              .reduceRight((item) => item);
            const allChunksNames = chunks.map((item) => item.name).join('~');
            return `${cacheGroupKey}-${allChunksNames}-${moduleFileName}`;
          },
          chunks: 'all',
        },
      },
    },
  },
};

splitChunks 구성으로 webpack을 실행하면 다음의 이름으로 공통 그룹 청크도 출력됩니다. commons-main-lodash.js.e7519d2bb8777058fa27.js(해시는 실제 출력의 예로 제공됩니다).

splitChunks.usedExports

splitChunks.cacheGroups{cacheGroup}.usedExports

boolean = true

모듈이 export 할 파일의 이름을 수정(mangle)하고 사용하지 않는 export를 생략하고 보다 효율적인 코드를 생성하기 위해 어떤 export를 사용하는지 알아봅니다. true인 경우 각 런타임에 대해 사용된 export를 분석하고, "global"인 경우 결합한 모든 런타임에 대해 전역적으로 export를 분석합니다.

splitChunks.cacheGroups

캐시 그룹은 splitChunks.*의 모든 옵션을 상속 및(또는) 재정의할 수 있습니다. 그러나 test, priorityreuseExistingChunk는 캐시 그룹 수준에서만 구성할 수 있습니다. 기본 캐시 그룹을 비활성화하려면 false로 설정하세요.

webpack.config.js

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

splitChunks.cacheGroups.{cacheGroup}.priority

number = -20

모듈은 여러 캐시 그룹에 속할 수 있습니다. 최적화는 priority(우선순위)가 더 높은 캐시 그룹을 선호합니다. 기본 그룹은 커스텀 그룹이 더 높은 우선순위를 가질 수 있도록 음수 우선순위를 갖습니다(커스텀 그룹일 경우 기본값은 0입니다).

splitChunks.cacheGroups.{cacheGroup}.reuseExistingChunk

boolean = true

현재 청크에 이미 기본 번들에서 분리된 모듈이 포함되어 있으면 새로 생성되는 대신 재사용됩니다. 이것은 청크의 파일 이름에 영향을 줄 수 있습니다.

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        defaultVendors: {
          reuseExistingChunk: true,
        },
      },
    },
  },
};

splitChunks.cacheGroups.{cacheGroup}.type

function RegExp string

모듈 유형별로 캐시 그룹에 모듈을 할당할 수 있습니다.

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        json: {
          type: 'json',
        },
      },
    },
  },
};

splitChunks.cacheGroups.test

splitChunks.cacheGroups.{cacheGroup}.test

function (module, { chunkGraph, moduleGraph }) => boolean RegExp string

캐시 그룹에 의해 선택되는 모듈을 제어합니다. 생략하면 모든 모듈이 선택됩니다. 이는 절대 경로 모듈 리소스 또는 청크 이름과 일치할 수 있습니다. 청크 이름이 일치하면 청크의 모든 모듈이 선택됩니다.

아래와 같이 {cacheGroup}.test에 기능을 제공합니다.

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        svgGroup: {
          test(module) {
            // `module.resource`는 디스크에 있는 파일의 절대 경로를 포함합니다.
            // 플랫폼 간 호환성을 위해 / 또는 \ 대신 `path.sep`을 사용합니다.
            const path = require('path');
            return (
              module.resource &&
              module.resource.endsWith('.svg') &&
              module.resource.includes(`${path.sep}cacheable_svgs${path.sep}`)
            );
          },
        },
        byModuleTypeGroup: {
          test(module) {
            return module.type === 'javascript/auto';
          },
        },
      },
    },
  },
};

modulechunks 객체에서 어떤 정보를 사용할 수 있는지 확인하려면 콜백에 debugger; 문을 넣으면 됩니다. 그런 다음 디버그 모드에서 webpack 빌드를 실행하여 Chromium DevTools의 파라미터를 검사합니다.

아래는 {cacheGroup}.testRegExp를 제공한 경우입니다.

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        defaultVendors: {
          // 플랫폼 간 호환성을 위한 경로 구분 기호로 `[\\/]`의 사용에 유의하세요.
          test: /[\\/]node_modules[\\/]|vendor[\\/]analytics_provider|vendor[\\/]other_lib/,
        },
      },
    },
  },
};

splitChunks.cacheGroups.{cacheGroup}.filename

string function (pathData, assetInfo) => string

초기 청크인 경우에만 파일 이름을 재정의할 수 있습니다. output.filename에서 사용할 수 있는 모든 플레이스홀더는 여기에서도 사용할 수 있습니다.

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        defaultVendors: {
          filename: '[name].bundle.js',
        },
      },
    },
  },
};

아래는 함수로 사용하는 방법입니다.

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        defaultVendors: {
          filename: (pathData) => {
            // 요구 사항에 따라 파일 이름 문자열을 생성하기 위해 pathData 객체를 사용하세요.
            return `${pathData.chunk.name}-bundle.js`;
          },
        },
      },
    },
  },
};

파일 이름 앞에 경로를 제공하여 폴더 구조를 생성할 수 있습니다(예: 'js/vendor/bundle.js').

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        defaultVendors: {
          filename: 'js/[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: {
        defaultVendors: {
          enforce: true,
        },
      },
    },
  },
};

splitChunks.cacheGroups.{cacheGroup}.idHint

string

청크 ID에 대한 힌트를 설정합니다. 청크의 파일 이름에 추가됩니다.

webpack.config.js

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        defaultVendors: {
          idHint: 'vendors',
        },
      },
    },
  },
};

Examples

Defaults: Example 1

// index.js

import('./a'); // 동적 import
// a.js
import 'react';

//...

결과: react를 포함하는 별도의 청크가 생성됩니다. import 호출에서 이 청크는 ./a를 포함하는 원래 청크와 병렬로 로드됩니다.

이유:

  • 조건 1: 청크는 node_modules의 모듈을 포함합니다
  • 조건 2: react가 30kb보다 큽니다
  • 조건 3: import 호출 시 병렬 요청 수는 2입니다
  • 조건 4: 초기 페이지 로드 시 요청에 영향을 주지 않습니다

이 이유는 무엇일까요? react는 애플리케이션 코드만큼 자주 변경되지 않을 것입니다. 별도의 청크로 이동하면 이 청크를 앱 코드와 별도로 캐시할 수 있습니다(청크 해시, 레코드, Cache-Control 또는 장기 캐시 접근 방식을 사용한다고 가정합니다).

Defaults: Example 2

// entry.js

// 동적 imports
import('./a');
import('./b');
// a.js
import './helpers'; // helpers의 크기는 40kb입니다

//...
// b.js
import './helpers';
import './more-helpers'; // more-helpers 또한 40kb의 크기를 가집니다

//...

결과: ./helpers와 이에 대한 모든 의존성을 포함하는 별도의 청크가 생성됩니다. import 호출에서 이 청크는 원래 청크와 병렬로 로드됩니다.

이유:

  • 조건 1: 청크는 두 import 호출 간에 공유됩니다
  • 조건 2: helpers는 30kb보다 큽니다
  • 조건 3: import 호출 시 병렬 요청 수는 2입니다
  • 조건 4: 초기 페이지 로드 시 요청에 영향을 주지 않습니다

helpers의 내용을 각 청크에 넣으면 코드가 두 번 다운로드됩니다. 별도의 청크를 사용하면 한 번만 발생합니다. 우리는 추가 요청 비용을 지불하며 이는 절충안으로 간주할 수 있습니다. 그렇기 때문에 최소 크기는 30kb입니다.

Split Chunks: Example 1

엔트리 포인트 간에 공유되는 모든 코드를 포함하는 commons 청크를 만듭니다.

webpack.config.js

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

Split Chunks: Example 2

전체 애플리케이션에서 node_modules의 모든 코드를 포함하는 vendors 청크를 만듭니다.

webpack.config.js

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

Split Chunks: Example 3

RegExp와 일치하는 특정 node_modules 패키지를 포함하는 custom vendor 청크를 만듭니다.

webpack.config.js

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

17 Contributors

sokrajeremenichelliPriestchchrisdothtmlEugeneHlushkobyzykjacobangelmadhavarshneysakhisheikhsuperburritoryandrew14snitin315chenxsanrohrlafjamesgeorge007anshumanvsnitin315

Translators