Tree Shaking in JavaScript Bundlers
Understanding how bundlers eliminate unused code automatically
Tree Shaking in JavaScript Bundlers
In this document, I want to explain what tree shaking is, how bundlers perform it automatically, and what developers need to consider to ensure unused code is eliminated.
1. What is Tree Shaking?
Tree shaking is the process of removing unused code (dead code) from a bundle. The term comes from the idea of “shaking a tree so that dead leaves fall off”.
Bundlers such as Webpack, Rollup, and Vite support tree shaking to optimize final build size. However, developers still need to follow certain practices for it to work effectively.
2. Automatic Tree Shaking by Bundlers
Bundlers analyze code to determine which exports are actually used. When using ES Modules (ESM, import/export
), unused functions, variables, and modules can be safely removed.
Example
// utils.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// main.js
import { add } from "./utils.js";
console.log(add(1, 2));
In this case, only add
is used. The subtract
function is excluded from the final bundle.
👉 This part happens automatically as long as ESM is used.
3. Developer Considerations
Tree shaking is not perfect by default. Developers must ensure conditions are met for bundlers to safely remove unused code.
1. Use ES Modules
- ✅ Use
import
/export
- ❌ Avoid
require()
(CommonJS) because it prevents static analysis
// Tree-shaking friendly
import { add } from "./utils.js";
// Not tree-shaking friendly
const utils = require("./utils.js");
2. Avoid Side Effects
If a module executes code just by being imported, bundlers cannot safely remove it.
// bad.js
console.log("loaded"); // Side effect when imported
Such modules are preserved in the bundle even if their exports are unused.
3. Declare sideEffects
in package.json
To help bundlers, projects can declare whether modules are free of side effects:
{
"sideEffects": false
}
This tells the bundler it can safely remove unused exports. If some files do have side effects, list them explicitly:
{
"sideEffects": ["./src/polyfills.js"]
}
4. Avoid Dynamic Import Patterns
When importing everything at once, bundlers cannot determine what is used.
// Not tree-shaking friendly
import * as utils from "./utils";
console.log(utils.add(1, 2));
Instead, import only what you need:
import { add } from "./utils";
console.log(add(1, 2));
4. Summary of Conditions
For effective tree shaking:
- Use ESM (
import/export
) instead of CommonJS - Ensure modules are side-effect free
- Declare
"sideEffects": false
inpackage.json
- Import only what you need, avoid wildcard imports