Rollup — 라이브러리 번들러의 표준

Rollup이 라이브러리 배포에 최적화된 이유, ESM·CJS·UMD 다중 포맷 출력, Tree Shaking 원리, @rollup/plugin-typescript와 vite-plugin 생태계, package.json exports 필드까지 정리합니다.

· 5 min read · PALDYN Team

지난 글에서 webpack의 의존성 그래프와 코드 스플리팅을 살펴봤습니다. webpack이 웹 애플리케이션에 최적화된 반면, Rollup라이브러리 배포에 최적화된 번들러입니다. React, Vue, Svelte, D3 등 거의 모든 주요 라이브러리가 Rollup으로 빌드됩니다. Vite도 내부적으로 Rollup을 사용합니다.

Rollup이 선택받는 이유

  1. 깔끔한 출력물 — webpack처럼 복잡한 런타임 코드 없이, 작성한 코드와 거의 동일한 읽기 좋은 번들 생성
  2. 완전한 Tree Shaking — ES 정적 분석 기반으로 미사용 코드를 정확히 제거
  3. 다중 포맷 출력 — 하나의 소스에서 ESM, CJS, UMD, IIFE를 동시에 생성
  4. 작은 번들 크기 — 라이브러리 배포 시 peer dependency를 번들에서 제외하기 쉬움

설치와 기본 사용

npm install --save-dev rollup @rollup/plugin-typescript \
  @rollup/plugin-node-resolve @rollup/plugin-commonjs
npx rollup --config

다중 포맷 출력

Rollup 출력 포맷 비교

하나의 rollup.config.js로 여러 포맷을 동시에 빌드하는 것이 Rollup의 핵심 가치입니다.

// rollup.config.js
import typescript from '@rollup/plugin-typescript';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import terser from '@rollup/plugin-terser';
import dts from 'rollup-plugin-dts';

const pkg = JSON.parse(
  await import('fs').then(fs => fs.promises.readFile('./package.json', 'utf-8'))
);

// 모든 외부 의존성을 번들에서 제외
const external = [
  ...Object.keys(pkg.dependencies ?? {}),
  ...Object.keys(pkg.peerDependencies ?? {}),
];

export default [
  // 1. ESM + CJS 번들
  {
    input: 'src/index.ts',
    external,
    plugins: [resolve(), commonjs(), typescript({ tsconfig: './tsconfig.build.json' })],
    output: [
      { file: pkg.exports['.'].import, format: 'esm', sourcemap: true },
      { file: pkg.exports['.'].require, format: 'cjs', sourcemap: true, exports: 'named' },
    ],
  },
  // 2. UMD (CDN 배포용)
  {
    input: 'src/index.ts',
    plugins: [resolve(), commonjs(), typescript(), terser()],
    output: {
      file: 'dist/index.umd.min.js',
      format: 'umd',
      name: 'MyLibrary',       // 전역 변수 이름
      globals: { react: 'React' },
    },
  },
  // 3. 타입 선언 파일 (.d.ts)
  {
    input: 'src/index.ts',
    plugins: [dts()],
    output: { file: pkg.exports['.'].types, format: 'esm' },
  },
];

Tree Shaking 원리

Rollup Tree Shaking

Rollup의 Tree Shaking은 ES 모듈의 정적 구조에 기반합니다. import/export는 항상 파일 최상위에 정적으로 선언되기 때문에, 파싱 단계에서 실제로 사용되는 export를 추적할 수 있습니다.

// ❌ CommonJS — Tree Shaking 불가
const { add } = require('./utils'); // 런타임에 결정

// ✅ ESM — Tree Shaking 가능
import { add } from './utils';      // 정적 분석 가능

sideEffects 설정

라이브러리 배포 시 package.json에 사이드이펙트를 명시해야 최적화 도구들이 Tree Shaking을 안전하게 적용할 수 있습니다.

{
  "name": "my-library",
  "sideEffects": false
}

전역 CSS나 폴리필 파일처럼 import하면 사이드이펙트가 있는 경우:

{
  "sideEffects": ["**/*.css", "src/polyfills.js"]
}

package.json exports 필드

라이브러리를 올바르게 배포하려면 exports 필드를 사용해 환경별 진입점을 지정해야 합니다.

{
  "name": "my-library",
  "version": "1.0.0",
  "type": "module",
  "exports": {
    ".": {
      "import":  "./dist/index.mjs",
      "require": "./dist/index.cjs",
      "types":   "./dist/index.d.ts"
    },
    "./utils": {
      "import":  "./dist/utils.mjs",
      "require": "./dist/utils.cjs",
      "types":   "./dist/utils.d.ts"
    }
  },
  "main": "./dist/index.cjs",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts"
}

exports 필드가 있으면 mainmodule은 구형 번들러를 위한 폴백입니다. Node.js 12+와 모던 번들러는 exports를 우선합니다.

플러그인 생태계

# 핵심 플러그인
npm install --save-dev \
  @rollup/plugin-node-resolve \   # node_modules 해석
  @rollup/plugin-commonjs \       # CJS → ESM 변환
  @rollup/plugin-typescript \     # TS 변환
  @rollup/plugin-alias \          # 경로 별칭
  @rollup/plugin-replace \        # 텍스트 치환
  @rollup/plugin-terser \         # 최소화
  rollup-plugin-dts \             # .d.ts 번들
  rollup-plugin-peer-deps-external  # peerDeps 자동 external

커스텀 플러그인 작성

// 모든 export에 JSDoc 주석을 추가하는 플러그인 (예시)
function addJsDocPlugin() {
  return {
    name: 'add-jsdoc',
    renderChunk(code) {
      return { code: `/** @module my-library */\n${code}`, map: null };
    },
  };
}

Rollup 플러그인은 Vite 플러그인과 API 호환됩니다. Rollup 플러그인을 Vite에서 그대로 사용할 수 있는 경우가 많습니다.

webpack vs Rollup 선택 기준

시나리오선택
React/Vue 웹 애플리케이션webpack (또는 Vite)
npm 라이브러리 배포Rollup
UI 컴포넌트 라이브러리Rollup
Node.js CLI 도구esbuild 또는 Rollup
마이크로프론트엔드webpack (Module Federation)

지난 글: webpack — 모듈 번들러의 완전 정복

다음 글: Vite — 차세대 프론트엔드 빌드 도구


읽어주셔서 감사합니다. 😊