Rollup
Rollup configuration for building JavaScript libraries with tree shaking and multiple output formats
You are an expert in Rollup for building JavaScript libraries with optimized tree shaking, multiple output formats, and plugin-based extensibility.
## Key Points
- Always externalize `dependencies` and `peerDependencies` for library builds so consumers do not get duplicate copies.
- Set `sideEffects: false` in package.json to enable downstream tree shaking of your library.
- Use the `exports` field in package.json to define conditional entry points for ESM and CJS consumers.
- Bundle type declarations with `rollup-plugin-dts` to produce a single `.d.ts` file rather than a mirrored directory structure.
- Use array config to define multiple builds (ESM, CJS, UMD, types) in a single `rollup.config.mjs`.
- Prefer `@rollup/plugin-node-resolve` over bundling node_modules into the output for libraries.
- **Forgetting to externalize dependencies**: If peer or regular dependencies are not listed in `external`, they get bundled into your output, causing duplication for consumers.
- **CJS default export issues**: When outputting CJS, use `exports: 'named'` or `exports: 'auto'` to control how default exports are handled. Mismatches cause `require('lib').default` confusion.
- **CommonJS interop**: Packages using CommonJS need `@rollup/plugin-commonjs`. Without it, named imports from CJS packages will fail.
- **Missing resolve plugin**: Without `@rollup/plugin-node-resolve`, Rollup cannot find packages in `node_modules` because it only resolves relative and absolute paths by default.
- **Circular dependencies**: Rollup warns about circular dependencies. While they sometimes work at runtime, they often cause initialization order bugs and should be refactored.
## Quick Example
```bash
npm install --save-dev rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs
npm install --save-dev @rollup/plugin-typescript rollup-plugin-dts
```skilldb get build-tools-skills/RollupFull skill: 182 linesRollup — Build Tools
You are an expert in Rollup for building JavaScript libraries with optimized tree shaking, multiple output formats, and plugin-based extensibility.
Core Philosophy
Overview
Rollup is a module bundler designed for JavaScript libraries. It produces clean, efficient output by leveraging ES module static analysis for tree shaking. Rollup excels at building packages that need to ship in multiple formats (ESM, CJS, UMD) and is the bundler used internally by Vite for production builds.
Setup & Configuration
Installation
npm install --save-dev rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs
npm install --save-dev @rollup/plugin-typescript rollup-plugin-dts
rollup.config.mjs
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import { readFileSync } from 'fs';
const pkg = JSON.parse(readFileSync('./package.json', 'utf-8'));
export default {
input: 'src/index.ts',
output: [
{
file: pkg.main,
format: 'cjs',
sourcemap: true,
exports: 'named',
},
{
file: pkg.module,
format: 'esm',
sourcemap: true,
},
],
external: [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
],
plugins: [
resolve(),
commonjs(),
typescript({ tsconfig: './tsconfig.json' }),
],
};
package.json Fields
{
"name": "my-lib",
"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"
}
},
"files": ["dist"],
"sideEffects": false
}
Core Patterns
Multiple Entry Points
export default {
input: {
index: 'src/index.ts',
utils: 'src/utils.ts',
hooks: 'src/hooks/index.ts',
},
output: {
dir: 'dist',
format: 'esm',
entryFileNames: '[name].js',
chunkFileNames: 'chunks/[name]-[hash].js',
sourcemap: true,
},
external: [/^react/],
plugins: [resolve(), commonjs(), typescript()],
};
Type Declaration Bundling
import dts from 'rollup-plugin-dts';
export default [
// Main build config (as above)
mainConfig,
// Declaration bundling
{
input: 'dist/types/index.d.ts',
output: { file: 'dist/index.d.ts', format: 'esm' },
plugins: [dts()],
},
];
UMD Build for CDN
{
input: 'src/index.ts',
output: {
file: 'dist/my-lib.umd.js',
format: 'umd',
name: 'MyLib',
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
sourcemap: true,
},
external: ['react', 'react-dom'],
plugins: [resolve(), commonjs(), typescript(), terser()],
}
Custom Plugin
function banner() {
return {
name: 'banner',
renderChunk(code) {
return `/* My Library v${pkg.version} | MIT License */\n${code}`;
},
};
}
Best Practices
- Always externalize
dependenciesandpeerDependenciesfor library builds so consumers do not get duplicate copies. - Set
sideEffects: falsein package.json to enable downstream tree shaking of your library. - Use the
exportsfield in package.json to define conditional entry points for ESM and CJS consumers. - Bundle type declarations with
rollup-plugin-dtsto produce a single.d.tsfile rather than a mirrored directory structure. - Use array config to define multiple builds (ESM, CJS, UMD, types) in a single
rollup.config.mjs. - Prefer
@rollup/plugin-node-resolveover bundling node_modules into the output for libraries.
Common Pitfalls
- Forgetting to externalize dependencies: If peer or regular dependencies are not listed in
external, they get bundled into your output, causing duplication for consumers. - CJS default export issues: When outputting CJS, use
exports: 'named'orexports: 'auto'to control how default exports are handled. Mismatches causerequire('lib').defaultconfusion. - CommonJS interop: Packages using CommonJS need
@rollup/plugin-commonjs. Without it, named imports from CJS packages will fail. - Missing resolve plugin: Without
@rollup/plugin-node-resolve, Rollup cannot find packages innode_modulesbecause it only resolves relative and absolute paths by default. - Circular dependencies: Rollup warns about circular dependencies. While they sometimes work at runtime, they often cause initialization order bugs and should be refactored.
Anti-Patterns
Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.
Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.
Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.
Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.
Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.
Install this skill directly: skilldb add build-tools-skills
Related Skills
Biome
Biome linter, formatter, and code analysis configuration for JavaScript and TypeScript projects
Esbuild
esbuild bundling, transpilation, and build scripting for ultra-fast JavaScript builds
Eslint Prettier
ESLint and Prettier combined setup for JavaScript and TypeScript linting and formatting
Swc
SWC compiler configuration for fast TypeScript and JavaScript transpilation and minification
Tsconfig
TypeScript compiler configuration, project references, and tsconfig best practices
Vite
Vite configuration, plugins, and dev server optimization for modern JavaScript projects