Tree Shaking Font Awesome Icons

August 11, 2019

Photo by Faye Cornish

Tree shaking: a word that at first sounds like another convoluted term used to describe some obscure technology or pattern. After rephrasing it as "dead code elimination," I find tree shaking to actually be a strong metaphor for what it describes.

Imagine building a large application and over time many packages are added as dependencies. Some of these packages provide utility methods, like the intersection method from lodash or underscore. Then there's more packages that provide some UI components like Evergreen UI, Semantic UI, React Bootstrap or one of the many others. And finally, maybe some icons provided by Font Awesome.

Relying on these packages saves a lot of time but if not monitored closely, the bundle size can start to explode resulting in shipping many megabytes of JavaScript and other assets to a user's browser. It not only takes a long time to download (especially on slower connections) but now the browser has to parse and compile all that code which can add signifigant time (especially on devices that may not have a lot of resources).

There are a few options. First, it's possible a user doesn't need all that code immediately. The bundle could be code split into smaller chunks so a user only has to download the code they need for the current page or feature they are interacting with. However, even with code splitting, if there are a lot of dependencies a user still has to download a lot of code on the initial load. But do they need all those dependencies? The simple answer is usually yes. The first page requires a utility method, and a UI component and an icon so all those dependencies need to be loaded. But the more complex and nuanced answer is usually no.

Across the whole application, maybe only 10% of the utility methods are used, 80% of the UI components and 20% of the icons. Each dependency is necessary but not all the utility methods, components and icons from those packages.

That means 90% of the utility methods, 20% of the UI components and 80% of the icon code that is being delivered to users is "dead code." Dead code is code that is included but never ran. Ideally, this dead code can be eliminated. It not only consumes more bandwidth and adds latency, it also adds times to decompressing, parsing, compiling and other processing the client has to do after it's been downloaded. This also means that during build time, it takes longer to minify, build sourcemaps, compress and any other sort of preprocessing that takes place.

Eliminating dead code is pretty straightforward in application code that you write. If a feature or component is unused, delete it. But how does this work with an external package? Isn't that all or nothing? It's either in package.json as a dependency or it's not?

🌳 Tree Shaking

As of version 2, webpack supports tree shaking. It requires the packages to be properly configured and built to allow tree shaking. Tree shaking is performed automatically by webpack in production mode. When it does work, it hopefully looks something like this.