번들 다이어트는 사용자가 내려받는 JavaScript 양을 측정하고 줄이는 작업이다. 같은 용량이라도 JS는 이미지보다 비싸다. 이미지는 다운로드와 디코딩만 하면 되지만, JS는 다운로드·파싱·컴파일·실행을 모두 거친다.
순서
- 먼저 잰다. Webpack Bundle Analyzer나 Next.js bundle analyzer로 어떤 라이브러리가 큰지 본다. 추측으로 시작하지 않는다(섣부른 최적화)
- 같은 라이브러리의 다른 버전이 중복 설치됐는지 본다. npm은 semver(Semantic Versioning)를 지킨다고 가정하고 호환되는 높은 버전 하나로 합칠 수 있는데, 그게
npm dedupe다. 패키지 매니저의 저장 방식은 npm과 pnpm 참고 - 무거운 라이브러리를 바꾼다. 용도가 겹치면 하나로 합치고, 작은 대안이나 네이티브 API(Application Programming Interface)로 대체한다. Bundlephobia에서 크기를 미리 확인할 수 있다
- 불필요한 폴리필(Polyfill)을 뺀다. 지원 브라우저를 기준으로 판단한다
- 라이브러리 영향을 페이지에 가둔다. 모든 페이지가 공유하는 공통 청크 하나에 넣으면 라이브러리를 하나 추가할 때마다 전 페이지가 무거워진다. 여러 청크로 나누고, 필요할 때만 받는 동적 임포트를 쓴다
배럴 파일을 거치지 않기
배럴 파일에서 하나만 import해도 배럴이 다시 내보내는 다른 모듈까지 불러오는 비용이 든다. 직접 경로로 import하거나, Next.js라면 experimental.optimizePackageImports에 패키지를 넣어 실제로 쓰는 모듈만 불러오게 한다(2026 기준 실험 옵션)
나중에 받을 청크를 미리 받기
webpack에서는 동적 임포트에 매직 코멘트(Magic Comments)를 달아 리소스 힌트를 낼 수 있다.
import(/* webpackPrefetch: true */ './LoginModal') // 다음 이동에서 쓸 듯한 청크
import(/* webpackPreload: true */ 'ChartingLibrary') // 지금 화면에서 곧 쓸 청크webpackPrefetch: 부모 청크를 다 받은 뒤<link rel="prefetch">를 붙인다. 브라우저는 한가할 때 받아 둔다webpackPreload:<link rel="preload">로 부모 청크와 병렬로 바로 받는다. 부모 청크가 곧바로 요청할 청크에 쓴다. 잘못 쓰면 오히려 성능을 해친다
라이브러리를 만드는 쪽이라면
- 트리 셰이킹이 되도록 ESM(ECMAScript Modules)으로 배포하고
sideEffects를 명시한다 - 번들러가 순수 함수 호출을 지울 수 있게
/*#__PURE__*/주석을 단다(Terser 등이 이용)
출처: 토스 SLASH 21 - JavaScript Bundle Diet · Next.js - optimizePackageImports · Vercel - How we optimized package imports in Next.js · webpack - Code Splitting: Prefetching/Preloading modules · webpack - Module Methods: Magic Comments