Pre-bundling은 Vite가 개발 서버 시작 시 node_modules의 의존성을 사전에 번들링하는 전략이다. esbuild를 사용하여 수행되며, 자동으로 투명하게 동작한다.

해당 개념이 필요한 이유

두 가지 핵심 문제를 해결한다:

1. CommonJS/UMD → ESM 변환

Vite의 개발 서버는 Native ESM으로 코드를 제공하므로, CommonJS나 UMD로 작성된 의존성을 ESM으로 변환해야 한다.

// React는 CommonJS로 배포됨
// Pre-bundling이 이것을 ESM으로 변환해줌
import React, { useState } from 'react';  // ← 이 문법이 동작하도록

2. HTTP 요청 수 최적화

lodash-es의 경우:
import { debounce } from 'lodash-es';

내부적으로 lodash-es는 600개 이상의 개별 모듈로 구성됨

Pre-bundling 없이: 600+ HTTP 요청 발생 → 브라우저 네트워크 정체
Pre-bundling 후:   1개 HTTP 요청      → 즉시 로드

AS-IS (Pre-bundling 없이)

import { debounce } from 'lodash-es';

브라우저:
GET lodash-es/debounce.js
  → GET lodash-es/isObject.js
    → GET lodash-es/isSymbol.js
      → GET lodash-es/...
        → ... (600+ 요청이 폭포처럼 발생)

→ 네트워크 탭이 수백 개의 요청으로 가득 참

TO-BE (Pre-bundling 후)

import { debounce } from 'lodash-es';

Vite가 사전에:
[600+ 개별 모듈] → esbuild → [단일 ESM 파일]

브라우저:
GET /node_modules/.vite/deps/lodash-es.js?v=abc123
→ 단 1개 요청으로 완료

동작 방식

자동 발견

  1. Vite가 소스 코드를 크롤링하여 bare import 감지 (예: import xx from 'react')
  2. 이 import들을 pre-bundling 진입점으로 사용
  3. esbuild로 빠르게 번들링
  4. 서버 시작 후 새로운 의존성 발견 시 → 재번들링 + 리로드

캐싱 전략

파일 시스템 캐시 (node_modules/.vite):

  • 다음 조건이 변경될 때만 재실행:
    • lockfile (package-lock.json 등) 변경
    • vite.config.js 관련 필드 변경
    • NODE_ENV 값 변경

브라우저 캐시:

  • max-age=31536000,immutable 헤더로 강력 캐싱
  • 패키지 버전이 변경되면 자동 무효화

강제 재번들링

vite --force          # CLI 플래그
# 또는
rm -rf node_modules/.vite  # 캐시 디렉토리 삭제

커스터마이징

// vite.config.js
export default {
  optimizeDeps: {
    include: ['large-cjs-package'],  // 강제로 pre-bundling에 포함
    exclude: ['tiny-esm-package'],   // pre-bundling에서 제외
  }
}
  • include: 내부 모듈이 많은 패키지나 CommonJS 패키지를 명시적으로 포함
  • exclude: 작고 유효한 ESM 패키지를 제외하여 브라우저가 직접 로드하게 함

Pre-bundling은 개발 모드에서만 동작한다. 프로덕션 빌드에서는 @rollup/plugin-commonjs가 같은 역할을 수행한다.

참고 문서