Updated: Apr 12, 2020
Bloated websites and web applications have become an epidemic of the modern web. While this is not much of an issue for users with high-speed internet and a high-performance CPU, it disrupts about everyone else. Mobile devices and users with slower internet connection are often highly sensitive to the size of the application, which directly affects network throughput, CPU utilization, memory footprint, and battery life.
Since this is quite well known, you may wonder: “How come this is not taken into consideration when building websites and applications?”. Well, when you develop your code on the latest-generation machines and enterprise-grade internet connection, it’s easy to overlook the package size issue. However, a timely reminder can change everything.
Instant notification about heavy packages
You can keep your application size under control using webpack-bundle-analyzer, cost-of-modules, bundlephobia, heeding webpack warnings or via code splitting and lazy loading. These tools and techniques can do a great job, yet you have to be very alert and never miss the insights they provide.
At some point, we realized that we’d rather use a tool that notifies you immediately upon importing a massive package in a visible, transparent and hard-to-miss manner. Being motivated by this gap, we have built the Import-Cost extension for VSCode.
Import-Cost is an open-source VSCode extension by we developed that provides instant feedback upon importing large packages. The extension, which has recently reached over 910,000 downloads, shows the size of third-party libraries the very moment they are imported. It helps you to prevent the package-size issues from snowballing and keep your application slim.
Note that though Import-Cost provides you with an immediate indication when importing oversized packages, it is not a bundle analysis tool.
For example, the size of the common dependencies between packages is calculated more than once. If packages X and Y use package Z, Z’s size is added to the sizes of both packages. We’ve chosen clarity and speed over the hidden logic that brings extra precision.
Import-Cost under the hood
There has been quite a lot of interest from the developer community about the internal design and logic of Import-Cost. Let’s shed some light on that.
The extension tracks the code changes in the active editor tab and analyzes these changes using the Babel-Parser package to find any import and require statements that use third-party libraries. These items are queued for inspection, as they often cause bundles bloating.
For example, when you paste the code snippet below into your code, Import-Cost inspects the react, react-dom and lodash/uniqueId libraries.
Import-Cost focuses on third-party libraries
Next, the extension creates a dummy application. It copies each import/require from the queue into a temporary file, uses the babili-webpack minifier plugin to optimize the application footprint, and runs webpack with that file as the entry point to identify all the dependencies of the third-party libraries and bundle them for size evaluation.
The extension considers only the code that is actually imported from the library, as webpack’s tree-shaking mechanism removes the unused components.
The extension also supports submodule imports that are useful for minimizing the amount of imported code:
Tree-shake everything except “func”
func1 is quite a party pooper
The imported object that has been copied to the entry-point file is printed through console.log to trick the tree-shaking mechanism into believing that it is used and prevent its code removal.
Caching and parallelization
To optimize the performance of the extension, it employs caching and parallelization. The former ensures that computation is only done once. The latter accelerates execution by parallelizing the calculations that cannot be fetched from the cache.
Caching takes into account the version of the libraries since different versions could have different sizes as demonstrated below. For parallelization, the extension uses the worker-farm library to run multiple webpack instances in parallel.
lodash version 3.10.1 weighs 51.2KB
lodash version 4.17.4 weighs 70.4KB
Once library sizes are calculated, you are informed of them with decorations, like 51.2K and 70.4K on the images above. Since computation is asynchronous, it might take a while. If by the time the information is ready you have already switched to another editor tab, the extension keeps the calculation results in a dedicated in-memory cache. Once you return to the relevant tab, the extension reads the cached info and promptly decorates the import or require statements.
While Import-Cost is originally designed as a VSCode extension, we’ve built it with portability in mind:
This modularity allows for IDEs other than VSCode to use the size calculation logic and have their own version of the extension.
The community rose to the challenge and built different versions of Import-Cost for almost all the popular IDEs out there:
JetBrains Editors - https://plugins.jetbrains.com/plugin/9970-import-cost
You are more than welcome to join over 910,000 users who have already downloaded the extension and even contribute based on your own needs and experience.
This post was written by Yair Haimovitch
You can follow him on Twitter
For more engineering updates and insights:
Visit us on GitHub
Subscribe to our YouTube channel