How I migrated from CRA to RSBuild
Tags: webdev, react, javascript
Published: 2024-01-13 09:14:30

I recently revisited an old personal React project and discovered it was built using Create React App (CRA). 
While considering a switch to Vite for its performance benefits, I stumbled upon RSBuild, which, according to its documentation, is even faster: [RSBuild Performance](https://rsbuild.dev/guide/start/#-performance).

## Why RSBuild ?

Here are my key reasons for choosing RSBuild:

1. **Performance**: It's designed for speed.
2. **CRA is Outdated**: The last CRA release was on **[April 12, 2022](https://github.com/facebook/create-react-app/releases/tag/v5.0.1)**
3. **Migration Guide**: RSBuild provides a detailed guide for seamless migration.
4. **Batteries included**: I don’t need to worry about additional integration, RSBuild covers what I need

## Few words about RSBuild

RSBuild is based on RSPack, a Rust-written bundler optimized for web development. It's user-friendly and minimizes configuration needs.

Being framework-agnostic, RSBuild offers a robust plugin system. For React integration, I simply added `plugins: [pluginReact()],` in `rsbuild.config.ts`.

RSBuild's comprehensive documentation includes examples and detailed guides for migrating from:

- Webpack
- Create React App (CRA)
- Vue CLI
- Modern Builder

## CSS

In my CRA project, I utilized `css-modules`. Fortunately, RSBuild supports it out of the box, so no extra effort was required on my part.

## Environment Variables

My project only had two environments, and I wanted to move away from the `REACT_APP` prefix. RSBuild allowed me to easily switch to using `PUBLIC` as the prefix, treating all my environment variables as public, which suited my project's needs.

## Testing

RSBuild doesn't integrate testing frameworks directly. Thus, there's no straight swap for `react-scripts test`. I set up Jest independently. To manage this, I used a separate `.env.test` file for test configurations. To avoid additional tooling with `ts-node`, I relied on standard CJS files:

I have stick with good old CJS files:

- The first file is for loading environment variables:
```javascript
// src/config/loadEnvs.js

const dotenv = require('dotenv')
const path = require('path')

const loadEnvs = (mode) => {
  const testOptions = mode === 'test' && {
    path: path.resolve(process.cwd(), '.env.test'),
  }

  try {
    return dotenv.config(testOptions)
  } catch (err) {
    console.log(err, 'Missing or wrong env files')
  }
}

module.exports = { loadEnvs }
```

- The second file is used to load the appropriate environment variables and run Jest with arguments specified in package.json:

```javascript
const { loadEnvs } = require('./loadEnvs')

loadEnvs('test')

const argv = process.argv.slice(2)

const jest = require('jest')

jest.run(argv)
```

- Finally, I updated the test commands in package.json to align with these changes.

```javascript
const { loadEnvs } = require('./loadEnvs')

loadEnvs('test')

const argv = process.argv.slice(2)

const jest = require('jest')

jest.run(argv)
```

## Results

Overall the migration took me around 30 minutes, which is quite fast in my opinion - even fact that my app is rather small one. 
The docs are great I have easily found, what I needed, big shoutout to the RSBuild Team ❤️

The performance improvements with RSBuild were huge:

 - Local build time: Reduced to about **0.3 seconds** 🔥.
 - GitHub CI: Reduced to about **0.8 seconds**, which is incredibly fast 🔥.
 - Local development server readiness: Around **0.25 seconds**.

![RSBuild took 0.8s to build project on CI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xlv2vnw8gqrjcbvrs6rl.png)

In contrast, with CRA:

- Local build time: Typically **7 to 9 seconds**. 
- GitHub CI: Around **26 seconds**.
- Local development server readiness: Between **3 to 5 seconds**.



![CRA took 26 seconds to build project on CI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3rwj1a80nl8y17oo2x5i.png)

## Other migration cases

I also explored other developers' experiences with migrating to RSBuild, as shared on Twitter:

- https://twitter.com/acemarke/status/1741298626628861992
- https://twitter.com/ScriptedAlchemy/status/1741058988094230528