Suggest an editImprove this articleRefine the answer for “Tree shaking”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Tree shaking is the removal of unused code from the final JavaScript bundle.** The bundler (Webpack, Rollup, Vite, Parcel) statically analyses the `import` / `export` graph, sees which exports are never used, and drops them, which is dead code elimination. It only works on ES Modules: a CommonJS `require()` cannot be analysed statically, and a module with side effects will not be dropped unless `package.json` declares `"sideEffects": false`. **Key point:** a smaller bundle means not just a faster download but faster parsing and execution too.Shown above the full answer for quick recall.Answer (EN)Image**Tree shaking is the process of removing unused code from the final JavaScript bundle.** The name literally means shaking a tree: picture your project's code as a tree whose dead branches (functions, modules, imports) simply fall off during the build. Less code means a faster download and better performance. ## Theory ### TL;DR - If a function, variable or import is used nowhere, the bundler (Webpack, Rollup, Vite) deletes that code from the output file. - It rests on ES Modules: `import` / `export` are static, so they can be analysed at build time. - CommonJS (`require`) does not support tree shaking. - Side effects block the removal of a module until `package.json` declares `"sideEffects": false`. - Rollup, Vite and esbuild do it out of the box; Webpack turns it on in production mode. ### Quick example ```javascript // utils.js export function add(a, b) { return a + b; } export function sub(a, b) { return a - b; } export function mul(a, b) { return a * b; } export function div(a, b) { return a / b; } // main.js import { add } from './utils.js'; console.log(add(2, 3)); ``` Without tree shaking the bundler puts every function (`add`, `sub`, `mul`, `div`) into `bundle.js`, even though only `add()` is actually used. With tree shaking enabled (Webpack production mode, Rollup or Vite) only `add()` survives in the final bundle. The result is a smaller bundle, a faster download, and faster parsing and execution too. ### How it works technically Tree shaking rests on three things: 1. **ES Modules (ESM)**, that is `import` / `export`: unlike `require`, ESM imports are static and can be analysed at build time; 2. **static dependency analysis**: the bundler knows exactly which exports are really used; 3. **dead code elimination**, the optimization that strips what is left unreferenced. ```javascript // the import is static, so the bundler sees that only add is used import { add } from './utils.js'; ``` CommonJS, on the other hand, does not support tree shaking: ```javascript const utils = require('./utils'); // the bundler cannot know for sure what is used ``` ### When tree shaking will not work Tree shaking does not work if: - you use CommonJS (`require`) instead of ES Modules (`import` / `export`); - the code has side effects, for example it runs something on import; - the library did not declare `"sideEffects": false` in its `package.json`; - you write dynamic imports or reach properties through variables. An example with a side effect: ```javascript // side.js console.log("This code runs on import!"); export const x = 42; ``` Even if `x` is never used, the whole file stays, because importing it executes `console.log()`, which is a side effect. ### Configuration in Webpack, Rollup and Vite **Webpack.** Tree shaking is enabled automatically in production mode when `package.json` contains: ```json { "sideEffects": false } ``` Instead of `false` you can give a list of the files that genuinely do have side effects. **Rollup.** Tree shaking is on by default. Historically Rollup was the first bundler to ship it. **Vite and esbuild.** It works out of the box, because both are built around ESM, and Vite additionally uses Rollup for the production build. ### The size of the win Before the optimization the bundle weighed 120 KB; after tree shaking, 42 KB. | Item | Description | | --- | --- | | What it does | Removes unused code from the final bundle | | Based on | ESM (`import` / `export`) and static analysis | | Works in | Webpack, Rollup, Vite, Parcel | | Does not work with | `require()`, side effects | | Goal | Reduce size and speed up loading | ### Common mistakes - **Expecting tree shaking from a CommonJS dependency.** If a library ships only a CJS build, the bundler cannot cut anything; look for a package with a `module` or an ESM `exports` field. - **Importing a whole package for one function.** `import _ from 'lodash'` pulls in everything; `import debounce from 'lodash-es/debounce'` gives the bundler a chance. - **Setting `"sideEffects": false` blindly.** If the package has files with real side effects, such as global polyfills or CSS imports, they silently vanish from the bundle. - **Checking the result in dev mode.** In Webpack tree shaking only runs in the production build, so measure the size there. - **Reaching exports through a variable.** `utils[name]()` makes static analysis impossible, and the bundler keeps everything. - **Confusing tree shaking with minification.** A minifier shortens the code that is there; tree shaking stops unused code from entering the bundle at all.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.