We’ve all done this:
- Install a huge library
- Use ONE function
- Ship 300KB of JavaScript
In modern web apps:
Shipping less code = faster apps
Two terms always come up here:
- Tree Shaking
- Dead Code Elimination (DCE)
They sound similar…
But they work in very different ways.
Let’s break it down with a real-world example so it actually sticks.
Table of Contents
- The Problem: Bloated Bundles
- Real-World Scenario: The Overloaded App
- Dead Code Elimination (DCE): The Surgeon
- Tree Shaking: The Gardener
- Why ES Modules Matter
- Key Differences
- How to Make Your Code Shakeable
- Mental Model
- Final Thoughts
The Problem: Bloated Bundles
Imagine your app loads slowly.
Users wait…
Bounce rate increases
You check your bundle:
500KB JavaScript
But your actual logic?
Maybe 50KB
So what happened?
Unused code is being shipped
Real-World Scenario: The Overloaded App
You’re building:
quickdash.com (a dashboard app)
You install a utility library:
import _ from "lodash";
`
But you only use:
js
_.debounce()
What gets shipped?
The ENTIRE library
Result
- Bigger bundle
- Slower load time
- Worse performance
This is where optimization kicks in.
Dead Code Elimination (DCE): The Surgeon
DCE is the classic optimization technique.
What it does
Removes code that will never run
Example
js
if (false) {
console.log("This will never run");
}
DCE removes it completely
Another Example
js
function unusedFunction() {
return 42;
}
If never called → removed
Analogy
A surgeon removing useless organs
Precise. Logical. Necessary.
What DCE Targets
- Unreachable code
- Unused variables
- Functions never called
It works at code level
Tree Shaking: The Gardener
Tree Shaking works differently.
What it does
Removes unused imports/modules
Example
js
import { debounce, throttle } from "lodash-es";
If you only use:
js
debounce()
throttle gets removed
Analogy
Shaking a tree so dead leaves fall off
Only what’s needed stays.
Key Idea
Include ONLY what you use
Works at module level
Why ES Modules Matter
Tree Shaking depends on:
ES6 modules (import/export)
Why?
Because they are:
Static (analyzable at build time)
CommonJS (bad for tree shaking)
js
const lib = require("lodash");
Dynamic → bundler can’t analyze usage
ES Modules (good)
js
import { debounce } from "lodash-es";
Bundler knows exactly what’s used
Key Differences
| Feature | Dead Code Elimination | Tree Shaking |
|---|---|---|
| Level | Code / function | Module / import |
| Removes | Unreachable code | Unused exports |
| Works with | Any JS | ES Modules only |
| Timing | After code analysis | During bundling |
How to Make Your Code Shakeable
Using a bundler isn’t enough.
You need to write shake-friendly code
1. Avoid Side Effects
Bad:
js
import "./init"; // modifies global state
Bundler won’t remove it
Good
Mark in package.json:
json
{
"sideEffects": false
}
2. Use Named Exports
Bad:
js
export default {
a,
b,
c
};
Good:
js
export const a = ...
export const b = ...
Bundler can pick only what’s needed
3. Import Only What You Need
Bad:
js
import _ from "lodash";
Good:
js
import { debounce } from "lodash-es";
Smaller bundle instantly
Real Impact
Without optimization:
- Large JS bundles
- Slow page load
- Poor mobile performance
With Tree Shaking + DCE:
- Smaller bundles
- Faster load times
- Better user experience
Mental Model
If you remember just this:
- DCE → Removes code that can’t run
- Tree Shaking → Removes code you didn’t import
DCE cleans inside your code
Tree Shaking trims your dependencies
Final Thoughts
Tree Shaking and DCE are invisible…
But powerful.
They:
- Reduce bundle size
- Improve performance
- Make apps faster
The fastest code is the code you never ship.
What About You?
Do you:
- Check your bundle size?
- Use tools like Webpack Analyzer?
- Optimize imports?
Let’s discuss in comment...
Top comments (0)