DEV Community

Cover image for How to make your library tree-shakable
Duc Le
Duc Le

Posted on

How to make your library tree-shakable

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:

Image description

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

Image description

Image description

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

Image description

The web package will install the common-ui package and uses its components:

Image description

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

Image description

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

Image description

By setting the formats for both CommonJS modules and ES6 modules and multiple entry points, our bundle will look like this

Image description

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:

Image description

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

Image description

You can see I removed the CodeEditor component, and run the build

Image description

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)