gotchajavascriptModerate
Tree shaking fails when modules use CommonJS (require) instead of ES modules
Viewed 0 times
tree shakingCommonJSESMlodash-esdead code eliminationsideEffectsbundle size
Problem
Dead code elimination (tree shaking) does not work for libraries shipped as CommonJS. Importing a single utility from lodash or moment pulls the entire library into the bundle because require() is dynamic and cannot be statically analyzed.
Solution
Use libraries that ship ES module builds. For lodash, use lodash-es. Configure bundlers to prefer the module field in package.json.
// Bad: pulls entire lodash (71kb gzipped)
import { debounce } from 'lodash';
// Good: tree-shakeable ESM build
import { debounce } from 'lodash-es';
// Or: import single function directly (always safe)
import debounce from 'lodash/debounce';
// webpack.config.js — prefer ESM entry point
module.exports = {
resolve: {
mainFields: ['module', 'browser', 'main']
}
};
// Bad: pulls entire lodash (71kb gzipped)
import { debounce } from 'lodash';
// Good: tree-shakeable ESM build
import { debounce } from 'lodash-es';
// Or: import single function directly (always safe)
import debounce from 'lodash/debounce';
// webpack.config.js — prefer ESM entry point
module.exports = {
resolve: {
mainFields: ['module', 'browser', 'main']
}
};
Why
ES module import/export statements are static — bundlers can determine at build time which exports are used and eliminate the rest. require() calls are dynamic function calls that cannot be safely removed without execution.
Gotchas
- sideEffects: false in package.json is required for bundlers to tree-shake your own library
- CSS imports are always treated as side effects — mark them explicitly in sideEffects: ['*.css']
- Babel transforming import to require() disables tree shaking — ensure @babel/preset-env targets modern browsers or use modules: false
- Check actual impact with webpack-bundle-analyzer before assuming a library is bloated
Code Snippets
package.json fields for tree-shakeable ESM library
// package.json for a tree-shakeable library
{
"name": "my-lib",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"sideEffects": false
}Context
When bundle analysis shows a library is much larger than expected, or when migrating from CJS to ESM
Revisions (0)
No revisions yet.