Create React App

本章节介绍如何将 Create React App(简称 CRA)或 CRACO 项目迁移到 Rsbuild。

CRA eject

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

CRA 项目在 eject 后,更近似于直接使用 webpack 的项目,因此你可以参考 webpack 迁移指南

安装依赖

首先你需要把 CRA 的 npm 依赖替换为 Rsbuild 的依赖。

  • 移除 CRA 的依赖:
npm
yarn
pnpm
bun
npm remove react-scripts

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

  • 安装 Rsbuild 的依赖:
npm
yarn
pnpm
bun
npm add @rsbuild/core @rsbuild/plugin-react -D

更新 npm scripts

下一步,你需要把 package.json 中的 npm scripts 更新为 Rsbuild 的 CLI 命令。

package.json
{
  "scripts": {
-   "start": "react-scripts start",
-   "build": "react-scripts build",
-   "eject": "react-scripts eject"
+   "start": "rsbuild dev",
+   "build": "rsbuild build",
+   "preview": "rsbuild preview"
  }
}
TIP

Rsbuild 未集成测试框架,因此没有提供用于替换 react-scripts test 的命令,你可以直接使用 Jest 或 Vitest 等测试框架。你可以参考 Rsbuild react-jest 示例项目进行配置。

创建配置文件

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

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 来指定 HTML 模板:

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

在 HTML 模板中,如果使用了 CRA 的 %PUBLIC_URL% 变量,请替换为 Rsbuild 的 assetPrefix 变量,并使用斜杠进行连接:

-  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+  <link rel="icon" href="<%= assetPrefix %>/favicon.ico" />

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

构建产物目录

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

你可以配置 Rsbuild 的 output.distPath.root 选项,将目录修改为 build,与 CRA 保持一致:

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

更多细节请参考构建产物目录章节。

使用 SVGR

如果你使用了 CRA 的 "SVG 转 React 组件" 功能(即 SVGR),那么还需要安装 Rsbuild 的 SVGR 插件。

比如使用了以下用法:

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

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

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

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

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

请参考 SVGR 插件 文档了解如何在 Rsbuild 中使用 SVGR。

配置迁移

以下是 CRA 配置对应的 Rsbuild 配置:

CRA Rsbuild
HOST server.host
PORT server.port
HTTPS server.https
WDS_SOCKET_HOST dev.client.host
WDS_SOCKET_PATH dev.client.path
WDS_SOCKET_PORT dev.client.port
PUBLIC_URL dev.assetPrefix / output.assetPrefix
BUILD_PATH output.distPath
GENERATE_SOURCEMAP output.sourceMap
IMAGE_INLINE_SIZE_LIMIT output.dataUriLimit
FAST_REFRESH dev.hmr
TSC_COMPILE_ON_ERROR Type Check Plugin

说明:

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

编译 node_modules

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

如果你需要处理 node_modules 中依赖引起的语法兼容性问题,可以使用 source.include 配置项来编译 node_modules。

环境变量

CRA 默认会将 REACT_APP_ 开头的环境变量注入到 client 代码中,而 Rsbuild 默认会注入 PUBLIC_ 开头的环境变量(参考 public 变量)。

为了兼容 CRA 的行为,你可以手动调用 Rsbuild 提供的 loadEnv 方法来读取 REACT_APP_ 开头的环境变量,并通过 source.define 配置项注入到 client 代码中。

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

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

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

引用未知资源

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

index.js
import document from './document.pdf';

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

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

为了解决该错误,你可以采用以下方法:

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

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 来手动注入 polyfill 代码。

在 Rsbuild 项目中,你可以移除 react-app-polyfill 相关的依赖和代码,因为 Rsbuild 会自动读取 browserslist 配置,并按需注入 polyfill 代码。

src/index.js
- import 'react-app-polyfill/ie11';
- import 'react-app-polyfill/stable';

你可以参考 浏览器兼容性 来了解 Rsbuild 是如何处理 polyfill 的。

读取 jsconfig.json

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

如果你需要在 Rsbuild 中使用该特性,可以使用 source.tsconfigPath 选项,使 Rsbuild 能够识别 jsconfig.json 中的 paths 字段。

rsbuild.config.mjs
export default {
  source: {
    tsconfigPath: './jsconfig.json',
  },
};

CRACO 迁移

如果你的项目使用了 CRACO 来覆盖 CRA 的配置,可以参考下表来迁移:

CRACO Rsbuild
webpack.configure tools.rspack
webpack.alias source.alias
webpack.plugins tools.rspack.appendPlugins
webpack.plugins.remove tools.rspack.removePlugin
style.modules output.cssModules
style.css tools.cssLoader
style.sass tools.sass
style.postcss tools.postcss
babel Babel Plugin
typescript Type Check Plugin
devServer server configs

示例

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

  • 迁移前:
craco.config.js
const { whenDev } = require('@craco/craco');

module.exports = {
  webpack: {
    configure: {
      resolve: {
        mainFields: ['browser', 'module', 'main'],
      },
    },
    plugins: [...whenDev(() => [new MyWebpackPlugin()], [])],
  },
};
  • 迁移后:
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 目录。