Bundle libraries and apps with Rollup: plugins, tree-shaking, multi-format output, code splitting, and watch mode. Use when building distributable JS libraries.
Scanned 9/29/2026
npx -y skills add aicodedecode/awesome-muse-skills --skill rollup-pro --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Rollup Pro?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/aicodedecode-rollup-pro)More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.
---
name: rollup-pro
description: Bundle libraries and apps with Rollup: plugins, tree-shaking, multi-format output, code splitting, and watch mode. Use when building distributable JS libraries.
category: development
---
# Rollup Pro
A practical guide to Rollup: the bundler of choice for JavaScript libraries — plugin pipeline, tree-shaking, multi-format output (ESM/CJS), code splitting, and configs that produce clean, minimal distributables.
## Overview
Rollup pioneered ES-module-first bundling and tree-shaking: it understands `import`/`export` statically and drops unused code aggressively. That's why most JS libraries ship Rollup-built bundles. For apps, Vite uses Rollup under the hood for production builds — so Rollup knowledge transfers directly to Vite build tuning.
Core idea: **flat, scope-hoisted bundles with dead code eliminated**, in whatever module formats your consumers need.
## When to use
- Building publishable libraries (components, utilities, SDKs).
- Multi-format output: ESM for bundlers, CJS for Node, UMD/IIFE for script tags.
- Tree-shaking-sensitive packages (every byte ships to consumers).
- Custom Vite production build tuning (Vite exposes Rollup options).
## Core concepts
- **Plugins.** `resolveId`/`load`/`transform` hooks; the standard set: `@rollup/plugin-node-resolve` (bare imports), `@rollup/plugin-commonjs` (CJS deps), `@rollup/plugin-typescript` or `rollup-plugin-esbuild`/`swc` (transpile), `@rollup/plugin-terser` (minify), `@rollup/plugin-dts` (type bundles).
- **Input/output.** One or many inputs; output per format with `format: 'es' | 'cjs' | 'umd' | 'iife'`. `preserveModules` keeps file structure (better tree-shaking for consumers).
- **External.** Dependencies consumers provide (`peerDependencies` like react): mark `external` so they're imported, not bundled. `external: [/^react/]` patterns or auto via `rollup-plugin-peer-deps-external`.
- **Tree-shaking.** Works on ESM; `sideEffects: false` in package.json lets bundlers drop unused modules confidently. Mark genuinely side-effectful files (CSS imports, polyfills) explicitly.
- **Code splitting.** Multiple inputs or dynamic imports → shared chunks. `manualChunks` for control.
- **Watch mode.** `rollup -c -w` for library development with fast rebuilds.
## Practical workflow
**1. Config for a library.**
```js
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import esbuild from 'rollup-plugin-esbuild';
import dts from 'rollup-plugin-dts';
const external = ['react', 'react-dom', /^react\//];
export default [
{
input: 'src/index.ts',
external,
output: [
{ file: 'dist/index.js', format: 'cjs', sourcemap: true },
{ file: 'dist/index.mjs', format: 'es', sourcemap: true },
],
plugins: [resolve(), commonjs(), esbuild({ target: 'es2020' })],
},
{
input: 'src/index.ts',
external,
output: [{ file: 'dist/index.d.ts', format: 'es' }],
plugins: [dts()],
},
];
```
**2. package.json wiring.**
```json
{
"main": "./dist/index.js", "module": "./dist/index.mjs",
"types": "./dist/index.d.ts", "sideEffects": false,
"files": ["dist"]
}
```
**3. Verify the output.** Check: no bundled react (search dist), tree-shaking works (import one function → bundle has one function), `.d.ts` resolves, `attw --pack` (Are The Types Wrong) passes for types correctness.
**4. Dual-package care.** CJS + ESM from one source: avoid `__dirname`/`require` in ESM output; test both entry points in Node.
## Common pitfalls
- **Bundling peer deps.** Forgetting `external` for react/lodash → consumers get duplicate copies → hooks break, bundles bloat. Externalize all peerDependencies.
- **CJS interop.** `import x from 'cjs-lib'` may need `commonjs()` + named-export interop; default imports of CJS modules are a classic breakage. Test the built output, not just source.
- **`sideEffects: false` lies.** Marking false while a module does global setup (registers custom elements, patches prototypes) lets bundlers drop it. Be honest per-file: `"sideEffects": ["*.css", "./src/polyfills.js"]`.
- **Missing `.d.ts` bundling.** Shipping unbundled or broken types. Use the dts plugin and verify with `attw`.
- **UMD global name collisions.** For script-tag builds, pick a distinctive `output.name`; document it.
- **Watching node_modules.** Default watch can be slow/noisy — configure `watch.exclude`.
- **Circular imports.** Rollup warns; circular ESM often works but CJS output can break (temporal dead zone). Eliminate cycles rather than suppressing warnings.
- **Minifying libraries.** Usually don't minify library output — consumers' bundlers minify. Ship readable code + sourcemaps.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!