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
toswc
for faster transforms - migrate from
jest
to modernvitest
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:
- bundle size
- build time (local and CI)
- dev-server readiness time
- package.json dependency count
- overall project size on the machine
- install time of the project dependencies (with existing node_modules)
- 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
anddevDependencies
- dev-server readiness: time printed by the bundler, when server is ready
- timing: (
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:
- doesn't have as huge a plugin ecosystem as Webpack
- RSPack design goal is not to have 100% compliance with Webpack API
- RSPack won't create identical artifacts like Webpack
- doesn't support the WASM for browser-side
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