> For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt.

# Create React App

本章节介绍如何将 [Create React App](https://github.com/facebook/create-react-app)（简称 CRA）或 [CRACO](https://craco.js.org/) 项目迁移到 Rsbuild。

:::tip CRA eject
如果你的项目已经执行了 CRA 的 `eject` 命令，那么本文档的大部分内容将不再适用。

CRA 项目在 eject 后，更近似于直接使用 webpack 的项目，因此可参考 [webpack 迁移指南](/zh/guide/migration/webpack.md)。

:::

## 使用 Agent Skills

使用支持 Skills 的 coding agent 时，可安装 [migrate-to-rsbuild](https://github.com/rstackjs/agent-skills#migrate-to-rsbuild) 技能来辅助完成迁移流程。

```bash
npx skills add rstackjs/agent-skills --skill migrate-to-rsbuild
```

安装后，让 coding agent 协助完成迁移即可。

## 安装依赖

首先，将 CRA 的 npm 依赖替换为 Rsbuild 的依赖。

- 移除 CRA 的依赖：


```sh [npm]
npm remove react-scripts
```

```sh [yarn]
yarn remove react-scripts
```

```sh [pnpm]
pnpm remove react-scripts
```

```sh [bun]
bun remove react-scripts
```

```sh [deno]
deno remove npm:react-scripts
```

> 对于使用 CRACO 的项目，你还可以移除 `@craco/craco` 依赖。

- 安装 Rsbuild 的依赖：


```sh [npm]
npm add @rsbuild/core @rsbuild/plugin-react -D
```

```sh [yarn]
yarn add @rsbuild/core @rsbuild/plugin-react -D
```

```sh [pnpm]
pnpm add @rsbuild/core @rsbuild/plugin-react -D
```

```sh [bun]
bun add @rsbuild/core @rsbuild/plugin-react -D
```

```sh [deno]
deno add npm:@rsbuild/core npm:@rsbuild/plugin-react -D
```

## 更新 npm scripts

下一步，将 package.json 中的 npm scripts 更新为 Rsbuild 的 CLI 命令。

```json title="package.json"
{
  "scripts": {
    "start": "react-scripts start", // [!code --]
    "build": "react-scripts build", // [!code --]
    "eject": "react-scripts eject", // [!code --]
    "start": "rsbuild", // [!code ++]
    "build": "rsbuild build", // [!code ++]
    "preview": "rsbuild preview" // [!code ++]
  }
}
```

:::tip
Rsbuild 没有内置测试框架，因此没有提供用于替换 `react-scripts test` 的命令，可直接使用 [Rstest](https://github.com/web-infra-dev/rstest)、Jest 或 Vitest 等测试框架。查看 [测试](/zh/guide/advanced/testing.md) 了解更多。
:::

## 创建配置文件

在 package.json 的同级目录下创建 Rsbuild 的配置文件 `rsbuild.config.ts`，并添加以下内容：

```ts title="rsbuild.config.ts"
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';

export default defineConfig({
  plugins: [pluginReact()],
});
```

## HTML 模板

CRA 默认使用 `public/index.html` 文件作为 HTML 模板。在 Rsbuild 中，通过 [html.template](/zh/config/html/template.md) 指定 HTML 模板：

```ts title="rsbuild.config.ts"
export default defineConfig({
  html: {
    template: './public/index.html',
  },
});
```

在 HTML 模板中，如果使用了 CRA 的 `%PUBLIC_URL%` 变量，请替换为 Rsbuild 的 [assetPrefix 变量](/zh/config/html/template-parameters.md)，并使用斜杠进行连接：

```html
<!-- [!code --] -->
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<!-- [!code ++] -->
<link rel="icon" href="<%= assetPrefix %>/favicon.ico" />
```

这样就完成了从 CRA 到 Rsbuild 的基本迁移，此时你可以执行 `npm run start` 命令来尝试启动开发服务器。

## 构建产物目录

CRA 默认会将构建产物输出到 `build` 目录，而 Rsbuild 的默认构建产物目录为 `dist`。

配置 Rsbuild 的 [output.distPath.root](/zh/config/output/dist-path.md) 选项，将目录修改为 `build`，与 CRA 保持一致：

```ts title="rsbuild.config.ts"
export default {
  output: {
    distPath: {
      root: 'build',
    },
  },
};
```

> 更多细节请参考[构建产物](/zh/guide/basic/output-files.md)章节。

## 使用 CSS 预处理器

Rsbuild 通过插件来支持 Sass 和 Less 等 CSS 预处理器，使用方式请参考：

- [Sass 插件](/zh/plugins/list/plugin-sass.md)
- [Less 插件](/zh/plugins/list/plugin-less.md)
- [Stylus 插件](https://github.com/rstackjs/rsbuild-plugin-stylus)

## 使用 SVGR

如果 CRA 项目使用了 "SVG 转 React 组件" 功能（即 [SVGR](https://react-svgr.com/)），还需安装 Rsbuild 的 SVGR 插件。

比如使用了以下用法：

```jsx
import { ReactComponent as Logo } from './logo.svg';

const App = () => (
  <div>
    <Logo />
  </div>
);
```

只需要安装和注册 `@rsbuild/plugin-svgr` 即可：

```ts title="rsbuild.config.ts"
import { pluginSvgr } from '@rsbuild/plugin-svgr';

export default {
  plugins: [pluginSvgr({ mixedImport: true })],
};
```

请参考 [SVGR 插件](/zh/plugins/list/plugin-svgr.md) 文档了解如何在 Rsbuild 中使用 SVGR。

## 配置迁移

以下是 [CRA 配置](https://create-react-app.dev/docs/advanced-configuration/)对应的 Rsbuild 配置：

| CRA                        | Rsbuild                                                                                                     |
| -------------------------- | ----------------------------------------------------------------------------------------------------------- |
| HOST                       | [server.host](/zh/config/server/host.md)                                                                    |
| PORT                       | [server.port](/zh/config/server/port.md)                                                                    |
| HTTPS                      | [server.https](/zh/config/server/https.md)                                                                  |
| WDS\_SOCKET\_HOST          | [dev.client.host](/zh/config/dev/client.md)                                                                 |
| WDS\_SOCKET\_PATH          | [dev.client.path](/zh/config/dev/client.md)                                                                 |
| WDS\_SOCKET\_PORT          | [dev.client.port](/zh/config/dev/client.md)                                                                 |
| PUBLIC\_URL                | [dev.assetPrefix](/zh/config/dev/asset-prefix.md) / [output.assetPrefix](/zh/config/output/asset-prefix.md) |
| BUILD\_PATH                | [output.distPath](/zh/config/output/dist-path.md)                                                           |
| GENERATE\_SOURCEMAP        | [output.sourceMap](/zh/config/output/source-map.md)                                                         |
| IMAGE\_INLINE\_SIZE\_LIMIT | [output.dataUriLimit](/zh/config/output/data-uri-limit.md)                                                  |
| FAST\_REFRESH              | [dev.hmr](/zh/config/dev/hmr.md)                                                                            |
| TSC\_COMPILE\_ON\_ERROR    | [@rsbuild/plugin-type-check](https://github.com/rstackjs/rsbuild-plugin-type-check)                         |

说明：

- 上述表格尚未覆盖到 CRA 的所有配置，欢迎补充。

## 编译 node\_modules

CRA 默认会使用 Babel 编译 node\_modules 中的依赖，但 Rsbuild 则不会，这是为了避免二次编译带来的性能损耗和潜在的编译错误。

如果你需要处理 node\_modules 中依赖引起的语法兼容性问题，可以使用 [source.include](/zh/config/source/include.md#compile-node_modules) 配置项来编译 node\_modules。

```ts title="rsbuild.config.ts"
export default {
  source: {
    // 编译所有 JS 文件并排除 core-js
    include: [{ not: /[\\/]core-js[\\/]/ }],
  },
};
```

## 环境变量

CRA 默认会将 `REACT_APP_` 开头的环境变量注入到 client 代码中，而 Rsbuild 默认会注入 `PUBLIC_` 开头的环境变量（参考 [public 变量](/zh/guide/advanced/env-vars.md#public-variables)）。

为了兼容 CRA 的行为，可手动调用 Rsbuild 提供的 [loadEnv](/zh/api/javascript-api/core.md#loadenv) 方法来读取 `REACT_APP_` 开头的环境变量，并通过 [source.define](/zh/config/source/define.md) 配置项注入到 client 代码中。

```ts title="rsbuild.config.ts"
import { defineConfig, loadEnv } from '@rsbuild/core';

const { publicVars } = loadEnv({ prefixes: ['REACT_APP_'] });

export default defineConfig({
  source: {
    define: publicVars,
  },
});
```

值得注意的是，CRA 允许在代码中访问完整的 `process.env` 对象，也允许对 `process.env` 进行解构。而 Rsbuild 出于包体积和安全的考虑，并没有注入完整的 `process.env` 对象。

```ts title="src/index.js"
// CRA 中可以这样访问
const { PUBLIC_URL } = process.env;
console.log(PUBLIC_URL);
console.log(process.env);
```

在 Rsbuild 中，可通过 [source.define](/zh/config/source/define.md) 配置项设置 `process.env`，读取 `loadEnv` 方法返回的 `rawPublicVars`，来允许以上用法：

```ts title="rsbuild.config.ts"
import { defineConfig, loadEnv } from '@rsbuild/core';

const { publicVars, rawPublicVars } = loadEnv({ prefixes: ['REACT_APP_'] });

export default defineConfig({
  source: {
    define: {
      ...publicVars,
      'process.env': JSON.stringify(rawPublicVars),
    },
  },
});
```

## 引用未知资源

在 CRA 中，如果你引用了一个构建工具无法识别的资源，CRA 默认会将该文件输出到 `build/static/media` 目录下，比如 `model.gltf` 文件：

```js title="index.js"
import model from './model.gltf';
```

在 Rsbuild 中，遇到无法识别的资源时，Rsbuild 会输出报错日志，类似于：

```
You may need an appropriate loader to handle this file type.
```

为了解决该错误，可采用以下方法：

- 使用 [tools.rspack](/zh/config/tools/rspack.md) 配置一个合适的 loader 来处理该类型的资源。
- 使用 [tools.rspack](/zh/config/tools/rspack.md) 配置 [asset modules](https://rspack.rs/zh/guide/features/asset-module) 规则来处理该类型的资源。

比如，可添加以下 asset modules 配置，来保持与 CRA 相同的输出结果：

```ts title="rsbuild.config.ts"
export default {
  tools: {
    rspack: {
      module: {
        rules: [
          {
            // 匹配 .png 文件
            // 你可以调整该正则表达式，以匹配不同类型的文件
            test: /\.png$/,
            type: 'asset/resource',
            generator: {
              filename: 'static/media/[name].[hash][ext]',
            },
          },
        ],
      },
    },
  },
};
```

## 移除 react-app-polyfill

CRA 提供了 [react-app-polyfill](https://npmjs.com/package/react-app-polyfill) 来手动注入 polyfill 代码。

在 Rsbuild 项目中，可移除 react-app-polyfill 相关的依赖和代码，因为 Rsbuild 会自动读取 browserslist 配置，并允许通过 [output.polyfill](/zh/config/output/polyfill.md) 配置项启用 polyfill 注入。

1. 移除 `react-app-polyfill` 引用：

```ts title="src/index.js"
import 'react-app-polyfill/ie11'; // [!code --]
import 'react-app-polyfill/stable'; // [!code --]
```

2. 安装 `core-js`：


```sh [npm]
npm add core-js
```

```sh [yarn]
yarn add core-js
```

```sh [pnpm]
pnpm add core-js
```

```sh [bun]
bun add core-js
```

```sh [deno]
deno add npm:core-js
```

3. 配置 [output.polyfill](/zh/config/output/polyfill.md)：

```ts title="rsbuild.config.ts"
export default {
  output: {
    polyfill: 'usage',
  },
};
```

> 参考 [浏览器兼容性](/zh/guide/advanced/browser-compatibility.md) 来了解 Rsbuild 是如何处理 polyfill 的。

## 配置 ESLint

CRA 默认使用 ESLint 检查代码质量。Rsbuild 默认不包含代码检查功能，但可在 `package.json` 中添加单独的 npm script 来运行 ESLint。

首先安装 [eslint](https://eslint.org/) 和 [eslint-config-react-app](https://npmjs.com/package/eslint-config-react-app)。使用 ESLint v8 以保持与 CRA 一致：


```sh [npm]
npm add eslint@8 eslint-config-react-app -D
```

```sh [yarn]
yarn add eslint@8 eslint-config-react-app -D
```

```sh [pnpm]
pnpm add eslint@8 eslint-config-react-app -D
```

```sh [bun]
bun add eslint@8 eslint-config-react-app -D
```

```sh [deno]
deno add npm:eslint@8 npm:eslint-config-react-app -D
```

然后在 `package.json` 中添加 `lint` 命令，并确认项目中包含 `eslintConfig` 配置或独立的 ESLint 配置文件：

```json title="package.json"
{
  "scripts": {
    "lint": "eslint src"
  },
  "eslintConfig": {
    "extends": ["react-app", "react-app/jest"]
  }
}
```

然后运行 `npm run lint` 执行 ESLint 检查。

### 在构建中运行 ESLint

除了在 `package.json` 中添加 `lint` 命令，也可添加 [@rsbuild/plugin-eslint](https://github.com/rstackjs/rsbuild-plugin-eslint) 插件来保持与 CRA 相同的行为。

`@rsbuild/plugin-eslint` 插件允许你在构建过程中执行 ESLint 检查。

```ts title="rsbuild.config.ts"
import { pluginEslint } from '@rsbuild/plugin-eslint';

export default {
  plugins: [pluginEslint()],
};
```

注册后，在开发 (`npm run dev`) 和生产构建 (`npm run build`) 过程中，ESLint 会自动运行。插件会在控制台输出 ESLint 警告和错误。

:::warning
我们并不推荐使用 `@rsbuild/plugin-eslint`，因为在构建过程中运行 ESLint 检查会显著增加构建时间。更推荐的做法是使用单独的 `lint` 命令来执行 ESLint 检查。
:::

## 读取 jsconfig.json

在非 TypeScript 项目中，CRA 支持读取 jsconfig.json 中的 `paths` 字段作为路径别名。

如果你需要在 Rsbuild 中使用该特性，可以参考 [路径别名 - jsconfig.json](/zh/guide/advanced/alias.md#jsconfigjson)。

## CRACO 迁移

如果你的项目使用了 [CRACO](https://craco.js.org) 来覆盖 CRA 的配置，可以参考下表来迁移：

| CRACO                                                                                           | Rsbuild                                                                             |
| ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| [webpack.configure](https://craco.js.org/docs/configuration/webpack/#webpackconfigure)          | [tools.rspack](/zh/config/tools/rspack.md)                                          |
| [webpack.alias](https://craco.js.org/docs/configuration/webpack/#webpackalias)                  | [resolve.alias](/zh/config/resolve/alias.md)                                        |
| [webpack.plugins.add](https://craco.js.org/docs/configuration/webpack/#webpackplugins)          | [appendPlugins of tools.rspack](/zh/config/tools/rspack.md#appendplugins)           |
| [webpack.plugins.remove](https://craco.js.org/docs/configuration/webpack/#webpackpluginsremove) | [removePlugin of tools.rspack](/zh/config/tools/rspack.md#removeplugin)             |
| [style.modules](https://craco.js.org/docs/configuration/style/#stylemodules)                    | [output.cssModules](/zh/config/output/css-modules.md)                               |
| [style.css](https://craco.js.org/docs/configuration/style/#stylecss)                            | [tools.cssLoader](/zh/config/tools/css-loader.md)                                   |
| [style.sass](https://craco.js.org/docs/configuration/style/#stylesass)                          | [Sass 插件](/zh/plugins/list/plugin-sass.md)                                          |
| [style.postcss](https://craco.js.org/docs/configuration/style/#stylepostcss)                    | [tools.postcss](/zh/config/tools/postcss.md)                                        |
| [babel](https://craco.js.org/docs/configuration/babel/)                                         | [Babel 插件](/zh/plugins/list/plugin-babel.md)                                        |
| [typescript](https://craco.js.org/docs/configuration/typescript/)                               | [@rsbuild/plugin-type-check](https://github.com/rstackjs/rsbuild-plugin-type-check) |
| [devServer](https://craco.js.org/docs/configuration/devserver/)                                 | [server configs](/zh/config/index.md)                                               |

### 示例

下面是一个从 `webpack.configure` 迁移到 `tools.rspack` 的例子：

- 迁移前：

```js title="craco.config.js"
const { whenDev } = require('@craco/craco');

module.exports = {
  webpack: {
    configure: {
      resolve: {
        mainFields: ['browser', 'module', 'main'],
      },
    },
    plugins: [...whenDev(() => [new MyWebpackPlugin()], [])],
  },
};
```

- 迁移后：

```ts title="rsbuild.config.ts"
export default {
  tools: {
    rspack: {
      resolve: {
        mainFields: ['browser', 'module', 'main'],
      },
      plugins:
        process.env.NODE_ENV === 'development' ? [new MyWebpackPlugin()] : [],
    },
  },
};
```

## 内容补充

当前文档只涵盖了迁移过程的部分事项，如果你发现有合适的内容可以补充，欢迎通过 pull request 来完善文档 🤝。

> Rsbuild 的文档位于 [rsbuild/website](https://github.com/web-infra-dev/rsbuild/tree/main/website) 目录。
