How to tree-shake unused JavaScript with ES modules
tree shaking definition, ES modules vs CommonJS, side effects, package.json sideEffects flag, named vs default exports, dead code elimination, Webpack/Rollup/Vite tree shaking
Tree Shaking
Tree shaking is dead code elimination based on static analysis of ES module imports. If you import only debounce from lodash-es, the bundler includes only that function — not the other 300+ utilities.
Tree shaking requires ES module syntax (import/export). CommonJS (require/module.exports) is dynamic and cannot be statically analyzed.
// ✗ NOT tree-shakeable — imports entire lodash (24KB+)
const _ = require('lodash');
_.debounce(fn, 300);
// ✓ Tree-shakeable — bundler includes only debounce
import { debounce } from 'lodash-es';
debounce(fn, 300);If a module has side effects (modifying globals, polyfills), mark them in package.json to prevent the bundler from removing them:
// package.json — mark specific files as having side effects
{
"sideEffects": [
"./src/polyfills.js",
"*.css"
]
}
// Or mark the entire package as pure (no side effects)
{
"sideEffects": false
}Check your bundle with a visualizer to see what made it in:
# Vite
npx vite build --mode production
npx vite-bundle-visualizer
# Webpack
npx webpack-bundle-analyzer stats.jsonVite and Rollup tree-shake aggressively by default. Webpack requires mode: 'production' and ES module imports. The most impactful tree-shaking wins come from switching icon libraries and utility libraries to ESM versions.
