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
export default {
// ...
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, async 및 initial입니다. all을 제공하는 것은 비동기 청크와 동기 청크 간에도 청크를 공유할 수 있다는 것을 의미하기 때문에 특히 강력할 수 있습니다.
대체 캐시 그룹(splitChunks.fallbackCacheGroup.chunks)에도 적용됩니다.
webpack.config.js
export default {
// ...
optimization: {
splitChunks: {
// 모든 유형의 청크를 포함합니다.
chunks: "all",
},
},
};또는 더 많은 제어를 위한 기능을 제공할 수 있습니다. 반환 값은 각 청크를 포함할지 여부를 나타냅니다.
export default {
// ...
optimization: {
splitChunks: {
chunks(chunk) {
// `my-excluded-chunk`를 제외합니다.
return chunk.name !== "my-excluded-chunk";
},
},
},
};Webpack 버전 5.86.0 이상을 사용하는 경우 정규식을 전달할 수도 있습니다.
export default {
// ...
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 옵션은 webpack 5에서 도입되었으며, 분할 후 남는 청크의 최소 크기가 특정 제한 이상인지 확인하여 크기가 0인 모듈이 생성되는 것을 방지합니다.
splitChunks.minRemainingSize의 기본값은 mode에 따라 달라집니다.
| 모드 | 기본값 |
|---|---|
"production" | the value of splitChunks.minSize |
"development" | 0 |
"none" | the value of splitChunks.minSize |
It doesn't need to be specified manually except for the rare cases where deep control is required.
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)에 적용될 수 있습니다.
maxAsyncSize와 maxSize의 차이점은 maxAsyncSize가 on-demand 로딩 청크에만 영향을 미친다는 점입니다.
splitChunks.maxInitialSize
number
maxSize와 마찬가지로 maxInitialSize는 전역적으로(splitChunks.maxInitialSize) 캐시 그룹(splitChunks.cacheGroups.{cacheGroup}.maxInitialSize) 또는 대체 캐시 그룹(splitChunks.fallbackCacheGroup.maxInitialSize)에 적용될 수 있습니다.
maxInitialSize와 maxSize의 차이점은 maxInitialSize가 초기 로딩 청크 에만 영향을 미친다는 것입니다.
splitChunks.name
boolean = false function (module, chunks, cacheGroupKey) => string string
또한 splitChunks.cacheGroups.{cacheGroup}.name와 같이 각 캐시 그룹에 대해서도 사용 가능합니다.
이는 분할 청크의 이름입니다. false를 제공하면 청크의 이름이 동일하게 유지되므로 불필요하게 이름이 변경되지 않습니다. 프로덕션 빌드에 권장되는 값입니다.
문자열이나 함수를 제공하면 이름을 커스텀 할 수 있습니다. 항상 같은 문자열을 반환하는 문자열이나 함수를 지정하면 모든 공통 모듈과 vendor가 단일 청크로 병합됩니다. 이로 인해 초기 다운로드가 더 커지고 페이지 로드가 느려질 수 있습니다.
함수를 명시한 경우 청크의 이름을 선택하는 데 특히 유용한 chunk.name 속성(여기서 chunk는 chunks 배열의 요소)을 찾을 수 있습니다.
splitChunks.name이 엔트리 포인트이름과 일치하면 엔트리 포인트 청크 및 캐시 그룹이 단일 청크로 결합됩니다.
main.js
import _ from "lodash";
console.log(_.join(["Hello", "webpack"], " "));webpack.config.js
export default {
// ...
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, priority 및 reuseExistingChunk는 캐시 그룹 수준에서만 구성할 수 있습니다. 기본 캐시 그룹을 비활성화하려면 false로 설정하세요.
webpack.config.js
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
default: false,
},
},
},
};splitChunks.cacheGroups.{cacheGroup}.priority
number = -20
모듈은 여러 캐시 그룹에 속할 수 있습니다. 최적화는 priority(우선순위)가 더 높은 캐시 그룹을 선호합니다. 기본 그룹은 커스텀 그룹이 더 높은 우선순위를 가질 수 있도록 음수 우선순위를 갖습니다(커스텀 그룹일 경우 기본값은 0입니다).
splitChunks.cacheGroups.{cacheGroup}.reuseExistingChunk
boolean = true
현재 청크에 이미 기본 번들에서 분리된 모듈이 포함되어 있으면 새로 생성되는 대신 재사용됩니다. 이것은 청크의 파일 이름에 영향을 줄 수 있습니다.
webpack.config.js
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
reuseExistingChunk: true,
},
},
},
},
};splitChunks.cacheGroups.{cacheGroup}.type
function RegExp string
모듈 유형별로 캐시 그룹에 모듈을 할당할 수 있습니다.
webpack.config.js
export default {
// ...
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
import path from "node:path";
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
svgGroup: {
test(module) {
// `module.resource`는 디스크에 있는 파일의 절대 경로를 포함합니다.
// 플랫폼 간 호환성을 위해 / 또는 \ 대신 `path.sep`을 사용합니다.
return (
module.resource &&
module.resource.endsWith(".svg") &&
module.resource.includes(`${path.sep}cacheable_svgs${path.sep}`)
);
},
},
byModuleTypeGroup: {
test(module) {
return module.type === "javascript/auto";
},
},
},
},
},
};module 및 chunks 객체에서 어떤 정보를 사용할 수 있는지 확인하려면 콜백에 debugger; 문을 넣으면 됩니다. 그런 다음 디버그 모드에서 webpack 빌드를 실행하여 Chromium DevTools의 파라미터를 검사합니다.
아래는 {cacheGroup}.test에 RegExp를 제공한 경우입니다.
webpack.config.js
export default {
// ...
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
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
filename: "[name].bundle.js",
},
},
},
},
};아래는 함수로 사용하는 방법입니다.
webpack.config.js
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
filename: (pathData) =>
// 요구 사항에 따라 파일 이름 문자열을 생성하기 위해 pathData 객체를 사용하세요.
`${pathData.chunk.name}-bundle.js`,
},
},
},
},
};파일 이름 앞에 경로를 제공하여 폴더 구조를 생성할 수 있습니다(예: 'js/vendor/bundle.js').
webpack.config.js
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
filename: "js/[name]/bundle.js",
},
},
},
},
};splitChunks.cacheGroups.{cacheGroup}.enforce
boolean = false
Webpack에 splitChunks.minSize, splitChunks.minChunks, splitChunks.maxAsyncRequests 및 splitChunks.maxInitialRequests 옵션을 무시하고 항상 이 캐시 그룹에 대한 청크를 생성하도록 지시합니다.
webpack.config.js
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
enforce: true,
},
},
},
},
};splitChunks.cacheGroups.{cacheGroup}.idHint
string
청크 ID에 대한 힌트를 설정합니다. 청크의 파일 이름에 추가됩니다.
webpack.config.js
export default {
// ...
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
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: "commons",
chunks: "initial",
minChunks: 2,
},
},
},
},
};Split Chunks: Example 2
전체 애플리케이션에서 node_modules의 모든 코드를 포함하는 vendors 청크를 만듭니다.
webpack.config.js
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all",
},
},
},
},
};Split Chunks: Example 3
RegExp와 일치하는 특정 node_modules 패키지를 포함하는 custom vendor 청크를 만듭니다.
webpack.config.js
export default {
// ...
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: "vendor",
chunks: "all",
},
},
},
},
};


