Introduction
In todayβs fast-paced development environment, build performance is crucial for developer productivity and deployment efficiency. Our team recently undertook a significant migration from Create React App (CRA) to Rsbuild, resulting in a remarkable 50%+ improvement in build times. This blog post outlines our journey, the challenges we encountered, and the lessons we learned during this migration.
Overview of the current stack
Core Architecture
- Micro Frontend Architecture: Built using Module Federation with multiple micro-frontends for different modules
- React 18
- TypeScript
- Create React App (CRA) with react-app-rewired for configuration overrides
- npm with Node.js 22.x
UI & Styling
- Design System: Custom design system built as a wrapper around Ant Design
- Styling:
Less
preprocessor for AntD overrides and Tailwind for the main styling - Monaco Editor for advanced code editing capabilities
- Day.js for lightweight date manipulation
State Management & Data
- State Management: Redux with Redux Saga for side effects
- Data Fetching: TanStack React Query for server state management
- Internationalization: i18next for multi-language support
Why We Needed This Migration?
The Problem with CRA
Our existing setup had several critical issues that were impacting our development workflow:
- CRA Deprecation: Create React App is officially deprecated, meaning no new features or security updates
- Slow Build Times: Our webpack-based builds were taking an average of 15 minutes to complete
- Bloated Configuration: Complex webpack overrides using react-app-rewired were becoming unmaintainable
Impact
- Customer Impact: Delays in fixing bugs due to slow build times were affecting customers. This led to frustration and a decrease in user satisfaction, as customers had to wait longer for improvements/fixes.
- Developer Productivity: Long build times significantly reduce developer velocity
Why We Chose Rsbuild?
After evaluating several alternatives, we chose Rsbuild for the following reasons:
1. Performance Benefits
- Rust-based Rspack: Underlying bundler written in Rust, providing ~50% faster builds compared to webpack
- Optimized Architecture: Built specifically for modern web development with performance in mind
2. Seamless Migration Path
- Webpack Compatibility: Rspack offers a webpack-compatible API, making migration smoother, and most popular webpack plugins are already supported
- CRA Migration Guide: Comprehensive migration documentation available at rsbuild.rs/guide/migration/cra
3. Out-of-the-Box Features
- Module Federation: Native support for micro-frontend architecture
- Less Support: Built-in Less preprocessor support
- Tree Shaking & Code Splitting: Advanced optimization features
- TypeScript: First-class TypeScript support
4. Future-Proof Architecture
- Plugin-based System: Extensible architecture for future enhancements
- Active community: Regular updates and active community support (300k+ weekly downloads)
- Modern Tooling: Built for the modern web development ecosystem
Migration Plan & Strategy
Phase 1: Foundation Setup
Following the official Rsbuild CRA migration guide, we:
-
Replaced Dependencies:
npm remove react-scripts npm add @rsbuild/core @rsbuild/plugin-react -D
-
Updated Scripts:
{ "scripts": { "start": "rsbuild dev", "build": "rsbuild build", "preview": "rsbuild preview" } }
-
Created Configuration:
// rsbuild.config.ts import { defineConfig } from "@rsbuild/core"; import { pluginReact } from "@rsbuild/plugin-react"; export default defineConfig({ plugins: [pluginReact()], });
Phase 2: Plugin Migration Analysis
We identified and migrated our webpack plugins:
Removed Plugins (native Rsbuild support):
babel-plugin-transform-remove-console
βperformance.removeConsole
worker-loader
β Native web worker support
Migrated Plugins:
- Module Federation β
@module-federation/rsbuild-plugin
- Less loader β
@rsbuild/plugin-less
- Node polyfills β
@rsbuild/plugin-node-polyfill
Phase 3: Staged Rollout
- Staging Environment: Deployed changes to staging for initial testing
- Beta Environment: Extended testing in the beta environment
- Traffic Analysis: Monitored for one week to identify potential issues
- Production Deployment: Gradual rollout to production
Challenges Faced & Solutions
1. Plugin and Loader Compatibility
- Challenge: Not all webpack plugins or loaders are directly compatible with Rsbuild/Rspack.
- Guideline: Audit your current plugins and loaders, and check for native support or recommended alternatives in Rsbuild. Be prepared to refactor or remove plugins that are no longer necessary or supported.
- Example: We found that plugins like
babel-plugin-transform-remove-console
andworker-loader
were no longer needed, as Rsbuild provided native support for these features.
2. Styling and CSS Handling
- Challenge: Differences in how CSS modules, preprocessors (like Less), and global styles are handled can lead to unexpected styling issues.
- Guideline: Review your styling approach, especially for global overrides and CSS module conventions. Test your styles thoroughly after migration and adjust configurations as needed.
- Example: Some global
Less
overrides for Ant Design were not being applied as expected due to differences in how global selectors were processed, which required us to adjust our style definitions and loader settings.
3. Micro-Frontend Integration
- Challenge: Ensuring consistent and singleton usage of shared dependencies across micro-frontends is critical to avoid runtime issues.
- Guideline: Align dependency versions and configurations across all MFEs, and use best practices for sharing libraries and assets.
- Example: We encountered issues with multiple instances of libraries like
dayjs
being loaded in different MFEs, which led to inconsistent behavior in date pickers.
4. Third-Party Library Support
- Challenge: Some third-party libraries or plugins may not work out of the box with Rsbuild.
- Guideline: Check the compatibility of critical libraries early in the migration process. Look for modern, actively maintained alternatives if needed, and plan for isolated testing of such dependencies.
- Example: Our existing code editor integration relied on a plugin that was not compatible with Rsbuild, prompting us to migrate to a newer, supported alternative.
Deployment Strategy π
Pre-Migration Preparation
Before starting the Rsbuild migration, we established a comprehensive deployment strategy to ensure minimal disruption:
Staged Deployment Approach
Phase 1: Internal Testing (Week 1-2)
- We first tested the
Rsbuild
changes in the local dev server - Comprehensive testing across all features and user flows
- Performance Benchmarking: Measured build times, bundle sizes, and runtime performance
Phase 2: Staging Environment (Week 3)
- Deployed the
Rsbuild
version to the staging environment - QA Testing: Manual QA testing and automation suites were run to identify any issues.
- Integration Testing: Verified all micro-frontend integrations worked correctly
Phase 3: Beta Environment (Week 4)
- Deployed the
Rsbuild
version to the beta environment - QA Testing: Manual QA testing and automation suites were run on more production-level data.
- Error Rate Monitoring: Closely monitored error rates and performance metrics
Phase 4: Production Rollout (Week 5)
- Maintenance window: Although we did not expect any downtime with this migration, we decided to provide a maintenance window communication to ensure safety and a better customer experience. The maintenance window was strategically chosen by analyzing user traffic data to ensure itβs during non-critical business hours.
- Real-time Monitoring: Continuous error monitoring during the rollout period
- Rollback plan: We already have a rollback strategy for deployments, so we decided to stick with it.
Post-Deployment Validation
Automated Health Checks
- Smoke Tests: Automated tests for critical user flows
- Performance Tests: Automated performance regression tests
Manual Validation Checklist
- [ ] All major user flows work correctly
- [ ] Performance metrics meet or exceed baseline
- [ ] Error rates remain within acceptable thresholds
- [ ] All integrations (APIs, third-party services) function properly
Lessons Learned from Deployment
What Went Well
- Staged Approach: Gradual rollout helped identify issues early
- Monitoring: Comprehensive monitoring caught issues before they affected users
- Rollback Plan: Having a solid rollback strategy provided confidence during deployment
Areas for Improvement
- Testing Coverage: Could have benefited from more automated integration tests
- Performance Baselines: Should have established clearer performance benchmarks
- Communication: Could have improved stakeholder communication during the rollout
Results π
Build Time Improvements
Production Build: Reduced from ~8 minutes to ~3 minutes (>60% improvement)
Developer Experience
- Faster Feedback Loop: Quicker development iterations
Conclusion
Our migration from CRA to Rsbuild was a significant success, resulting in 50%+ improvement in build times and a more modern, maintainable build system. While the migration presented several challenges, the benefits far outweighed the effort:
- Faster Development: Reduced build times significantly improved developer productivity
- Modern Tooling: Access to the latest web development features and optimizations
- Future-Proof: Active development and community support ensure long-term viability
The key to success was a well-planned migration strategy, thorough testing, and addressing issues incrementally. For teams considering similar migrations, we recommend:
- Start with the official migration guide
- Plan for plugin compatibility issues
- Implement a staged rollout strategy
- Monitor performance metrics throughout
- Have rollback plans ready
The migration has positioned our team for better performance, faster development cycles, and access to modern web development tools. The investment in migration has already paid dividends in improved developer experience and deployment efficiency.
Whatβs Next?
Here are some of the next steps we are considering:
-
Adopting Faster Package Managers
- We are exploring switching from
npm
topnpm
for dependency management.
- We are exploring switching from
-
Optimizing Dependencies
- Regularly audit and prune unused dependencies/code, and consider splitting large dependencies or lazy-loading rarely used modules to keep the build lean.
-
Fine-Tuning Module Federation
- Analyze our micro-frontend boundaries and shared dependencies to ensure optimal code splitting and minimal duplication across MFEs, reducing both build and runtime bundle sizes.
-
Parallelizing CI/CD Steps
- Refactor CI/CD pipelines to maximize parallelism, such as running linting, testing, and building steps concurrently where possible.
-
Profiling and Monitoring
- Continuously profile build performance using tools like Webpack Bundle Analyzer or Rsbuildβs Rsdoctor to identify new bottlenecks as the codebase evolves.