Rollup Complete Guide | ES Module Bundler
이 글의 핵심
Rollup is a module bundler for JavaScript that compiles ES modules into optimized bundles. It's the bundler of choice for libraries and powers Vite's production builds.
Introduction
Rollup is a module bundler for JavaScript that treats ES modules as first-class citizens. It’s designed for building libraries and produces highly optimized output.
Why Rollup?
Traditional bundlers include lots of runtime code:
// Webpack output (simplified)
(function(modules) {
var installedModules = {};
function __webpack_require__(moduleId) {
// ... runtime code
}
return __webpack_require__(0);
})([/* modules */]);
Rollup output is clean and minimal:
// Just your code, optimized
function add(a, b) {
return a + b;
}
export { add };
1. Installation
npm install --save-dev rollup
Basic config:
// rollup.config.js
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'es'
}
};
rollup -c
2. Output Formats
Rollup supports multiple module formats:
export default {
input: 'src/index.js',
output: [
// ES Module (modern)
{
file: 'dist/bundle.esm.js',
format: 'es'
},
// CommonJS (Node.js)
{
file: 'dist/bundle.cjs.js',
format: 'cjs'
},
// UMD (browser)
{
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyLibrary'
},
// IIFE (browser script tag)
{
file: 'dist/bundle.iife.js',
format: 'iife',
name: 'MyLibrary'
}
]
};
3. Tree Shaking
Rollup pioneered tree shaking - removing unused code:
// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export function multiply(a, b) {
return a * b;
}
// main.js
import { add } from './math.js';
console.log(add(1, 2));
Output (only used code):
function add(a, b) {
return a + b;
}
console.log(add(1, 2));
// subtract and multiply are removed!
4. Essential Plugins
@rollup/plugin-node-resolve
Resolves npm packages:
npm install --save-dev @rollup/plugin-node-resolve
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'es'
},
plugins: [resolve()]
};
@rollup/plugin-commonjs
Converts CommonJS to ES modules:
npm install --save-dev @rollup/plugin-commonjs
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
export default {
plugins: [
resolve(),
commonjs() // After resolve
]
};
@rollup/plugin-babel
Transpiles modern JavaScript:
npm install --save-dev @rollup/plugin-babel @babel/core @babel/preset-env
import babel from '@rollup/plugin-babel';
export default {
plugins: [
babel({
babelHelpers: 'bundled',
presets: ['@babel/preset-env']
})
]
};
@rollup/plugin-terser
Minifies output:
npm install --save-dev @rollup/plugin-terser
import terser from '@rollup/plugin-terser';
export default {
plugins: [
terser()
]
};
5. Building a Library
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
export default {
input: 'src/index.js',
output: [
{
file: 'dist/my-library.esm.js',
format: 'es',
sourcemap: true
},
{
file: 'dist/my-library.cjs.js',
format: 'cjs',
sourcemap: true
},
{
file: 'dist/my-library.min.js',
format: 'umd',
name: 'MyLibrary',
sourcemap: true,
plugins: [terser()]
}
],
plugins: [
resolve(),
commonjs(),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**'
})
],
external: ['react', 'react-dom'] // Don't bundle React
};
package.json:
{
"name": "my-library",
"main": "dist/my-library.cjs.js",
"module": "dist/my-library.esm.js",
"browser": "dist/my-library.min.js",
"files": ["dist"],
"scripts": {
"build": "rollup -c"
}
}
6. Code Splitting
export default {
input: {
main: 'src/main.js',
admin: 'src/admin.js'
},
output: {
dir: 'dist',
format: 'es'
}
};
Dynamic imports:
// main.js
async function loadModule() {
const module = await import('./heavy-module.js');
module.init();
}
7. TypeScript Support
npm install --save-dev @rollup/plugin-typescript typescript
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/index.ts',
output: {
file: 'dist/bundle.js',
format: 'es'
},
plugins: [
typescript()
]
};
8. React Library
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
export default {
input: 'src/index.jsx',
output: [
{
file: 'dist/index.js',
format: 'cjs',
sourcemap: true
},
{
file: 'dist/index.esm.js',
format: 'es',
sourcemap: true
}
],
plugins: [
peerDepsExternal(), // Externalize peer dependencies
resolve(),
babel({
babelHelpers: 'bundled',
presets: [
'@babel/preset-env',
['@babel/preset-react', { runtime: 'automatic' }]
],
exclude: 'node_modules/**'
}),
commonjs()
],
external: ['react', 'react-dom']
};
9. CSS and Assets
PostCSS
npm install --save-dev rollup-plugin-postcss
import postcss from 'rollup-plugin-postcss';
export default {
plugins: [
postcss({
extract: true,
minimize: true
})
]
};
Images
npm install --save-dev @rollup/plugin-image
import image from '@rollup/plugin-image';
export default {
plugins: [
image()
]
};
10. Development Workflow
npm install --save-dev rollup-plugin-serve rollup-plugin-livereload
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';
const dev = process.env.NODE_ENV !== 'production';
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: dev
},
plugins: [
// ... other plugins
dev && serve({
open: true,
contentBase: ['dist', 'public'],
port: 3000
}),
dev && livereload('dist')
].filter(Boolean)
};
{
"scripts": {
"dev": "rollup -c -w",
"build": "NODE_ENV=production rollup -c"
}
}
11. Advanced Configuration
Multiple Configs
// rollup.config.js
import dev from './rollup.config.dev.js';
import prod from './rollup.config.prod.js';
export default process.env.NODE_ENV === 'production' ? prod : dev;
Conditional Plugins
const production = !process.env.ROLLUP_WATCH;
export default {
plugins: [
resolve(),
commonjs(),
production && terser()
].filter(Boolean)
};
12. Optimizations
External Dependencies
export default {
external: [
'react',
'react-dom',
/^lodash/ // All lodash packages
]
};
Mangled Props (Advanced)
import terser from '@rollup/plugin-terser';
export default {
plugins: [
terser({
mangle: {
properties: {
regex: /^_/ // Mangle properties starting with _
}
}
})
]
};
13. Watch Mode
rollup -c -w
// rollup.config.js
export default {
watch: {
include: 'src/**',
exclude: 'node_modules/**',
clearScreen: false
}
};
14. Real-World Example
Complete library build:
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 peerDepsExternal from 'rollup-plugin-peer-deps-external';
import postcss from 'rollup-plugin-postcss';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/index.ts',
output: [
{
file: 'dist/index.js',
format: 'cjs',
sourcemap: true,
exports: 'named'
},
{
file: 'dist/index.esm.js',
format: 'es',
sourcemap: true,
exports: 'named'
},
{
file: 'dist/index.umd.js',
format: 'umd',
name: 'MyLib',
sourcemap: true,
exports: 'named',
globals: {
react: 'React',
'react-dom': 'ReactDOM'
}
}
],
plugins: [
peerDepsExternal(),
resolve({
extensions: ['.js', '.jsx', '.ts', '.tsx']
}),
commonjs(),
typescript({
tsconfig: './tsconfig.json',
declaration: true,
declarationDir: 'dist'
}),
postcss({
extract: 'styles.css',
minimize: production
}),
production && terser()
].filter(Boolean),
external: ['react', 'react-dom']
};
15. Performance Tips
1. Use Cache
Rollup caches by default in watch mode.
2. Parallelize Builds
npm install --save-dev npm-run-all
{
"scripts": {
"build:esm": "rollup -c rollup.config.esm.js",
"build:cjs": "rollup -c rollup.config.cjs.js",
"build": "npm-run-all --parallel build:*"
}
}
3. Minimize Plugin Work
plugins: [
resolve({
mainFields: ['module', 'main'],
extensions: ['.js'] // Only what you need
})
]
Summary
Rollup excels at building optimized libraries:
- Tree shaking pioneer
- Clean output with minimal runtime
- ES module first design
- Plugin ecosystem for everything
- Powers Vite production builds
Key Takeaways:
- Best for library builds
- Excellent tree shaking
- Multiple output formats
- Clean, readable output
- Plugin-based architecture
Next Steps:
Resources: