A bundler story: migrating from Webpack to Rspack

Tim Petricola
Alan Product and Technical Blog
7 min readSep 3, 2024
Photo by Seth Doyle on Unsplash

Here at Alan, we have been using Webpack for years. While it has served us well, it has become a bottleneck for development. We recently completed the migration to Rspack, a Rust alternative promising better performance. This is a short story of our journey and learnings.

Picking a bundler

JavaScript bundlers are tools that package our code and its dependencies into single or multiple JavaScript files, optimized for performance and browser loading.

When Alan started (in 2016), Webpack was the de facto bundler for JavaScript applications. It was battle-tested, had a large ecosystem, and had very extensive configuration options.

Webpack has served us very well over the years, but it has become a bottleneck for development. Our local build and hot module replacement were not fast enough:

  • the first load on the server start would take up to 45s
  • HMR could take up to 15s to complete
  • Production build would take more than 5min on CI

We managed to improve our setup over the years (e.g. filesystem cache, replacing Babel and Terser with Esbuild, …) but we reached a point where it was hard to get more performance improvement without a complete rewrite.

There was an opportunity to improve the feedback loop both in development and in production by finding a new bundler.

Over the past few years, a lot of new build tools have appeared in the JavaScript ecosystem — Parcel, Vite, Esbuild, Rspack, Turbopack, Farm, Mako, etc. All of them promise their own advantages in terms of developer experience and performance.

But at Alan, we like boring tech. We don’t want to use cutting-edge technology that would require engineers to dig deep into new concepts or spend time overcoming issues in tooling. We kept this principle in mind as we took a look at two new bundlers — Vite and Rspack.

Vite

We’ve explored switching to Vite in the past, as it has become a very popular tool in the React ecosystem. Vite is an amazing tool with a different approach as it doesn’t bundle assets in development, allowing for faster server start times and hot module replacement. However, we found that Vite was not a good fit for us:

  • Vite relies on different tools for development and production builds (Esbuild in dev, Rollup in prod). It can lead to discrepancies between development and production builds, and it can be hard to debug issues in the build process.
  • The unbundled approach of Vite in development would often lead to browser network congestion due to the high amount of modules we have in our application. It can be optimized, but it was consuming more time than we wanted to spend on it.
  • Vite is very different from Webpack. We would have had to rewrite our entire build configuration, which can be very time-consuming and error-prone.

Rspack

Early in 2023, a new bundler entered the game: Rspack. It promised Webpack interoperability but with massive performance improvements (notably thanks to the Rust ecosystem).

While we don’t like adopting brand-new technology, the promise was so good that we decided to try it during a cooldown week (transition week between quarters, without a set roadmap, making it easy to explore new ideas).

Our Migration Journey

Experimentation phase

As Webpack’s config is mostly compatible with Rspack, the initial proof of concept was quite straightforward. For incompatible parts, we implemented a small compatibility layer converting any Webpack config to Rspack config. This layer handled gotchas like:

  • removing unnecessary loaders (e.g. css-loader)
  • replacing some plugins with their Rspack equivalents (e.g. html-webpack-plugin by rspack.HtmlWebpackPlugin)
  • switching our custom Esbuild loader and minifier in favor of the built-in ones using SWC

Only ~200 lines of code were needed for the compatibility layer, thanks to Rspack being designed as a drop-in replacement for Webpack.

And the resulting performance was … impressive ⚡:

  • local initial build times were up to 3x faster than Webpack (from 16s to 6s)
  • hot module replacement was up to 20x faster than Webpack (from 7s to 400ms)

Even more, these numbers are an underestimate of the true performance gain, as:

  • They compare Webpack without sourcemaps to Rspack with sourcemaps (with Webpack sourcemaps became so slow that we didn’t have them enabled by default in development).
  • We were using a filesystem cache for Webpack, while Rspack has no cache at all

We had a few issues at this point as Rspack was still a very early project: we couldn’t make our SSR configuration work, CSS extraction was not ready, and we had transient HMR errors. But it was good enough that we decided to let engineers opt-in to Rspack in development and see how it went.

Real user monitoring

While we could immediately see the benefits of Rspack in our local development, we wanted to make sure that we significantly improved the developer experience.

We decided to collect data on initial builds and HMR updates. This data would be collected on developer machines and sent to Datadog to be easy to visualize.

We implemented a very simple plugin compatible with both Webpack and Rspack, thanks to Unplugin.

This allowed us to confirm that improvements were there for all our engineers, not just in specific scenarios.

Progressive rollout

As Rspack improved and moved from 0.1 to its first v1.0 stable version, we kept upgrading and improving our setup.

We started migrating small internal projects to Rspack. Our migration process for each project looked like this:

  1. local opt-in usage of Rspack with a BUNDLER=rspack environment variable
  2. make Rspack the default local bundler (and allow opting out with BUNDLER=webpack)
  3. switch the production build to Rspack
  4. remove support for Webpack

The BUNDLERenvironment variable was key to gather more information about Rspack while not being too constraining for engineers. Setting the variable to rspack would:

  • switch the bundler used in development to Rspack
  • add more information in the console output to help engineers (e.g. referring to our internal Rspack documentation, telling them who to ping in case of issues, and how to switch back to Webpack)

On each project we migrated we saw instant improvement in build times, and we could progressively move more and more complex parts of our codebase to Rspack.

We migrated some internal projects in parallel while we waited for Rspack to gain stability for more critical ones. We eventually reached a state where the only project still on Webpack was the one serving our landing pages with server-side rendering (and we were waiting for Rspack v1.0 to be able to switch that one).

Completing the migration

Over time, all issues we initially had with Rspack were solved either by newly released versions, or by tweaking our configuration.

As Rspack reached its first stable version last week, we were ready to flip the switch for our final application.

To complete the migration we:

  • switched the last application to Rspack in production and development
  • removed the compatibility layer and started uring Rspack configs as the only source of truth

We also replaced our Storybook’s webpack5 builder with storybook-rsbuild (Rsbuild is an abstraction layer over Rspack, which is compatible with Storybook).

Results

Performance

But what about the real-world numbers? Taking one of our most complex projects, the improvements are clear:

+---------------------+---------+--------------+
| | Webpack | Rspack |
+---------------------+---------+--------------+
| Dev - Initial build | 16.17s | 5.99s (-62%) |
| Dev - HMR | 2.90s | 700ms (-72%) |
| Prod - Build | 2min10s | 34s (-86%) |
+---------------------+---------+--------------+

And our Storybook build time went from 2min25 to 33s (-88%).

Maintainability

We could also remove a lot of boilerplate configuration as Rpsack has amazing defaults out of the box:

We also don’t have to maintain a custom filesystem cache in development (and sometimes have to bust it manually) as Rspack is already fast without a cache.

Internal feedback

The feedback from the team has been very positive:

Switching to Rspack was LIFE CHANGING for my frontend developments in the last 1+ year.

Rspack made frontend dev much easier!

WOW that’s much much better ⚡

Looking ahead

We’re very excited about the future of bundlers. We are very happy with Rspack, but we’re also closely following what’s happening with Vite (especially with the upcoming Rolldown, their Rust alternative to Rollup).

The team behind Rspack released Rsbuild. This is a higher-level build abstraction over Rspack. It has amazing defaults and provides good performance and a lot of features out of the box.

The whole ecosystem is also moving fast and adopting this new generation of bundlers. For instance, we rely on Docusaurus for some internal documentation and can’t wait for them to complete their move from Webpack to Rspack!

If you’re considering making the switch from Webpack to Rspack, we highly recommend giving it a try!

--

--