DEV Community

Cover image for Webpack to Rspack: A Deep Dive Into Our Build Time Breakthrough
Diwaker Singh
Diwaker Singh

Posted on • Originally published at Medium

Webpack to Rspack: A Deep Dive Into Our Build Time Breakthrough

1. Why We Migrated

We maintain a large, multi-entrypoint Single Page Application (SPA) with a custom router and integrated micro-frontends via Module Federation. With over 11 independent entry bundles and full CI pipelines, build performance had become a major bottleneck — especially with Webpack.

Our main goal: dramatically reduce build time without touching bundle size or runtime behavior. Rspack promised faster builds with familiar Webpack compatibility, and it delivered — but not without a few surprises.


2. Migration Plan and Scope

We opted for an all-at-once migration rather than phasing. This included:

  • Replacing Webpack with Rspack in all configs.
  • Moving from webpack.config.js to an array-based rspack.config.js.
  • Updating all build/development scripts to use Rspack CLI.
  • Ensuring all CI/CD pipelines, microfrontends, and chunk-loading logic remained intact.

Rspack supports exporting an array of configs. Here's our rspack.config.js:

module.exports = [
  require('./rspack/agency-admin.config.js'),
  require('./rspack/surveys.config.js'),
  require('./rspack/server.config.js'),
  ...
];
Enter fullscreen mode Exit fullscreen mode

Each config builds independently in parallel — ideal for our multi-app setup.


3. Config Refactor: Before and After

Our configs are modular: each specific app config extends a shared base.config.js and webapp.config.js. Here's how we structured a few key parts.

✅ Example: agency-admin.config.js Highlights

output: {
  filename: DEVELOPMENT
    ? 'scripts/engage/[name].js'
    : 'scripts/engage/[name]/[contenthash].js',
  chunkFilename: DEVELOPMENT
    ? 'scripts/engage/[name].chunk.js'
    : 'scripts/engage/[name].chunk/[contenthash].js',
}
Enter fullscreen mode Exit fullscreen mode
  • Module Federation was preserved using Rspack’s ModuleFederationPluginV1.
  • Asset stats were written using our custom AssetManifestPlugin.

✅ Server Config (server.config.js)

  • Uses target: 'node'
  • externals configured with webpack-node-externals
  • Critical remotes loaded dynamically via module federation

4. Plugin & Loader Compatibility

Most Webpack loaders worked out of the box with minimal rewiring. However:

🛠️ Custom Plugin: AssetManifestPlugin

We retained a hand-written plugin that generates a stats manifest JSON:

compiler.hooks.done.tapPromise(pluginName, async (stats) => {
  const statsJson = stats.toJson({ entrypoints: true, chunks: true, ... });
  await writeFile(filepath, JSON.stringify(statsJson, null, 2));
});
Enter fullscreen mode Exit fullscreen mode

No changes were required to make it work with Rspack — a good sign of API stability.


5. Performance Gains

Metric Webpack Rspack Gain
Full Build 1032.47 s 312.92 s ~70% ↓

The improvement was immediate, both locally and on CI (Jenkins). No changes were required in CI jobs — we simply swapped out the CLI in package.json.


6. Gotchas

⚠️ chunkhash Collision in S3 Artifacts

  • We store all built assets in S3 using [chunkhash] filenames.
  • After the switch to Rspack, a few files generated the same chunkhash as previous Webpack builds — but with incompatible runtime formats.
  • Because we don't delete old artifacts, our CDN served a Webpack-built file instead of the new one.

✅ Fix:

Switched from:

filename: '[name].[chunkhash].js'
Enter fullscreen mode Exit fullscreen mode

To:

filename: '[name].[contenthash].js'
Enter fullscreen mode Exit fullscreen mode

This made the hashing content-aware and eliminated the risk of mismatched builds.


⚠️ ContextReplacementPlugin Shim Removed

During our initial POC, Rspack lacked support for ContextReplacementPlugin, which we relied on in Webpack. We wrote a custom shim to mimic it.

By the time we fully migrated, Rspack had added support, allowing us to delete the shim and simplify the config.


⚠️ Runtime Global Clashes

Rspack does not default chunkLoadingGlobal like Webpack. Without setting this explicitly, chunk runtime globals could clash — especially important in our microfrontend setup.

output: {
  chunkLoadingGlobal: 'rspackChunkLoadingGlobal',
}
Enter fullscreen mode Exit fullscreen mode

7. Testing, Tooling, and Integration

  • No changes were needed to our Flow, Jest, or E2E tests.
  • Linting worked fine with eslint-import-resolver-webpack pointing to rspack.config.js.
  • Tools like Sentry sourcemaps, Webpack Bundle Analyzer, and custom loaders worked without modification.

CI (Jenkins) required no pipeline changes. A simple script swap from webpack to rspack did the job.


8. Final Thoughts

This was a high-impact migration that paid off in less than a week. Here’s what worked for us:

✅ Migrating all apps at once to avoid hybrid states

✅ Ensuring S3 hash collisions were handled early

✅ Relying on plugin parity as Rspack matured


9. What's Next?

  • Investigating Rsdoctor for further cold build diagnostics
  • Possibly rewriting one legacy plugin using Rspack’s newer APIs
  • We currently use Babel to strip Flow types and rely on multiple Babel plugins. Moving to SWC would’ve touched a large surface area — so we deferred it.
  • Similarly, we stayed with our PostCSS plugin stack for CSS processing and didn’t switch to Lightning CSS, prioritizing migration safety over marginal gains.

Rspack is ready for real-world use — and for performance-obsessed frontend teams, it’s already a game changer.


Should You Migrate?

Here’s how we’d answer it:

  • ✅ Are your Webpack build times >10 minutes?
  • ✅ Do you have multiple independent apps or entrypoints?
  • ✅ Are you not relying on niche Webpack plugins with no Rspack equivalent?
  • ✅ Do you want a faster build with minimal rewrite risk?

If so, Rspack is a strong candidate. You don’t need to switch to SWC or Lightning CSS. We didn’t — and it still paid off.


Thanks for Reading

If this migration helped you, or if you’re considering a similar move, we’d love to hear from you. Feel free to drop questions or share your experience in the comments.

Interested in how our design system tooling or MCP integrations evolve from here? Follow along or check the repo links soon. ✌️

Top comments (0)