Introduction
Over the past 15 years, the JavaScript ecosystem has expanded rapidly, introducing countless tools to make development easi...
For further actions, you may consider blocking this person and/or reporting abuse
There are some notable issues that need to be pointed out for this comparison:
You are using Parcel's build time from a cached run. On my machine, a fresh build with Parcel is about 20x slower than a cache hit.
Your bundle size comparison is not just comparing bundlers, but a combination of bundlers + minifiers. This is quite difficult to make it apples-to-apples because some bundlers come with built-in minification, some require external minifier via plugins, and most of them allow switching between minifiers. The choice of which minifier to use is full of speed vs. quality trade-offs in itself. For example, Vite uses esbuild as the minifier by default, but can use terser or swc instead. In your benchmark, you are using esbuild as the minifier in the rollup config, but using terser in the webpack config. Terser is significantly slower than esbuild, but yields better minification ratio (see github.com/privatenumber/minificat...) If you want to compare only bundlers, then you should do it without minification, but that will not reflect production cases; if you want to compare bundle + minification, then you should at least use the same minifier for bundlers that don't have built-in minification.
Why Rolldown's bundle size look big in this case: while Rolldown has built-in minification (via Oxc minifier), it is still WIP. It only implements very rudimentary compression and is in there for integration test purposes, and has a LOT of room for improvements in the next few months. We should probably emit a warning when users use Rolldown's built-in minify before it is ready. For now, we recommend using a more mature minifier via a plugin. If you use swc as the minifier via a plugin with Rolldown, you should see similar bundle size compared to Rollup.
esbuild has a unique advantage in this benchmark in that its built-in minification adds very little overhead compared to its non-minified build, because it parallelizes many minify-related operations in its per-module transform phase, and also performs the final minification on the same AST. This architectural choice results in better performance, but limits the amount of cross-module optimizations that can be performed. In Rolldown / Oxc, we have opted to perform minification on a separate AST on the bundled chunks in order to be able to add more cross-module-analysis based optimizations down the road. This sacrifices some performance when the minifier is enabled, but will result in smaller bundles in the long run.
I'm not sure how you are measuring the numbers. Usually, numbers reported by the tools themselves omit some necessary overhead (e.g. launching the CLI, parsing the config etc.), where as end-to-end time via npm scripts includes unnecessary overhead of
npm
or the script runner. There is also a lot of noise / fluctutation between manual single runs. I think a more accurate way to report numbers is usinghyperfine
to run the builds using Node 22'snode --run
so that we measure the end-to-end time withoutnpm run
overhead.That's good feedback, which I was kind of hoping for. I will address some of the points:
The article is updated to:
rollup-plugin-esbuild
plugin.The updated results put Rolldown in the group of best performing bundlers when it comes to bundle size. This is very impressive, given that it's still in alpha.
Thanks for the update!
I noticed another thing: Rollup and Rolldown are showing unreasonably large bundles for MobX and tippy.js, and found out that their configs don't have the necessary options to replace
process.env.NODE_ENV
for treeshaking. PR: github.com/filipsobol/bundle-size-...Nice catch! I've also disabled the module preload polyfill in Vite because it was added to every result separately, skewing the results, while in real application will only be added once.
The article is updated.
Thanks for the comment!
In my humble opinion (and experience) build times don’t matter at all if compared to testing/linting processes timing at CI/CD pipelines. So the bundle size is eventually a much more important metric here — at least for large enterprise codebases.
This is an excellent overview of modern bundlers and their performance! I had no idea the differences in build times and output sizes could be so dramatic. Definitely trying out esbuild for my next project! 🚀
Thanks for pulling all this information together and sharing your insights!
It's been my world for the last 6 months reducing the bundle size of AG Grid!
Greetings from CKEditor! Shipping JavaScript libraries is much fun, isn't it, Filip? :D
Thanks for gathering all of this information. I've been trying to optimize some of my stuff for a while, and this really helps!
Thanks for the great article !
I've noticed that Webpack and Rspack supports context require by default, eg: require('./' + name), but rollup seems doesn't support it by default, so
moment
is bundled by webpack but not rollup in some cases, that affects bundle size as wellThis case is discussed here github.com/filipsobol/bundle-size-...