Most popular mistake to ruin Webpack bundle optimization


Intro

Working on big projects brings many difficult challenges, keeping applications bundle size in check is one of them. When project grows, inevitably you will start separating big sections of features into separate modules or sub-applications, delegating development to other teams or, sometimes, even other companies. Not after long you have huge application, tens teams building hundreds of modules, all to be packed, bundled and shipped towards user.

Control of bundle size becomes critical at this point, one module, one bad apple, can just ruin everything. Fortunately webpack does a lot of optimisation under the hood, to make sure you ship as minimum code as required. However, and I witnessed this over and over again, there is still one simple mistake you can do that will prevent webpack from working its magic. Let’s talk about that.

TL;DR

We all know at this point, webpack does “tree shaking” to optimise bundle size. Just in case, “tree shaking” is a term commonly used in the JavaScript context for dead-code elimination, or in simple words – export-ed code that wasn’t import-ed and executed will be detected as unused, so it can be safely removed to decrease bundle size.

What you might not know, it’s not the webpack that cleans up dead code per se. Of course, it does bulk of “preparation” work, but it is terser package that actually will cut off unused code. Terser is JavaScript parser, mangler and compressor toolkit for ES6+.

Let’s lay this out – webpack will take your modules, concatenate them into chunks and feed to terser for minification (all of this, obviously, will happen only if optimization is enabled).

 
Time to highlight few key points:

  • By default, webpack always will try to concatenate your code from different modules (files) into one scope and create a chunk from it later. E.g. moduleA.js imports few methods from moduleB.js will end up being chunk-[hash].js containing code from both files mentioned before within one scope, like it was written inside one file in the first place (essentially removing “module” concept). When it can’t be concatenated though, webpack will register those files as modules, so they can be accessed globally via internal helper __webpack_require__ later.

  • By default terser doesn’t cut off global references in your code (topLevel flag is false). E.g. you build some library with global scope API, you don’t want it to be removed during minification. In essence, only somewhat “obviously” dead (unreachable) code or unused in near scopes code will be removed.

You probably saw this coming – terser can remove your unused export-s only if webpack scoped them in a way that unused declarations can be easily detected.

For optimization webpack heavily relies on the static structure of ES2015 module syntax, i.e. import and export key-words, and, as for now, doesn’t work for other module types. We can see this ourself from the source.



Source link

Latest articles

Related articles

Leave a reply

Please enter your comment!
Please enter your name here