Upgrade to `RSPack` and `pnpm`
Notes from Cam
- The lines changed is only huge because of
yarn.lockremoval andpnpm-lock.yamladdition. Many of the files changed are just removing the hot reload. - On that note: This PR would remove the need for a "hot reload" package like we have in #9112. So that's another consideration.
- I did a bit of digging related to CI and our deployment infrastructure and this change should work well. But it will be telling if we try to deploy to prototype to test.
Migrate from Webpack to RSPack and Yarn to pnpm
Overview
This PR modernizes the Treeherder build infrastructure by:
- Migrating from Webpack to RSPack - A Rust-based bundler that is 5-10x faster while maintaining near-complete Webpack API compatibility
- Migrating from Yarn to pnpm - A more efficient and stricter package manager with better disk space usage and faster installs
- Cleaning up legacy dependencies - Removing deprecated packages and optimizing the dependency tree
Why RSPack?
RSPack is a high-performance JavaScript bundler written in Rust that offers:
- 5-10x faster builds compared to Webpack
- Near-complete Webpack API compatibility - minimal migration effort
- Built-in SWC support - faster transpilation than Babel for the build process
- Active development - backed by ByteDance, used in production at scale
Why pnpm?
pnpm offers several advantages over Yarn:
- Faster installs - Up to 2x faster than npm/yarn
- Disk space efficient - Uses hard links to save disk space
- Stricter dependency management - Prevents phantom dependencies
- Better monorepo support - Not relevant here, but future-proofing
Changes Made
Build System Migration
| File | Change |
|---|---|
webpack.config.js → rspack.config.js |
Migrated to RSPack configuration with equivalent functionality |
package.json |
Updated scripts to use rspack instead of webpack |
.npmrc |
Added pnpm configuration file |
.yarnrc |
Removed (no longer needed) |
yarn.lock → pnpm-lock.yaml |
Switched lockfile formats |
RSPack Configuration Highlights
- Uses
builtin:swc-loaderfor faster JS/JSX transpilation (faster than Babel) - Uses
@rspack/plugin-react-refreshfor HMR (replacesreact-hot-loader) - Maintains all existing functionality: code splitting, CSS extraction, dev server with proxy, etc.
- Silences Sass
@importdeprecation warnings (Bootstrap 5 still uses@import)
Dependency Cleanup
Removed from dependencies (no longer needed)
-
react-hot-loader- Replaced by RSPack's built-in React Refresh
Removed from devDependencies
-
@babel/plugin-proposal-class-properties- Deprecated, built into @babel/preset-env -
@babel/plugin-syntax-dynamic-import- Built into @babel/preset-env -
path- Built-in Node.js module, unnecessary as a dependency
Moved to devDependencies (were incorrectly in dependencies)
-
eslint-formatter-codeframe- Only used by ESLint -
globals- Only used by ESLint config -
redux-mock-store- Only used in tests
Code Changes
Removed react-hot-loader usage from 8 files:
-
ui/App.jsx -
ui/job-view/App.jsx -
ui/login-callback/LoginCallback.jsx -
ui/logviewer/App.jsx -
ui/push-health/App.jsx -
ui/intermittent-failures/App.jsx -
ui/userguide/App.jsx -
ui/perfherder/App.jsx
Configuration Updates
| File | Change |
|---|---|
babel.config.json |
Simplified - removed deprecated plugins, using automatic JSX runtime |
.prettierignore |
Added venv/, node_modules/, pnpm-lock.yaml |
.circleci/config.yml |
Updated to use pnpm |
docker/Dockerfile |
Updated to use pnpm |
docs/*.md |
Updated documentation to reference pnpm commands |
Testing
All scripts pass successfully:
| Script | Status |
|---|---|
pnpm build |
✅ Compiles with no errors or warnings |
pnpm build:dev |
✅ Compiles successfully |
pnpm lint |
✅ No linting errors |
pnpm test |
✅ All tests pass |
pnpm start |
✅ Dev server starts, HMR works |
pnpm format:check |
✅ All files formatted correctly |
pnpm markdownlint |
✅ No markdown issues |
Build Performance Comparison
While exact benchmarks depend on hardware, RSPack typically provides:
- Production build: ~1.7s (vs ~5-8s with Webpack)
- Development build: ~1.3s (vs ~4-6s with Webpack)
- HMR updates: Near-instant
Migration Guide for Developers
For local development
# Remove old dependencies
rm -rf node_modules yarn.lock
# Install pnpm if not already installed
npm install -g pnpm
# Install dependencies
pnpm install
# Start development server
pnpm start
Common commands (same as before, just use pnpm)
pnpm start # Start dev server (connects to production API)
pnpm start:stage # Start dev server (connects to staging API)
pnpm start:local # Start dev server (connects to local backend)
pnpm build # Production build
pnpm test # Run tests
pnpm lint # Run ESLint
Package Manager Enforcement
This PR adds guards to ensure developers use pnpm instead of yarn or npm.
How It Works
1. packageManager field in package.json
"packageManager": "[email protected]"
This field:
- Blocks Yarn (classic) with a clear error message about Corepack
- Signals to modern tools and CI systems which package manager to use
- Is the standard way to declare package manager requirements per Node.js Corepack
2. preinstall script
"scripts": {
"preinstall": "npx only-allow pnpm",
...
}
This script:
- Runs before any install command
- Provides a clear error message if someone tries to use npm or yarn
- Works as a fallback for environments that don't respect
packageManager
What Developers Will See
If they try to use Yarn:
error This project's package.json defines "packageManager": "[email protected]".
However the current global version of Yarn is 1.22.22.
Presence of the "packageManager" field indicates that the project is meant
to be used with Corepack...
If they try to use npm:
Use "pnpm" for installation in this project.
If you don't have pnpm, install it via "npm i -g pnpm".
For more details, go to https://pnpm.io/
Migration for Developers
# Remove old dependencies
rm -rf node_modules yarn.lock
# Install pnpm if not already installed
npm install -g pnpm
# Install dependencies
pnpm install
# Start development
pnpm start
Breaking Changes
None. The migration is transparent to end users and maintains all existing functionality.
Remaining Warnings (informational only)
- Peer dependency warnings - Several older React packages have peer deps for React 16/17. These work fine with React 18 but pnpm is stricter about reporting them.
-
Node deprecation warning -
util._extenddeprecation from a transitive dependency. Does not affect functionality.
Future Improvements (out of scope for this PR)
- Consider migrating from
momenttodayjsfor better tree-shaking - Consider upgrading
react-router-domto v6 - Consider upgrading to newer versions of date picker, split pane, and table components that properly support React 18
Codecov Report
:white_check_mark: All modified and coverable lines are covered by tests.
:white_check_mark: Project coverage is 81.37%. Comparing base (a82c683) to head (5aad6b8).
Additional details and impacted files
@@ Coverage Diff @@
## master #9114 +/- ##
==========================================
+ Coverage 80.01% 81.37% +1.35%
==========================================
Files 601 601
Lines 32715 33764 +1049
Branches 3314 3057 -257
==========================================
+ Hits 26178 27476 +1298
+ Misses 6371 5930 -441
- Partials 166 358 +192
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
- :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
I was doing a bit more digging. And there are a couple more easy optimizations we can make to improve the test execution and docker. I'll create another commit for that shortly.
I just rebased this on latest master
@Archaeopteryx I wanted to check if there's anything else you need from me on this PR. I have time to work on it today, if needed.