Rollup 번들러 설정 에러: 빌드 최적화 및 문제 해결
Rollup 번들러 설정 시 발생하는 에러와 빌드 최적화 방법을 설명합니다.
Rollup 번들러 설정 에러
Introduction
Rollup은 JavaScript 모듈 번들링을 위한 강력한 도구로, tree shaking과 ES 모듈 지원에 특화되어 있습니다. 라이브러리 개발 시 많이 사용되지만, 설정 과정에서 여러 에러에 직면할 수 있습니다. 이 글에서는 Rollup 설정 에러 해결 방법과 빌드 최적화 기법을 다루겠습니다.
Environment
// package.json
{
"name": "my-library",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs.js",
"types": "./dist/index.d.ts"
}
},
"scripts": {
"build": "rollup -c",
"watch": "rollup -c --watch"
},
"devDependencies": {
"rollup": "^4.9.0",
"@rollup/plugin-typescript": "^11.1.0",
"@rollup/plugin-node-resolve": "^15.2.0",
"@rollup/plugin-commonjs": "^25.0.0",
"@rollup/plugin-terser": "^0.4.0",
"tslib": "^2.6.0",
"typescript": "^5.3.0"
}
}npx rollup --version
# rollup v4.9.1Problem
Rollup 설정 시 발생하는 에러들:
// rollup.config.js
import typescript from '@rollup/plugin-typescript';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/index.ts',
output: {
file: 'dist/index.js',
format: 'cjs'
},
plugins: [
typescript(),
resolve(),
commonjs()
]
};
// 에러: Cannot use import statement outside a module
// TypeError: plugins.map is not a function# 빌드 실행 시 에러
npm run build
# 에러:
# [!] (plugin typescript) Error: tslib does not exist
# src/index.ts:1:0
# import { Button } from './Button';Analysis
Rollup 설정 에러의 원인을 분석했습니다:
// Rollup 설정 파일 구조
// rollup.config.js (ES 모듈 방식)
export default {
input: 'src/index.ts',
output: [
{
file: 'dist/index.cjs.js',
format: 'cjs',
sourcemap: true
},
{
file: 'dist/index.esm.js',
format: 'es',
sourcemap: true
}
],
plugins: [
resolve(),
commonjs(),
typescript()
]
};
// 플러그인 순서的重要性:
// 1. resolve(): node_modules에서 모듈 해결
// 2. commonjs(): CommonJS 모듈을 ES 모듈로 변환
// 3. typescript(): TypeScript 컴파일# TypeScript 컴파일 옵션 확인
cat tsconfig.json
# {
# "compilerOptions": {
# "target": "ES2020",
# "module": "ESNext",
# "declaration": true,
# "declarationDir": "./dist"
# }
# }Solution
1단계: 기본 설정 구성
// rollup.config.mjs (ES 모듈 확장자 사용)
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import terser from '@rollup/plugin-terser';
import { readFileSync } from 'fs';
const pkg = JSON.parse(readFileSync('./package.json', 'utf8'));
export default {
input: 'src/index.ts',
output: [
{
file: pkg.main,
format: 'cjs',
sourcemap: true,
exports: 'named'
},
{
file: pkg.module,
format: 'es',
sourcemap: true,
exports: 'named'
}
],
external: [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {})
],
plugins: [
resolve(),
commonjs(),
typescript({
tsconfig: './tsconfig.json',
declaration: true,
declarationDir: './dist/types'
}),
terser({
compress: {
drop_console: true
}
})
],
onwarn: (warning, warn) => {
if (warning.code === 'CircularDependency') {
return;
}
warn(warning);
}
};2단계: TypeScript 설정 최적화
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"declaration": true,
"declarationDir": "./dist/types",
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.stories.tsx"]
}3단계: 코드 분할 설정
// rollup.config.mjs (코드 분할)
export default {
input: {
index: 'src/index.ts',
utils: 'src/utils/index.ts',
hooks: 'src/hooks/index.ts'
},
output: [
{
dir: 'dist',
format: 'cjs',
entryFileNames: '[name].cjs.js',
chunkFileNames: 'chunks/[name]-[hash].js',
sourcemap: true
},
{
dir: 'dist',
format: 'es',
entryFileNames: '[name].esm.js',
chunkFileNames: 'chunks/[name]-[hash].js',
sourcemap: true
}
],
plugins: [
resolve(),
commonjs(),
typescript()
],
manualChunks: {
vendor: ['react', 'react-dom'],
utils: ['lodash', 'date-fns']
}
};4단계: 빌드 최적화
// rollup.config.mjs (최적화된 설정)
import copy from 'rollup-plugin-copy';
import postcss from 'rollup-plugin-postcss';
import image from '@rollup/plugin-image';
export default {
input: 'src/index.ts',
output: {
dir: 'dist',
format: 'es',
sourcemap: true,
preserveModules: true,
preserveModulesRoot: 'src'
},
plugins: [
resolve({
browser: true,
dedupe: ['react', 'react-dom']
}),
commonjs(),
typescript({
tsconfig: './tsconfig.build.json'
}),
postcss({
extract: 'styles.css',
minimize: true
}),
image(),
copy({
targets: [
{ src: 'src/assets/fonts', dest: 'dist' },
{ src: 'README.md', dest: 'dist' }
]
})
],
treeshake: {
moduleSideEffects: false,
propertyReadSideEffects: false,
tryCatchDeoptimization: false
}
};Lessons Learned
- 플러그인 순서: resolve, commonjs, typescript 순서로 플러그인을 정렬해야 합니다
- ESM 설정:
rollup.config.mjs파일을 사용하여 ES 모듈 문법을 지원해야 합니다 - external 설정: 외부 의존성을 명시하여 번들 크기를 줄여야 합니다
- tree shaking: treeshake 옵션을 최적화하여 불필요한 코드를 제거해야 합니다
- 다중 출력: CJS와 ESM 형식으로 동시에 출력하여 호환성을 확보해야 합니다
이 블로그는 외부 스폰서십, 제휴 마케팅 또는 광고 수익을 받지 않습니다.