Tree shaking
Tree shaking is a term commonly used in the JavaScript context for dead-code elimination. Although many bundlers nowadays support tree-shaking like Rollup or Webpack, tree-shaking is not just an on/off feature. To make tree-shaking becomes valuable, there are many factors that affect the quality
Basically, Tree shaking is detecting which exports are unused in our application when bundling and won’t include it into our bundler.
Achieve Tree-shaking
From tree-shaking basic definition, many bundlers support it by default, you might don’t have to do any thing. Look at my example below:
Here is my library called common-ui
, I split my code into small modules and export them all in the root index.ts
file. And here is my bundler config ( tsup ) and the dist folder after I built it
This is the most basic config though. I only set up the entry point to the index.ts . So every line of code that are not exported and used by this file won’t be included in our dist folder. By this way, you are achieving dead code elimination right ?
But it is more complicated than that
A library is nothing without an application that uses it, since my example is a monorepo. I will create a package to use the library
The web
package will install the common-ui
package and uses its components:
You can see that I imported 9 components from the common-ui
library, let’s see what is the bundle size of my web application
It’s 258kb, quite heavy. So let’s see if I remove few imports from the common-ui
library to reduce the bundle size
Well…. I tried to remove half of the imports, but the bundle size still the same. So the tree-shaking thing I did above absolutely didn’t help.
Why ?
This is because Common JS Modules VS ES6 Modules
The significant difference is that ESM imports are static whereas CJS imports are dynamic
TSup
uses esbuild
as its bundler and it supports both formats
Tree shaking relies on static code analysis. It detects which modules are necessary for the code to work and eliminates other modules from the final bundle during compile time.
So ESM is a requirement for Tree-Shaking feature.
Let’s change our config file a bit
By setting the formats for both CommonJS modules and ES6 modules and multiple entry points, our bundle will look like this
For every module in our files, there will be both .cjs
file and .js
file for CommonJS and ES6 modules respectively. In our package.json
file:
We map the .cjs
and .js
and .d.ts
files and set the side effects optimization and make our library side effects free. Now let’s get back to our web application to see if the bundle size is smaller when I remove imports
You can see I removed the CodeEditor
component, and run the build
The bundled size is smaller from the 260kb above because the bundler detected we only use parts of the library so It won’t include whole library into to bundled file.
Conclusion
Tree shaking a library is not simple. Its quality depends on multiple factors and this article presents the basics. Understand what is the bundled output and the formats are the basics to make our library tree-shakable
You can check out my source code here
Last words
Although my content on dev.to is free for everyone, but if you find this article helpful, you can buy me a coffee here
Top comments (0)