Rollup Cheatsheet¶
Rollup - Next-generation ES Module Bundler
Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex, such as a library or application. It uses the new standardized format for code modules included in the ES6 revision of JavaScript.
Table of Contents¶
- Installation
- Basic Configuration
- Input Options
- Output Options
- Plugins
- External Dependencies
- Tree Shaking
- Code Splitting
- Watch Mode
- Development vs Production
- TypeScript Integration
- CSS and Assets
- Library Development
- Advanced Configuration
- Performance Optimization
- Troubleshooting
- Best Practices
Installation¶
Global Installation¶
Local Installation (Recommended)¶
# Initialize npm project
npm init -y
# Install Rollup locally
npm install --save-dev rollup
# Install common plugins
npm install --save-dev @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-babel
Package.json Scripts¶
{
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"build:prod": "NODE_ENV=production rollup -c"
}
}
Basic Configuration¶
Minimal rollup.config.js¶
Complete Basic Configuration¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
name: 'MyBundle',
sourcemap: true
},
plugins: [
resolve(),
commonjs(),
terser()
]
};
Multiple Configurations¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
const configs = [
// ES module build
{
input: 'src/main.js',
output: {
file: 'dist/bundle.esm.js',
format: 'es'
},
plugins: [resolve(), commonjs()]
},
// UMD build
{
input: 'src/main.js',
output: {
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyLibrary'
},
plugins: [resolve(), commonjs()]
}
];
export default configs;
Environment-based Configuration¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: !production
},
plugins: [
resolve(),
commonjs(),
production && terser()
]
};
Input Options¶
Single Entry Point¶
Multiple Entry Points¶
Dynamic Entry Points¶
import glob from 'glob';
const entries = glob.sync('src/pages/*.js').reduce((acc, path) => {
const entry = path.replace('src/pages/', '').replace('.js', '');
acc[entry] = path;
return acc;
}, {});
export default {
input: entries
};
Entry with External Dependencies¶
Output Options¶
Output Formats¶
// ES Module
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.esm.js',
format: 'es'
}
};
// CommonJS
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs'
}
};
// UMD (Universal Module Definition)
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyLibrary'
}
};
// IIFE (Immediately Invoked Function Expression)
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
name: 'MyApp'
}
};
// AMD (Asynchronous Module Definition)
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.amd.js',
format: 'amd'
}
};
// SystemJS
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.system.js',
format: 'system'
}
};
Multiple Output Formats¶
export default {
input: 'src/main.js',
output: [
{
file: 'dist/bundle.esm.js',
format: 'es'
},
{
file: 'dist/bundle.cjs.js',
format: 'cjs'
},
{
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyLibrary'
}
]
};
Output Directory¶
export default {
input: {
main: 'src/main.js',
admin: 'src/admin.js'
},
output: {
dir: 'dist',
format: 'es',
entryFileNames: '[name].js',
chunkFileNames: '[name]-[hash].js'
}
};
Source Maps¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: true, // Generate external source map
// sourcemap: 'inline', // Inline source map
// sourcemap: 'hidden' // Generate but don't reference
}
};
Plugins¶
Essential Plugins¶
# Install essential plugins
npm install --save-dev @rollup/plugin-node-resolve
npm install --save-dev @rollup/plugin-commonjs
npm install --save-dev @rollup/plugin-babel
npm install --save-dev @rollup/plugin-terser
Node Resolve Plugin¶
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
resolve({
browser: true, // Use browser field in package.json
preferBuiltins: false, // Don't prefer Node.js built-ins
extensions: ['.js', '.jsx', '.ts', '.tsx']
})
]
};
CommonJS Plugin¶
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
commonjs({
include: 'node_modules/**', // Convert CommonJS modules
exclude: ['node_modules/foo/**'], // Exclude specific modules
transformMixedEsModules: true // Handle mixed ES/CommonJS modules
})
]
};
Babel Plugin¶
import babel from '@rollup/plugin-babel';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
presets: [
['@babel/preset-env', {
targets: {
browsers: ['> 1%', 'last 2 versions']
}
}]
]
})
]
};
Terser Plugin (Minification)¶
import { terser } from 'rollup-plugin-terser';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
terser({
compress: {
drop_console: true, // Remove console.log
drop_debugger: true // Remove debugger statements
},
format: {
comments: false // Remove comments
}
})
]
};
Replace Plugin¶
import replace from '@rollup/plugin-replace';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
'__VERSION__': JSON.stringify(process.env.npm_package_version)
})
]
};
JSON Plugin¶
import json from '@rollup/plugin-json';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
json()
]
};
// Usage in code
import { version } from '../package.json';
console.log(version);
URL Plugin (Assets)¶
import url from '@rollup/plugin-url';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
url({
limit: 10 * 1024, // 10KB limit for inline
include: ['**/*.svg', '**/*.png', '**/*.jpg', '**/*.gif'],
emitFiles: true
})
]
};
External Dependencies¶
Basic External Configuration¶
export default {
input: 'src/main.js',
external: ['lodash', 'react', 'react-dom'],
output: {
file: 'dist/bundle.js',
format: 'umd',
globals: {
'lodash': '_',
'react': 'React',
'react-dom': 'ReactDOM'
}
}
};
Dynamic External Function¶
export default {
input: 'src/main.js',
external: (id) => {
// Mark all node_modules as external
return id.includes('node_modules');
},
output: {
file: 'dist/bundle.js',
format: 'es'
}
};
Peer Dependencies as External¶
import pkg from './package.json';
export default {
input: 'src/main.js',
external: Object.keys(pkg.peerDependencies || {}),
output: {
file: 'dist/bundle.js',
format: 'es'
}
};
Tree Shaking¶
Enabling Tree Shaking¶
// Rollup automatically tree-shakes ES modules
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'es'
}
};
Tree Shaking with Side Effects¶
// package.json
{
"sideEffects": false // No side effects, safe to tree-shake
}
// Or specify files with side effects
{
"sideEffects": [
"*.css",
"./src/polyfills.js"
]
}
Preserving Side Effects¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'es'
},
treeshake: {
moduleSideEffects: false, // Assume no side effects
// moduleSideEffects: (id) => id.includes('polyfill')
}
};
Tree Shaking Example¶
// utils.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export function multiply(a, b) {
console.log('This has a side effect!');
return a * b;
}
// main.js
import { add } from './utils.js'; // Only 'add' will be included
console.log(add(2, 3));
Code Splitting¶
Dynamic Imports¶
// main.js
async function loadModule() {
const module = await import('./heavy-module.js');
return module.default();
}
// Rollup config
export default {
input: 'src/main.js',
output: {
dir: 'dist',
format: 'es',
chunkFileNames: '[name]-[hash].js'
}
};
Manual Chunks¶
export default {
input: 'src/main.js',
output: {
dir: 'dist',
format: 'es',
manualChunks: {
vendor: ['lodash', 'react'],
utils: ['src/utils/helpers.js', 'src/utils/constants.js']
}
}
};
Dynamic Manual Chunks¶
export default {
input: 'src/main.js',
output: {
dir: 'dist',
format: 'es',
manualChunks: (id) => {
if (id.includes('node_modules')) {
return 'vendor';
}
if (id.includes('src/utils')) {
return 'utils';
}
}
}
};
Entry Point Splitting¶
export default {
input: {
main: 'src/main.js',
admin: 'src/admin.js',
vendor: 'src/vendor.js'
},
output: {
dir: 'dist',
format: 'es'
}
};
Watch Mode¶
Basic Watch Mode¶
Watch Configuration¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
watch: {
include: 'src/**',
exclude: 'node_modules/**',
clearScreen: false
}
};
Watch with Plugins¶
import livereload from 'rollup-plugin-livereload';
import serve from 'rollup-plugin-serve';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: !production
},
plugins: [
// ... other plugins
!production && serve({
open: true,
contentBase: 'dist',
port: 3000
}),
!production && livereload('dist')
]
};
Development vs Production¶
Environment-based Configuration¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
import replace from '@rollup/plugin-replace';
const production = process.env.NODE_ENV === 'production';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: !production
},
plugins: [
resolve(),
commonjs(),
replace({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
production && terser()
].filter(Boolean)
};
Separate Config Files¶
// rollup.config.dev.js
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: true
},
plugins: [
serve({
contentBase: 'dist',
port: 3000
}),
livereload('dist')
]
};
// rollup.config.prod.js
import { terser } from 'rollup-plugin-terser';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
terser()
]
};
Package.json Scripts¶
{
"scripts": {
"dev": "rollup -c rollup.config.dev.js -w",
"build": "NODE_ENV=production rollup -c rollup.config.prod.js"
}
}
TypeScript Integration¶
TypeScript Plugin¶
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/main.ts',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
typescript({
tsconfig: './tsconfig.json'
})
]
};
TypeScript Configuration¶
// tsconfig.json
{
"compilerOptions": {
"target": "es2018",
"module": "esnext",
"lib": ["dom", "dom.iterable", "es6"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
"declaration": true,
"outDir": "dist"
},
"include": [
"src"
]
}
TypeScript with Babel¶
import typescript from '@rollup/plugin-typescript';
import babel from '@rollup/plugin-babel';
export default {
input: 'src/main.ts',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
typescript(),
babel({
babelHelpers: 'bundled',
extensions: ['.js', '.ts']
})
]
};
CSS and Assets¶
PostCSS Plugin¶
import postcss from 'rollup-plugin-postcss';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
postcss({
extract: true, // Extract to separate CSS file
minimize: true, // Minify CSS
sourceMap: true
})
]
};
SCSS/Sass Support¶
import postcss from 'rollup-plugin-postcss';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
postcss({
extract: 'styles.css',
use: ['sass']
})
]
};
Asset Handling¶
import url from '@rollup/plugin-url';
import copy from 'rollup-plugin-copy';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
url({
limit: 10 * 1024, // 10KB
include: ['**/*.svg', '**/*.png', '**/*.jpg'],
emitFiles: true
}),
copy({
targets: [
{ src: 'src/assets/images/*', dest: 'dist/images' },
{ src: 'src/assets/fonts/*', dest: 'dist/fonts' }
]
})
]
};
Library Development¶
Library Configuration¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
import pkg from './package.json';
export default [
// ES module build
{
input: 'src/index.js',
external: Object.keys(pkg.peerDependencies || {}),
output: {
file: pkg.module,
format: 'es'
},
plugins: [
resolve(),
commonjs()
]
},
// CommonJS build
{
input: 'src/index.js',
external: Object.keys(pkg.peerDependencies || {}),
output: {
file: pkg.main,
format: 'cjs'
},
plugins: [
resolve(),
commonjs()
]
},
// UMD build
{
input: 'src/index.js',
output: {
file: pkg.browser,
format: 'umd',
name: 'MyLibrary',
globals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
},
plugins: [
resolve(),
commonjs(),
terser()
]
}
];
Package.json for Library¶
{
"name": "my-library",
"version": "1.0.0",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"browser": "dist/index.umd.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "rollup -c",
"prepublishOnly": "npm run build"
},
"peerDependencies": {
"react": "^17.0.0",
"react-dom": "^17.0.0"
}
}
TypeScript Library¶
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.esm.js',
format: 'es'
},
{
file: 'dist/index.cjs.js',
format: 'cjs'
}
],
plugins: [
typescript({
declaration: true,
declarationDir: 'dist'
}),
resolve(),
commonjs()
]
};
Advanced Configuration¶
Custom Plugin¶
function myPlugin() {
return {
name: 'my-plugin',
buildStart(opts) {
console.log('Build started');
},
transform(code, id) {
if (id.endsWith('.special')) {
return `export default ${JSON.stringify(code)}`;
}
},
generateBundle(opts, bundle) {
console.log('Bundle generated');
}
};
}
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
myPlugin()
]
};
Conditional Builds¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
const configs = [];
// Development build
if (process.env.NODE_ENV !== 'production') {
configs.push({
input: 'src/main.js',
output: {
file: 'dist/bundle.dev.js',
format: 'iife',
sourcemap: true
},
plugins: [resolve(), commonjs()]
});
}
// Production build
if (process.env.NODE_ENV === 'production') {
configs.push({
input: 'src/main.js',
output: {
file: 'dist/bundle.min.js',
format: 'iife'
},
plugins: [resolve(), commonjs(), terser()]
});
}
export default configs;
Multi-entry with Shared Dependencies¶
export default {
input: {
main: 'src/main.js',
admin: 'src/admin.js'
},
output: {
dir: 'dist',
format: 'es',
manualChunks: {
vendor: ['lodash', 'react'],
shared: ['src/utils/shared.js']
}
}
};
Performance Optimization¶
Bundle Analysis¶
# Install bundle analyzer
npm install --save-dev rollup-plugin-analyzer
# Use in config
import analyze from 'rollup-plugin-analyzer';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
analyze({
summaryOnly: true,
limit: 10
})
]
};
Optimize Dependencies¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
resolve({
preferBuiltins: false,
browser: true
}),
commonjs({
include: 'node_modules/**'
})
]
};
Minimize Bundle Size¶
import { terser } from 'rollup-plugin-terser';
import replace from '@rollup/plugin-replace';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production')
}),
terser({
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log', 'console.info']
}
})
]
};
Troubleshooting¶
Common Issues and Solutions¶
Circular Dependencies¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
onwarn: (warning, warn) => {
if (warning.code === 'CIRCULAR_DEPENDENCY') {
console.warn('Circular dependency:', warning.message);
return;
}
warn(warning);
}
};
External Dependencies Not Found¶
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
resolve({
browser: true,
preferBuiltins: false
})
]
};
CommonJS Module Issues¶
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
commonjs({
include: 'node_modules/**',
transformMixedEsModules: true
})
]
};
Memory Issues¶
Debug Configuration¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
onwarn: (warning, warn) => {
console.log('Warning:', warning);
warn(warning);
}
};
Best Practices¶
Configuration Organization¶
// rollup.config.js
import { createConfig } from './config/rollup.common.js';
const configs = [
createConfig('es'),
createConfig('cjs'),
createConfig('umd')
];
export default configs;
// config/rollup.common.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
export function createConfig(format) {
return {
input: 'src/index.js',
output: {
file: `dist/bundle.${format}.js`,
format
},
plugins: [
resolve(),
commonjs()
]
};
}
Performance Best Practices¶
- Use ES modules for better tree shaking
- Mark external dependencies to reduce bundle size
- Enable code splitting for large applications
- Use terser for production minification
- Analyze bundles to identify optimization opportunities
Development Best Practices¶
- Use watch mode for development
- Enable source maps for debugging
- Set up live reload for better DX
- Configure linting with ESLint
- Use TypeScript for better type safety
Library Development Best Practices¶
- Provide multiple formats (ES, CJS, UMD)
- Generate TypeScript declarations for TypeScript users
- Mark peer dependencies as external
- Use semantic versioning for releases
- Test builds before publishing
Summary¶
Rollup is a powerful module bundler that excels at creating optimized bundles for libraries and applications. Key features include:
- ES Module First: Native support for ES modules with excellent tree shaking
- Multiple Output Formats: Support for ES, CJS, UMD, IIFE, AMD, and SystemJS
- Plugin Ecosystem: Rich ecosystem of plugins for various transformations
- Code Splitting: Advanced code splitting capabilities
- Tree Shaking: Automatic dead code elimination
- TypeScript Support: First-class TypeScript integration
- Library Friendly: Excellent for building and distributing libraries
By leveraging Rollup's strengths and following best practices, you can create highly optimized bundles that are perfect for both library development and application building.