Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bundler-example

JavaScript/TypeScript 번들러 및 빌드 도구 비교 학습 프로젝트. Bun 워크스페이스를 활용해 7개 도구를 동일한 소스 코드로 빌드하고 결과를 비교합니다.


이 도구들, 전부 "번들러"라고 불러도 될까?

결론부터 말하면 엄밀히는 아닙니다. 역할에 따라 두 가지 기준으로 나뉩니다.

분류 1 — 무엇을 직접 하는가 (번들러 vs 빌드 도구)

도구 분류 설명
webpack 번들러 모듈 번들링을 직접 수행
rollup 번들러 모듈 번들링을 직접 수행
esbuild 번들러 + 트랜스파일러 번들링과 TS 변환을 직접 수행
rolldown 번들러 모듈 번들링을 직접 수행 (Rust)
vite 빌드 도구 Vite 6: esbuild+rollup / Vite 8: rolldown+Oxc로 통합
tsup 빌드 도구 내부적으로 esbuild 사용
tsdown 빌드 도구 내부적으로 rolldown 사용

분류 2 — 무엇을 위한 도구인가 (앱 vs 라이브러리)

도구 용도 HMR 개발 서버
webpack 앱 빌드 ✅ (webpack-dev-server)
rollup 라이브러리 빌드
esbuild 라이브러리 빌드 ❌ (--serve 있지만 HMR 없음)
vite 앱 빌드
tsup 라이브러리 빌드
rolldown 라이브러리 빌드
tsdown 라이브러리 빌드

번들러(Bundler): 여러 JS/TS 모듈 파일을 분석해 하나(또는 소수)의 파일로 합치는 도구.

빌드 도구(Build tool): 번들러를 내부적으로 호출하면서 추가 작업(.d.ts 생성, 포맷 변환, clean 등)을 처리해주는 상위 도구.

일상적인 대화에서는 7개 모두를 묶어서 "번들러"라고 부르는 경우가 많고, 이 문서에서도 편의상 그렇게 표현합니다.


앱 빌드 도구 vs 라이브러리 빌드 도구

가장 중요한 구분입니다. 비교 표에서 tsdown이 ESM·CJS·.d.ts·sourcemap을 전부 지원한다고 해서 vite나 Next.js를 대체할 수 있는 게 아닙니다. 그 체크박스들은 전부 "npm 패키지를 어떤 형식으로 만들어내느냐" 에 관한 것이기 때문입니다.

기능 tsdown (라이브러리) vite (앱)
개발 서버 (localhost)
HMR
HTML 진입점 처리
CSS / 이미지 / 폰트 처리
React/Vue 컴포넌트 HMR ✅ (플러그인)
브라우저 코드 분할 (lazy loading)
환경변수 브라우저 주입 (.env)
ESM 출력
CJS 출력
.d.ts 생성 ✅ (플러그인)

tsdown은 브라우저가 없습니다. 입력은 .ts 파일이고 출력은 dist/index.js 파일입니다. 거기서 끝입니다. 반면 vite가 만들어내는 dist/는 브라우저에서 바로 열 수 있는 앱입니다.

비유: tsdown은 인쇄소 (원고 → 책), vite는 서점 + 인쇄소 (책도 찍고, 손님이 와서 바로 읽는 공간도 제공).

두 도구는 경쟁 관계가 아닙니다. React 앱 안에서 직접 만든 npm 라이브러리를 쓴다면, 라이브러리는 tsdown으로 빌드하고 앱은 vite로 개발하는 식으로 함께 씁니다.


HMR이란?

HMR(Hot Module Replacement) 은 개발 중 파일을 저장하면 페이지 전체를 새로고침하지 않고 변경된 모듈만 교체해주는 기능입니다. 상태(state)가 유지된 채로 코드 변경이 반영됩니다.

7개 도구 중 HMR을 지원하는 것은 webpack과 vite 둘뿐입니다. 나머지는 --watch 옵션이 있어도 그것은 단순히 파일 변경 시 dist/를 재생성하는 것이지, 브라우저와 연결되어 있지 않습니다.

webpack HMR vs vite HMR:

webpack HMR
  파일 변경 → 영향받는 모듈 전체 재번들링 → 브라우저에 전달
  (번들링 과정이 있어 느림)

vite HMR
  파일 변경 → 변경된 파일 하나만 esbuild로 변환 → 브라우저에 바로 전달
  (번들링 없이 네이티브 ESM으로 서빙하므로 빠름)

프로젝트 규모가 커질수록 webpack은 HMR도 느려지지만 vite는 거의 일정하게 빠릅니다. 이것이 vite가 webpack을 빠르게 대체한 핵심 이유입니다.


왜 번들러가 필요한가?

모던 JS/TS 개발에서 번들러가 필요한 이유는 크게 세 가지 문제에서 출발합니다.

1. 브라우저는 파일을 직접 읽지 못한다

코드를 파일로 분리해서 작성하면 import './math.ts' 같은 구문을 사용하게 됩니다. 그런데 브라우저는 보안상 로컬 파일 시스템에 직접 접근할 수 없고, 서버에서 파일을 받아올 때도 파일 하나마다 네트워크 요청 1번이 발생합니다.

파일 100개짜리 프로젝트 → 네트워크 요청 100번 → 페이지 로딩 느림

번들러는 이 수백 개의 파일을 빌드 시점에 하나(또는 소수)의 파일로 합쳐 요청 횟수를 줄입니다.

2. 브라우저와 Node.js는 TypeScript를 실행하지 못한다

브라우저와 Node.js의 런타임은 .ts 파일을 직접 실행할 수 없습니다. TypeScript 코드는 반드시 JavaScript로 변환(트랜스파일) 되어야 합니다.

번들러(또는 번들러에 통합된 트랜스파일러)가 빌드 시점에 이 변환을 담당합니다.

src/index.ts  →  번들러  →  dist/index.js  →  브라우저/Node.js 실행 가능

3. 라이브러리를 npm에 배포할 때 포맷을 맞춰야 한다

npm에 올린 패키지를 사용하는 환경은 다양합니다.

  • ESM (import) 환경 — 최신 번들러, 브라우저 native module
  • CJS (require) 환경 — 구형 Node.js, Jest 등

번들러 없이 TypeScript 소스를 그대로 배포하면 대부분의 환경에서 바로 사용할 수 없습니다. 번들러는 하나의 소스 코드에서 ESM · CJS 두 포맷을 동시에 생성해주고, .d.ts 타입 선언 파일도 함께 만들어줍니다.

추가 이점

기능 설명
Tree-shaking 사용하지 않는 코드를 번들에서 자동 제거해 파일 크기 감소
Minification 공백·주석 제거, 변수명 단축으로 파일 크기 추가 감소
환경 변수 인라인 process.env.NODE_ENV 같은 값을 빌드 시점에 치환
코드 분할(Code splitting) 앱을 여러 청크로 나눠 필요한 시점에만 로드

패키지 구성

출시 순서 기준으로 정렬되어 있습니다.

packages/
├── webpack-example/    번들러      (2012) — loader 시스템, 앱 번들의 시작
├── rollup-example/     번들러      (2015) — ES 모듈 중심, 정교한 tree-shaking
├── esbuild-example/    번들러      (2020) — Go 기반, 극속
├── vite-example/       빌드 도구   (2020) — 개발 서버 + 프로덕션 빌드 통합
├── tsup-example/       빌드 도구   (2021) — esbuild 기반, TS 라이브러리용
├── rolldown-example/   번들러      (2023) — Rust 기반, rollup 호환 후계자
└── tsdown-example/     빌드 도구   (2024) — rolldown 기반, tsup의 후계자

공통 소스 구조

모든 패키지는 동일한 src/ 파일을 사용합니다.

src/
├── math.ts     순수 함수 모음 (add, subtract, multiply, divide, factorial, calculate)
├── greet.ts    다국어 인사 함수 (greet, greetAll)
└── index.ts    re-export 진입점 — tree-shaking 비교용

비교 의도: 동일한 소스를 각 도구로 빌드해 출력 크기, 형식, .d.ts 생성 여부, 빌드 속도를 직접 비교합니다.


빠른 시작

bun install

# 전체 빌드
bun run build

# 개별 빌드 (출시 순서)
bun run build:webpack
bun run build:rollup
bun run build:esbuild
bun run build:vite
bun run build:tsup
bun run build:rolldown
bun run build:tsdown

번들러별 상세

1. webpack

번들러 | 2012 | 앱 빌드 | HMR ✅ | 독립 설계 | Loader 시스템

  • 공식 문서
  • 최초의 현대적 JS 번들러. CommonJS 모듈 시스템 기반으로 설계됨
  • Loader 시스템: 파일 형식별 변환 파이프라인 — TypeScript는 ts-loader 필요
  • Plugin 시스템: 번들 최적화, 코드 분할, HMR 등 앱 개발 전반을 담당
  • HMR: webpack-dev-server를 통해 지원. 변경 시 영향받는 모듈을 재번들링 후 교체
  • 번들에 webpack 자체 런타임 코드 포함 (자체 모듈 시스템 구현체)
  • rollup/rolldown과 완전히 독립적인 아키텍처

핵심 옵션:

// webpack.config.js (ESM — package.json에 "type": "module" 지정)
import path from 'path'
import { fileURLToPath } from 'url'

const __dirname = fileURLToPath(new URL('.', import.meta.url))

export default {
  entry: './src/index.ts',
  module: {
    rules: [
      { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/ },
    ],
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    library: { type: 'module' },
    clean: true,
  },
  experiments: { outputModule: true },
  mode: 'production',
}

특이사항:

  • 설정 파일 형식: "type": "module" + .js → ESM / "type" 없음 + .cjs → CJS 둘 다 가능
  • webpack 자체는 CJS 기반으로 설계됐지만, 설정 파일은 ESM으로 작성 가능 (공식 지원)
  • production 모드는 자동으로 minify + tree-shaking 적용
  • 단일 bundle.js 출력이 기본 — 라이브러리보다 앱 번들에 적합
  • 프로젝트가 커질수록 HMR 속도가 느려짐 → 이것이 vite 등장 배경

2. rollup

번들러 | 2015 | 라이브러리 빌드 | HMR ❌ | ES 모듈 중심

  • 공식 문서
  • ES 모듈 명세를 처음부터 고려해 설계된 번들러
  • tree-shaking이 가장 정교 — 정적 분석으로 사용하지 않는 export를 정밀하게 제거
  • TypeScript 지원은 @rollup/plugin-typescript 플러그인 필요
  • .d.ts 생성은 rollup-plugin-dts 플러그인 필요
  • 설정 파일은 .js/.mjs 권장 (.ts 설정 파일은 별도 플러그인 필요)
  • --watch는 있지만 개발 서버/HMR 없음 — 라이브러리 재빌드 용도

핵심 옵션:

// rollup.config.js
export default [
  {
    input: 'src/index.ts',
    output: [
      { file: 'dist/index.mjs', format: 'es' },
      { file: 'dist/index.cjs', format: 'cjs' },
    ],
    plugins: [typescript()],
  },
  // .d.ts 번들을 별도 패스로 생성
  {
    input: 'src/index.ts',
    output: { file: 'dist/index.d.ts', format: 'es' },
    plugins: [dts()],
  },
]

지원 출력 포맷: es · cjs · umd · iife · amd · system

특이사항:

  • TypeScript 처리를 직접 설정해야 하는 만큼, 번들러가 내부적으로 무슨 일을 하는지 가장 명확하게 배울 수 있음
  • 플러그인 생태계가 풍부하고, rolldown이 이 플러그인 API를 그대로 계승

3. esbuild

번들러 + 트랜스파일러 | 2020 | 라이브러리 빌드 | HMR ❌ | Go 기반 | 극속

  • 공식 문서
  • Go로 작성. 기존 번들러 대비 10~100배 빠른 빌드 속도
  • TypeScript 트랜스파일 내장 (타입 검사는 하지 않음)
  • .d.ts 생성 불가tsc --emitDeclarationOnly 별도 실행 필요
  • 설정 파일 개념 없음 → JS/TS API를 직접 호출하는 빌드 스크립트를 작성
  • --serve 옵션으로 파일 서빙은 가능하지만 HMR은 없음
  • CLI와 JS API 두 가지 방식 제공

핵심 옵션:

// build.ts
await esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  format: 'esm',      // 'esm' | 'cjs' | 'iife'
  outfile: 'dist/index.mjs',
  platform: 'node',   // 'browser' | 'node' | 'neutral'
  sourcemap: true,
  minify: true,
})

특이사항:

  • CJS 출력 시 __toESM, __toCommonJS 헬퍼가 자동 삽입되어 ESM보다 파일이 큼
  • 타입 검사가 없어 빌드는 빠르지만, 타입 오류가 런타임까지 넘어갈 수 있음
  • tsup의 내부 엔진으로 채택되어 실질적으로 영향력을 넓힘

4. vite

빌드 도구 | 2020 | 앱 빌드 | HMR ✅ | 개발 서버 + 프로덕션 빌드 통합

  • 공식 문서
  • 빠른 개발 서버(HMR)와 프로덕션 빌드를 하나의 도구로 제공
  • HMR: 변경된 파일 하나만 변환해서 브라우저에 전달 — 프로젝트 크기와 무관하게 빠름
  • Library Mode를 통해 npm 라이브러리 배포용 번들도 생성 가능
  • .d.ts 생성은 vite-plugin-dts 플러그인 필요

Vite 내부 아키텍처 변천 (중요):

Vite는 역사적으로 내부에서 두 개의 다른 도구를 동시에 사용해왔습니다.

Vite 1~6 (기존 구조) ─────────────────────────────────────────
  개발 서버 deps 사전 번들링  →  esbuild  (빠른 변환용)
  프로덕션 빌드              →  rollup   (최적화 번들링용)
  두 파이프라인의 동작 차이로 dev/prod 불일치 문제 발생

공식 문서 직접 인용:

"Vite originally relied on two separate tools: esbuild for fast compilation during development, and Rollup for thorough optimization in production builds. This worked, but maintaining two pipelines introduced inconsistencies: different transformation behaviors, separate plugin systems, and growing glue code to keep them aligned."

rolldown은 바로 이 문제를 해결하기 위해 만들어졌습니다.

Vite 7 (rolldown-vite 실험 패키지) / Vite 8 (정식 통합) ──────────
  개발 서버 deps 사전 번들링  →  rolldown      (esbuild 대체)
  프로덕션 빌드              →  rolldown      (rollup 대체)
  문법 변환 / JS 압축        →  Oxc           (esbuild 대체)
  CSS 압축                   →  Lightning CSS (esbuild 대체)
  단일 파이프라인 → dev/prod 동작 일치
  rollupOptions → rolldownOptions (Vite 8에서 rollupOptions deprecated)

현재(2025) 상태: Vite 8에서 rolldown이 정식 통합됨. Vite 7에서 rolldown-vite 별도 패키지로 실험 운용 후 Vite 8에 메인 병합. rollupOptions는 Vite 8에서 deprecated → rolldownOptions로 변경.

핵심 옵션 (Library Mode, Vite 8 기준):

// vite.config.ts
export default defineConfig({
  plugins: [dts({ include: ['src'] })],
  build: {
    lib: {
      entry: 'src/index.ts',
      formats: ['es', 'cjs'],
      fileName: (format) => format === 'es' ? 'index.js' : 'index.cjs',
    },
    // Vite 8: rolldownOptions (rolldown 정식 통합)
    // Vite 6 이하: rollupOptions
    rolldownOptions: {
      external: [],
    },
  },
})

특이사항:

  • webpack과의 핵심 차이: 개발 서버에서 번들링을 하지 않아 HMR이 훨씬 빠름
  • 내부적으로 rollup/rolldown을 쓰지만 추상화로 숨겨져 있어, 저수준 제어는 어려움
  • vite-plugin-dts가 생성한 .d.ts는 파일별로 분산됨 (tsup/tsdown처럼 단일 파일 번들 아님)
  • Vite 팀은 향후 개발 서버도 번들링하는 "Full Bundle Mode" 도입 예정 (dev/prod 완전 일치)

5. tsup

빌드 도구 | 2021 | 라이브러리 빌드 | HMR ❌ | esbuild 기반

  • 공식 문서
  • esbuild 위에서 동작하는 라이브러리 번들링 도구
  • esbuild가 해주지 않는 것들을 추가: .d.ts 생성, ESM+CJS 동시 출력, external 자동 감지
  • --watch는 파일 변경 시 dist/ 재생성만 함 — HMR·개발 서버 없음

tsup이 만들어진 이유: 2021년 당시 rolldown은 존재하지 않았고, esbuild는 너무 저수준이라 라이브러리 배포에 필요한 편의 기능이 없었습니다. tsup은 그 공백을 채우기 위해 만들어졌습니다.

⚠️ 주의: 공식 README에 "not actively maintained anymore" 명시. tsdown으로 이전 권장

핵심 옵션:

// tsup.config.ts
import { defineConfig } from 'tsup'

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,        // .d.ts 자동 생성
  clean: true,      // 빌드 전 dist/ 정리
  sourcemap: true,
})

특이사항:

  • tsdown과 설정 구조가 거의 동일 — 두 파일을 나란히 비교해보면 차이가 명확히 보임
  • 내부 엔진(esbuild vs rolldown)의 차이가 출력 결과와 속도에 영향을 줌

6. rolldown

번들러 | 2023 | 라이브러리 빌드 | HMR ❌ | Rust 기반 | rollup 호환 후계자

  • 공식 문서
  • VoidZero(Vite 팀)가 Rust로 개발한 차세대 번들러
  • rollup API 완전 호환 — 동일한 config 구조, 기존 rollup 플러그인 재사용 가능
  • TypeScript 내장 지원 (Oxc 기반) — @rollup/plugin-typescript 불필요
  • Vite 7+의 기반 번들러로 채택됨
  • .d.ts 생성은 미지원 → 라이브러리 번들링은 tsdown 사용 권장 (공식 문서 명시)
  • --watch는 있지만 개발 서버/HMR 없음

핵심 옵션:

// rolldown.config.ts
import { defineConfig } from 'rolldown'

export default defineConfig([
  {
    input: 'src/index.ts',
    output: { file: 'dist/index.mjs', format: 'esm' },
  },
  {
    input: 'src/index.ts',
    output: { file: 'dist/index.cjs', format: 'cjs' },
  },
])

특이사항:

  • 설정 구조는 rollup과 거의 동일하지만 빌드 속도는 압도적 (아래 속도 비교 참고)
  • esbuild와 속도가 비슷하면서 rollup의 플러그인 생태계 호환
  • rolldown은 엔진이고 tsdown은 그 엔진을 탑재한 완성차 — 직접 쓸 일은 많지 않음

7. tsdown

빌드 도구 | 2024 | 라이브러리 빌드 | HMR ❌ | rolldown 기반 | tsup의 공식 후계자

  • 공식 문서
  • VoidZero/Rolldown 팀이 만든 tsup의 공식 후계자
  • rolldown 기반 → Rust 성능 / Oxc 기반 .d.ts 생성 (tsup보다 빠름)
  • tsup과 설정 구조가 거의 동일 — .d.ts 생성, ESM+CJS 동시 출력, external 자동 감지
  • --watch는 파일 변경 시 dist/ 재생성만 함 — HMR·개발 서버 없음
  • Rolldown Vite의 Library Mode 기반이 될 예정

⚠️ 주의: Node.js 22.18.0+ 필요. Bun 지원은 experimental.

핵심 옵션:

// tsdown.config.ts
import { defineConfig } from 'tsdown'

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
  clean: true,
  sourcemap: true,
})

특이사항:

  • tsup과 설정이 거의 동일하지만 내부 엔진이 rolldown
  • 현재(v0.12.x) .d.ts 파일명에 해시가 포함됨 (index-NRoTx8IK.d.ts) — 버전에 따라 변경될 수 있음

빌드 결과 비교

이 표는 "npm 라이브러리 배포용 출력물" 기준의 비교입니다. HMR·개발 서버 등 앱 개발 기능과는 별개입니다.

출력 파일

도구 ESM CJS .d.ts sourcemap
webpack
rollup index.mjs index.cjs ✅ 단일 파일
esbuild index.mjs index.cjs
vite index.js index.cjs ✅ 파일별 분산
tsup index.js index.cjs ✅ 단일 파일
rolldown index.mjs index.cjs
tsdown index.js index.cjs ✅ 단일 파일

webpack은 단일 bundle.js 출력 (ESM/CJS 분리 없음, minified)

번들 크기 (byte)

도구 ESM CJS
webpack bundle.js 560 B (minified)
rollup 1,219 B 1,367 B
esbuild 898 B 2,101 B
vite 735 B 673 B
tsup 931 B 2,135 B
rolldown 1,038 B 1,244 B
tsdown 1,037 B 1,244 B

esbuild/tsup CJS가 유독 큰 이유: CJS 출력 시 __toESM, __toCommonJS interop 헬퍼를 자동 삽입합니다. rollup/rolldown 계열은 더 경량의 CJS 래퍼를 생성합니다.

vite가 작은 이유: Library Mode에서 rollup의 tree-shaking + minification이 기본 적용됩니다.

빌드 속도 (실측)

도구 빌드 시간 비고
esbuild ~즉시 Go 네이티브 바이너리
rolldown ~9 ms Rust 네이티브 바이너리
vite ~530 ms rollup 내부 사용 + dts
tsup ~650 ms esbuild + dts 생성
rollup ~1,000 ms JS 엔진, dts 포함
webpack ~1,000 ms JS 엔진
tsdown ~1,500 ms rolldown + Oxc dts 생성

도구 계층과 생태계 진화

              [앱 빌드 도구]                    [라이브러리 빌드 도구]
              HMR / 개발 서버 있음               HMR 없음 / npm 배포용

2012  webpack ────────────────────────────────────────────────────────
        (CommonJS 중심, 독자 아키텍처)

2015  rollup  ──────────────────────────────────── (라이브러리 번들러)
        (ES 모듈 중심)                                        │
                                                              ▼
2020  esbuild ────────────────────────────── tsup (2021, esbuild 래퍼)
        (Go, 극속)          ↗ dep 사전 번들링                 │ deprecated
           │                                                  ▼
2020  vite ─┤─────────────────────────────────── tsdown (2024, rolldown 래퍼)
        v1~6│  개발 서버: esbuild (변환) + 네이티브 ESM       ▲
            │  프로덕션:  rollup (번들링)                     │
            │  → 두 파이프라인 → dev/prod 불일치 문제         │
            │                                                  │
2023        └──────────── rolldown ────────────────────────────┘
              (Rust, rollup 호환)    Vite 7+에서 esbuild + rollup 둘 다 대체
                                     단일 파이프라인 → dev/prod 일치
                                     Oxc가 변환·압축 담당

언제 무엇을 쓸까

상황 추천 이유
React/Vue 앱 개발 vite HMR, 개발 서버, 플러그인 생태계
npm 라이브러리 배포 tsdown .d.ts, ESM+CJS, rolldown 성능
레거시 앱 (webpack 이미 사용 중) webpack 유지 마이그레이션 비용 > 이점
npm 라이브러리 (레거시) tsup tsdown 이전 전 유지보수
번들러 내부 동작 학습 esbuild 또는 rollup 저수준, 설정 직접 제어
Vite/rollup 플러그인 개발 rolldown 동일한 플러그인 API
번들러 없이 빠르게 실행 Bun (bun build) 별도 설정 불필요

참고 링크

도구 문서 저장소
webpack webpack.js.org webpack/webpack
rollup rollupjs.org rollup/rollup
esbuild esbuild.github.io evanw/esbuild
vite vite.dev vitejs/vite
tsup tsup.egoist.dev egoist/tsup
rolldown rolldown.rs rolldown/rolldown
tsdown tsdown.dev rolldown/tsdown

About

2026년 기준 번들러 사용 및 비교 예시

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages