Modern Webpack Boilerplate: Part 4: Migration to RsBuild

Recap of Part 3: In the previous episode, we have added the setup for:

  • setup for Jest test runner
  • CSS with PostCSS configuration
  • assets handling
  • bundle size observability

As the boilerplate grows, so do:

  • new setup code
  • new configuration code
  • new dependencies for plugins and tools

You could ship this as an npm package (like react-scripts/next-scripts) to hide bundler complexity—but that requires:

  • ongoing maintenance and versioning
  • an internal abstraction for bundler setup

Alternative

If we want to proceed with Webpack in this part we will most likely end up with:

  • migrate from babel to swc for faster transforms
  • migrate from jest to modern vitest test runner
  • enable source maps
  • tune chunk-splitting
  • explore SSR support

Instead, this part migrates the boilerplate to RsBuild and evaluates the trade-offs.

Why RsBuild ?

It is powered by Rspack (Webpack-compatible most important API) batteries included like Vite. It is way faster than Webpack and need way less boilerplate.

Vite

Vite is the current "go-to" solution as a build tool for modern web applications.
It won't be the part of the comparison, since it needs stable Rolldown to compare with the speed of RsBuild (Rust vs Rust comparison).
Moreover the RSPack (bundler encapsulated in RsBuild) has compatible (most important parts) API with Webpack. The migration is typically smoother than switching to Vite.

You can check more about direct benchmarks in RsPack benchmarks

Establishing comparison metrics

To compare two tools we need a set of metrics:

  1. bundle size
  2. build time (local and CI)
  3. dev-server readiness time
  4. package.json dependency count
  5. overall project size on the machine
  6. install time of the project dependencies (with existing node_modules)
  7. boilerplate lines of code (without node_modules, package-lock.json)

Environment controls

  • Hardware: MacBook Air M1 (local), GitHub Actions free tier (CI).
  • Node & package manager: Node 22 LTS (22.19.0 at the time), installs with existing node_modules
  • Sampling: 5 runs for time-related metrics
  • Tooling:
    • timing: (time)
    • bundle: stat size and gzipped bundle
    • size: du -sh (project) jq for .dependencies and devDependencies
    • dev-server readiness: time printed by the bundler, when server is ready

I will create another post with comparison in big real world apps in future

Webpack results

  • bundle size: 199.96 KB (52.2 KB gzipped)
  • build time: (local and CI)
    • local: AVG 3.614s MED 3.574s
    • CI: AVG 6.418s MED 6.387s
  • dev-server readiness time: AVG 1.024s MED 1.023s
  • package.json dependency count:
    • dependencies: 3
    • devDependencies: 31
  • overall project size on the machine: 212 MB
  • install time of the project dependencies (with existing node_modules):
    • local: AVG: 1.556s, MED: 1.527s
    • CI: AVG: 10.981s, MED: 11.890s
  • boilerplate lines of code: 285 overall

RsBuild results

  • bundle size: 143.62 KB (45.62 KB gzipped) as it removed useless core-js polyfills
  • build time: (local and CI)
    • local: AVG: 0.865s, MED: 0.932s
    • CI: 1.246s, MED: 1.242s
  • dev-server readiness time: AVG: 0.038s, MED: 0.040s
  • package.json dependency count:
    • dependencies: 3
    • devDependencies: 16 (15 deps less)
  • overall project size on the machine: 216 MB (higher because of RsBuild cache and binaries)
  • install time of the project dependencies (with existing node_modules):
    • local: 1.358s, MED: 1.308s
    • CI: AVG: 8.527s, MED: 8.622s
  • boilerplate lines of code: 256 overall

Summary

It was quite obvious that in terms of performance the Webpack and Babel setup will fall short.
Migration also improves the business metrics, like:

  • faster hotfix recovery, less downtime cost
  • faster releases, shorter time-to-market, ship value sooner
  • lower infra spend (at org scale), better gross margin
  • fewer deps/simpler pipeline, less maintenance time, fewer failures/reruns
  • smaller bundles, cheaper bandwidth/CDN, faster conversions
  • faster dev server/local builds/HMR, less time/money wasted on waiting

Tradeoffs

It has some small tradeoffs:

That concludes this part. You can review all the details in following PR: https://github.com/Verthon/webpack-react-boilerplate/pull/6/files The best summary for the PR is removed-to-added code ratio: +930 −5,721