Ever since Browserify, bundlers have been extremely important in the web ecosystem. They provide the ability to automatically process code, which opens up opportunities for performance optimization and non-native languages. This article looks at the background of bundlers, why they are essential, and their current state.
For a large part of the web, bundlers did not exist. To include scripts, most people just linked to the library on a CDN like CDNJS or Google Hosted Libraries. This would begin to change in 2009 when Node.js was released. Instead of using CDNs, Node.js came with its package manager, npm. npm was easy to use because every library was just one
npm install away, and updating was effortless. Because of the ease of use, many people wanted to use npm on the web. However, this was impossible until Browserify came along.
Browserify's tagline describes itself pretty well.
Browserify lets you
require('modules')in the browser by bundling up all of your dependencies.
require() statements in your code. Bundling also meant that your site was often faster because there were not as many HTTP requests being sent out, which reduced overhead (this is less the case in modern browsers because HTTP/2 adds the ability to download multiple resources on a single connection). Browserify quickly gained adoption because of these advantages. It is also important to note other ways of using modules on the web, like Require.js, which used AMD instead of CommonJS, and Bower, which fully replaced NPM for the browser.
If you already know why bundlers are used, you can skip this section
In general, most people do not write their code like this:
let l="hello";l+=" world!",l=l.repeat(5),console.log(l);
Instead, to make things readable, they would probably write something like this:
let text = "hello" text +=" world! " text = text.repeat(5) console.log(text)
However, the first example is smaller and therefore transferred faster. Now, you might think you have to sacrifice size for readability, but there is a solution, minifiers. Minifiers automatically transform your source code into a smaller form. In fact, the first code example was generated by Terser, which is one of the best minifiers. Bundlers make using minifiers easy through plugins. Additionally, bundlers help perform other optimizations, like tree shaking, which removes unused code. Finally, bundling scripts itself can improve performance by reducing HTTP requests needed.
Often, it is more efficient to use a language like Sass or Stylus instead of plain CSS. Or, perhaps you are trying to use TypeScript to enforce static typing in your code. Whatever the case, it is often better to use languages that the web does not natively support. Bundlers can help with this. Instead of running a bunch of different commands yourself to compile everything, you can often just add plugins to your bundler config file and run the bundler.
Most modern bundlers have features that enable faster iteration, like Hot Module Reload (HMR). HMR automatically reloads specific modules that have changed rather than the whole page, making reloading faster. Additionally, if you are using a framework like React, React state can be preserved, which means that the page data does not reset every time.
Bundling modules together is the original reason why bundlers were made. Even though there are many other features now, this is still important. Even with the native support of ESM, it is still helpful to be able to
require modules without having to write full import paths (although import maps could help with this).
Nowadays, almost every web developer uses one bundler or another. Webpack is by far the most popular, with Rollup and Vite in second and third, respectively. Currently, Vite is the fastest-growing major bundler, which has been adopted by frameworks like Vitepress, SvelteKit, Astro, and more.
ESM is supported in most modern bundlers. While tools like Browserify do not support ESM, most tools as new or newer than Webpack support ESM. Additionally, ESM is often the recommended way to do things for supported bundlers because it is more future-oriented than CommonJS or AMD, and it is easier to statically analyze imports for tree shaking. ESM also opens up the opportunity for unbundled development, which we cover below.
Unbundled development utilizes native ESM support in browsers to offer an ultra-fast development experience. Unlike a traditional bundler which bundles everything in development, unbundled development transforms the code and rewrites import paths to the ESM compliant file path without bundling your code. Additionally, most bundlers that do this pre-bundle dependencies because that decreases the number of imports needed, and dependencies are unlikely to change often. The two most prominent bundlers that utilize unbundled development are Vite and Snowpack. Snowpack, created in 2019, was the first bundler to have an unbundled development experience. However, while Snowpack was popular for some time, this did not last forever. In 2020, the team behind Vue created Vite. Vite has many advantages over Snowpack, like the ease of use, speed, better optimization, and more. Additionally, popular projects like SvelteKit adopted Vite instead of Snowpack. All of this helped Vite pass Snowpack in downloads, and it now has more than 10x downloads compared to Snowpack. In fact, even Astro, a project created by the team behind Snowpack (be on the lookout for an article about Astro), is now using Vite. Overall, if you want fast, unbundled development, I recommend Vite.
Webpack has an infamously complex plugin system. While it is very powerful, it can be scary for beginners. Luckily, there are newer bundlers that focus on this. Parcel was created in 2017 by Devon Govett to allow for easy, zero-config bundling. Parcel supports many of the features Webpack plugins provide, like Sass, TypeScript, and JSX, without requiring you to do anything. Additionally, due to caching and the increasing use of Rust, Parcel v2 can be faster than Webpack. Vite is another low-config bundler, although it does not do as much out of the box.
Webpack is still the most popular bundler. While it has not been taking advantage of the ability for massive speed improvements specified above, it still has added new features in the most recent version, Webpack 5. The biggest thing added in Webpack 5 is module federation, or micro-frontends. Module federation separates different elements of a website and makes it easier to share pieces of code like component libraries. Another big thing Webpack added in version 5 is better caching, which can improve reload times in development. Overall, Webpack is still advancing, although it is falling behind some bundlers in certain features.
The world of web bundlers is advancing quickly. Hopefully this article gave you an overview of what is currently happening for bundlers. If you liked this article, sign up for the ByteofDev mailing list here (or don't, but I hope you do 🙃), and thank you for reading.