Introduction
Modern JavaScript apps often pull in large libraries and frameworks, but shipping every export—even those never used—bloats bundles and slows page loads. Tree shaking is a build‑time optimization that prunes “dead” exports (functions, classes, modules you never reference) from your final output. Rollup, built around ES modules’ static analysis, excels at precise dead‑code elimination. In this guide, you’ll learn:
- How tree shaking works under the hood in Rollup
- Project setup for optimal elimination of unused code
- Common pitfalls that prevent effective shaking
- Advanced techniques: manual chunks, code splitting, minification
- Integrating CSS pruning for a completely lean deliverable

Let’s transform your codebase into a razor‑sharp, high‑performance bundle.
1. How Tree Shaking Works in Rollup
1.1 ES Modules Enable Static Analysis
- Static Imports/Exports:
import {foo} from 'lib',export function bar() - No Side‑Effect Calls: Rollup can see exactly which exports are used; it doesn’t bundle the rest
- Dead Code Elimination: Unused exports never enter the dependency graph
1.2 Comparison to CommonJS
| Feature | CommonJS (require) | ES Modules (import) |
|---|---|---|
| Static Analysis | Limited (dynamic at runtime) | Fully static at build time |
| Tree Shaking | Poor—most require bundlers include everything | Excellent—Rollup prunes unused |
| File Format | module.exports | export, export default |
2. Setting Up Rollup for Tree Shaking
2.1 Initialize Your Project
bashCopyEditmkdir rollup-shake-demo
cd rollup-shake-demo
npm init -y
npm install rollup @rollup/plugin-node-resolve --save-dev
Directory structure:
pgsqlCopyEditrollup-shake-demo/
├── src/
│ ├── index.js
│ ├── utils.js
│ └── feature.js
└── rollup.config.js
2.2 Example Source with Unused Code
jsCopyEdit// src/utils.js
export function usedHelper() {
console.log('Used!');
}
export function unusedHelper() {
console.log('Unused!');
}
// src/feature.js
export function feature() {
console.log('Feature code');
}
// src/index.js
import { usedHelper } from './utils.js';
import { feature } from './feature.js';
usedHelper();
feature();
unusedHelper is never imported → candidate for removal.
2.3 Basic Rollup Configuration

jsCopyEdit// rollup.config.js
import { nodeResolve } from '@rollup/plugin-node-resolve';
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'es',
sourcemap: true
},
plugins: [
nodeResolve()
]
};
Run:
bashCopyEditnpx rollup -c
Inspect dist/bundle.js: only usedHelper and feature should appear.
3. Ensuring Effective Tree Shaking
3.1 Use ES Module Syntax Throughout
- Avoid
require()/module.exports - Prefer
import/export
3.2 Mark Side‑Effect‑Free Packages
In your package.json:
jsoncCopyEdit{
"sideEffects": false
}
For external CJS packages, configure Rollup’s CommonJS plugin:
jsCopyEditimport commonjs from '@rollup/plugin-commonjs';
plugins: [
commonjs({ include: 'node_modules/**', ignore: [] })
]
3.3 Avoid Re‑Exports of Everything
jsCopyEdit// bundle-utils.js — bad
export * from './utils.js';
Instead, explicitly import only needed exports in your entry:
jsCopyEditimport { usedHelper } from './utils.js';
4. Analyzing and Troubleshooting

4.1 Generate a Bundle Manifest
Add a plugin to dump bundle info:
jsCopyEdit// rollup.config.js additions
import fs from 'fs';
plugins: [
// ... other plugins ...
{
name: 'meta-dump',
generateBundle(options, bundle) {
fs.writeFileSync('dist/meta.json', JSON.stringify(bundle, null, 2));
}
}
]
Inspect dist/meta.json to see which modules remained.
4.2 Common Pitfalls
| Symptom | Cause | Remedy |
|---|---|---|
| Unused exports still in bundle | Using CommonJS or dynamic imports | Convert to ES modules; avoid require |
| Entire library included | Library not marked sideEffects: false | Add package.json flag or plugin config |
| Re‑exporting pulls in dead code | Using export * | Import only needed symbols |
5. Advanced Techniques
5.1 Code Splitting & Manual Chunks
jsCopyEdit// rollup.config.js
export default {
input: { main: 'src/index.js' },
output: {
dir: 'dist',
format: 'es',
manualChunks(id) {
if (id.includes('node_modules')) return 'vendor';
if (id.includes('src/feature.js')) return 'feature';
}
}
};
Loads vendor, feature, and main separately, and each is tree‑shaken individually.
5.2 Minification with Terser
bashCopyEditnpm install rollup-plugin-terser --save-dev
jsCopyEditimport { terser } from 'rollup-plugin-terser';
plugins: [
// ...other plugins...
terser({
module: true,
compress: {
passes: 2,
pure_getters: true
},
mangle: true
})
]
Minification removes unreachable code within used modules (dead branches).
5.3 CSS Dead‑Code Elimination

If using CSS imports in JS, combine Rollup with PurgeCSS or PostCSS:
bashCopyEditnpm install postcss rollup-plugin-postcss @fullhuman/postcss-purgecss --save-dev
jsCopyEditimport postcss from 'rollup-plugin-postcss';
import purgecss from '@fullhuman/postcss-purgecss';
plugins: [
postcss({
extract: true,
plugins: [
purgecss({
content: ['./src/**/*.js', './public/index.html']
})
]
})
]
Removes unused selectors, mirroring JS tree shaking.
6. Best Practices
- Always author libraries in ES modules to maximize static analysis.
- Set
"sideEffects": falsein package.json for your own code. - Explicitly import only what you need—avoid wildcard re‑exports.
- Analyze builds regularly with metafile dumps and bundle analyzer plugins.
- Combine tree shaking with minification for deep dead‑code removal.
- Split code logically into chunks for on‑demand loading.
Conclusion
Rollup’s tree shaking, powered by ES module static analysis, lets you ship only the code your application uses—trimming unused exports and dependencies from your bundles. By:
- Authoring with ES
import/export - Marking packages side‑effect‑free
- Avoiding CommonJS patterns and wildcard re‑exports
- Employing code splitting, minification, and CSS pruning
—you’ll deliver lightning‑fast, minimal payloads to your users. Integrate these strategies into your build pipeline today and watch your bundle sizes—and load times—plummet.























































































































































































































































































































































































































































































































































































































































































