Tree shaking is a feature enabled by the ES2015 module definition. The idea is that given it's possible to analyze the module definition statically without running it, webpack can tell which parts of the code are being used and which are not. It's possible to verify this behavior by expanding the application and adding code there that should be eliminated.
Starting from webpack 5, tree shaking has been improved and it works in cases where it didn't work before, including nesting and CommonJS.
To shake code, you have to define a module and use only a part of its code:
src/shake.js
const shake = () => console.log("shake");
const bake = () => console.log("bake");
export { shake, bake };
To make sure you use a part of the code, alter the application entry point:
src/index.js
...
import { bake } from "./shake";
bake();
If you build the project again (npm run build
) and examine the build (dist/main.js
), it should contain console.log("bake")
, but miss console.log("shake")
. That's tree shaking in action.
To understand which exports are being shaked out, set `stats.usedExports` field to `true` in webpack configuration.
For tree shaking to work with TypeScript, you have to set `compilerOptions.module` to `es2015` or equivalent. The idea is to retain ES2015 module definitions for webpack to process as it needs the information for tree shaking.
The same idea works with dependencies that use the ES2015 module definition. Given the related packaging, standards are still emerging, you have to be careful when consuming such packages. Webpack tries to resolve package.json
module
field for this reason.
For tools like webpack to allow tree shake npm packages, you should generate a build that has transpiled everything else except the ES2015 module definitions and then point to it through package.json
module
field. In Babel terms, you have to let webpack to manage ES2015 modules by setting "modules": false
.
Another important point is to set "sideEffects": false
to state that when the code is executing, it doesn't modify anything outside of its own scope. The property also accepts an array of file paths if you want to be more specific. The Stack Overflow question related to this explains in detail why.
To get most out of tree shaking with external packages, you have to use babel-plugin-transform-imports to rewrite imports so that they work with webpack's tree shaking logic. See webpack issue #2867 for more information.
It's possible to force "sideEffects": false
at webpack configuration by setting up a loader definition with test: path.resolve(__dirname, "node_modules/package")
and sideEffects: false
fields.
[SurviveJS - Maintenance](https://survivejs.com/maintenance/packaging/building/) delves deeper to the topic from the package point of view.
Tree shaking is a potentially powerful technique. For the source to benefit from tree shaking, npm packages have to be implemented using the ES2015 module syntax, and they have to expose the ES2015 version through package.json
module
field tools like webpack can pick up.
To recap:
"sideEffects": false
as after that webpack knows it's safe to tree shake the package.You'll learn how to manage environment variables using webpack in the next chapter.
This book is available through Leanpub (digital), Amazon (paperback), and Kindle (digital). By purchasing the book you support the development of further content. A part of profit (~30%) goes to Tobias Koppers, the author of webpack.