정의
여러 페이지가 공통으로 쓰는 외부 라이브러리(node_modules) 코드를 하나로 묶어 캐시하려다가, 오히려 모든 페이지가 거대한 공통 묶음을 통째로 내려받게 되는 함정을 피하고 싶을 때 알아야 할 개념이다.
용어를 먼저 풀면: 번들은 웹팩이 여러 파일을 합쳐 만든 하나의 JS 파일, **청크(chunk)**는 그 번들을 나눈 조각, vendor 청크는 외부 라이브러리만 모은 조각, First Load는 한 페이지를 처음 열 때 받아야 하는 JS 총량, dynamic import(import()·next/dynamic)는 "필요할 때 따로 내려받게" 코드를 나누는 기법이다.
구체적으로, optimization.splitChunks.cacheGroups(웹팩에서 어떤 모듈을 어떤 청크로 묶을지 정하는 설정)의 모든 것을 담는 vendor 그룹에 고정 name과 chunks: "all" 을 함께 주면, dynamic import로 애써 떼어낸 모듈까지 초기 공통 vendor 청크로 다시 끌려 들어가(hoist) 모든 페이지 First Load가 비대해진다. 즉, dynamic import만으로는 웹팩의 분할 정책을 못 이길 수 있다.
왜 필요한가
번들 최적화는 “라우트별로 무엇이 다른가”보다 먼저 모든 엔트리가 공유하는 청크를 의심해야 한다. First Load가 라우트마다 거의 같다면 shared vendor가 병목일 가능성이 높다. async cacheGroup(비동기 청크용 묶음 규칙)을 추가해도 해당 모듈이 여전히 static import 체인(페이지가 처음부터 import로 곧장 끌어오는 경로)에 남아 있으면 초기 그래프에서 빠지지 않는다.
동작 원리
- webpack은 모듈 그래프를 분석해 cacheGroup
test에 맞는 모듈을 청크로 묶는다. chunks: "all"이면 async 청크에 있는 모듈도 해당 그룹 후보가 된다.- 고정
name: "vendor"는 여러 엔트리·라우트 전용 의존성을 하나의 파일로 강제한다. next/dynamic등으로 컴포넌트를 lazy해도, 동일 모듈이 2곳 이상에서 참조되면 splitChunks가 shared로 끌어올릴 수 있다.- named async cacheGroup(
enforce: true)은 이미 초기 그래프에 있는 import를 빼지 못한다 — import 경로 자체를 async화해야 한다.
실무 적용
@next/bundle-analyzer또는 webpack-bundle-analyzer로 vendor 내부 모듈 목록을 본다. CLI의 “shared by all” 합계만으로는 부족한 경우가 많다.- catch-all vendor에
chunks: "initial", 고정name제거,maxSize적용. - 무거운 라이브러리(수식·애니메이션·캔버스 등)는 async cacheGroup + 사용 컴포넌트 dynamic import.
- cacheGroup
test정규식이 wrapper 패키지가 아닌 실제 번들에 들어간 패키지명을 가리키는지 확인한다. - 변경마다 재빌드·gzip 측정으로 효과를 검증한다.
트레이드오프
- vendor 분할을 늘리면 shared 청크 수·HTTP 요청이 늘 수 있다. HTTP/2·캐시 히트와 First Load 목표 사이에서 균형을 잡는다.
- 과도한 cacheGroup은 빌드 시간·디버깅 복잡도를 올린다. 이미 라우트 단위 lazy인 대형 청크는 추가 쪼개기 실익이 적을 수 있다.
- Turbopack·Rspack 등 번들러마다 기본 split 정책이 다르다 — webpack 커스텀 설정은 해당 번들러 문서와 대조한다.
사용하면 안 되는 경우
- 이미 First Load가 작고 라우트별로 크게 다른 경우 — shared vendor가 주원인이 아닐 수 있다.
- 측정 없이 cacheGroup만 복사·붙여넣기 — 환경·의존성 그래프가 다르면 역효과 가능.
- 모든 node_modules를 무조건 initial vendor에서 제외하려는 시도 — 런타임 청크 폭발·순환 참조 위험.
흔한 실수
- dynamic import 추가 후 “분리됐다”고 가정하고 analyzer를 다시 안 봄.
- async cacheGroup만 추가하고 상위에서 static import 유지.
lottie-react만 매칭하고 실제 무거운 core 패키지는 vendor에 남김.- 빌드 로그의
error문자열로 완료를 오탐(도구 경고 메시지 포함).
관련 개념
- resource-priority — 로드 우선순위·critical path
- lab-performance-measurement-variance — 번들·메트릭 측정 분산