The best way to annoy and frustrate users is to give them a sluggish, unresponsive experience. So if you’d like your users to curse your name and yell in frustration, skip this article.
Still here? Cool. As you know, in modern JavaScript, it is too easy to ship excessive megabytes of JavaScript code to the client. Bundlers and code splitters exist to trim out excess source code and ensure the user downloads the minimum payload required to use the app. As in all things JavaScript, you have choices. Perhaps there are too many choices, but too many are undoubtedly preferable to not enough, so we’ll have to accept and embrace the reality and figure out which one is the right choice for your specific circumstances.
While you could download and configure each bundler to validate effectiveness in your application, why do that when Google already did this for you? In this episode of React Wednesday, Zain Sajjad walked us through the main points for JavaScript bundlers, did demos, and interpreted the results. Read on for the bake-off results. Note, I won’t rehash the Google test results. They speak for themselves and are going to be updated from time to time. Please check their site for the latest results.
Which bundler is the best?
Ahh, the old “Which one is the best question?”. If you’ve been in software development for enough time, you know the answer is always “It depends”. In the case of bundlers, the bundler authors have optimized each bundler for specific outcomes. In this article, we’ll go over what each bundler is good at so you can make an informed decision.
It’s important to mention that your success with a particular bundler is a function of how well you design your bundling and code splitting strategy. Even the best bundlers won’t save you from a poorly thought out plan.
Take the issue of caching and hashing. The browser will cache files it has and not request them again over the wire. If you split your code well, much of the user’s code will come from a cache local to the user- the fastest method. If the splitting is done poorly, the browser will request code from the network when it could have avoided it – substantially slower than cache. Take the time to consider the outcome you want and what options you have before you worry too much about the “best” bundler.
The best advice for bundling
When you think through your bundling and code splitting strategy, be sure to consider what you expect to change in the future. Custom application source code (.js, .css, etc) will change often. Library and framework code will change (hopefully) at a slower rate. Static items like images, font packs, and so on will change little, if at all. Each time you ship a new bundle, expect all users to go through a cache invalidation, request-from-network process to load the new bundle.
Why use Webpack for JavaScript Application Bundling?
- Development – First Build: 1,383ms
- Development – Reload App: 38ms
- Release Build: 2,996ms at 132KB
- Library Release: 2,740ms at 6KB
- Configuration Requirements: Sophisticated and highly configurable on the one hand, verbose and complex on the other.
Webpack uses the pre-transpiled source code content as the hash input. If you upgrade your transpiler, and feed in your unchanged source code, Webpack will not generate a new hash nor cause a cache invalidation on the user’s browser. This design decision means that users will not download the latest version of the code. You may find this behavior desirable or not desirable, depending on your circumstances.
According to Zain, WebPack is an excellent choice for web applications. There are tons of plugins available, along with robust community support.
Why use Parcel for JavaScript Application Bundling?
- Development – First Build: 3,730ms
- Development – Reload App: 190ms
- Release Build: 4,670ms at 128.21KB
- Library Release: 1,340ms at 5KB
- Configuration Requirements: None. Parcel does a lot of magic for you without requiring configuration.
Parcel uses the post-transpilation product as the source for hashing. This design decision often gives Parcel a slight edge in caching because changes, like altering a comment, that don’t make it into the transpiled content won’t affect caching. If you upgrade your transpiler and the content output is different, this condition creates a new hash and subsequent cache invalidation on the user’s browser.
Why use Rollup for JavaScript Application Bundling?
- Development – First Build: 5,500ms
- Development – Reload App: 667ms
- Release Build: 9,660ms at 127.81KB
- Library Release: 1,660ms at 3KB
- Configuration Requirements: Minimal and clear
Like Webpack, Rollup uses the pre-transpiled source code content as the hash input. If you upgrade your transpiler, and feed in your unchanged source code, Rollup will not generate a new hash nor cause a cache invalidation on the user’s browser.
One thing to be aware of about Rollup is it doesn’t correctly update hashes for dependent assets. Ideally, when an asset is updated and referenced in a JavaScript bundle, the bundler should detect that and update the bundle’s hashed URL.
On the other hand, Rollup does a fantastic job crunching down the file size, especially for the library release test. According to Zain, Rollup is an excellent choice for libraries. If you build and ship library code, take a look at Rollup first. There are plugins available though the Rollup plugin ecosystem is not as robust as Webpack.
So Which Is The Best?
Ahh, that question again. The right decision depends on how you’d like to bundle your application source code. By watching the replay of this broadcast and also looking over the tests performed by the Google team, you’ll be in a better spot to choose a JavaScript bunder that produces optimal bundles for your application circumstances.
Helpful Links
- React Wednesdays site – upcoming show schedule, archives, calendar invites
- React Wednesdays: Comparing Webpack, Rollup, Parcel, and More
- Zain’s article on benchmarking bundlers in 2020
- Bundler Tooling Report – Google
- Zain @zsajjad93 on Twitter