Script Valley
Web Performance Fundamentals
JavaScript PerformanceLesson 4.3

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.json

Vite 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.

Up next

What causes long tasks on the main thread and how to fix them

Sign in to track progress