Create React App を rsbuild に変えてみる

古の CRA (Create React App) project を久々に触ったら react-scripts が動かなくなっていたので、この際 rsbuild に乗り換えてみる。
公式 Doc に migration guide 載ってるのでこれに従って進めていく。

Installing Dependencies
react-scripts を取り除いて、rsbuild に必要な dependencies 入れる。
npm remove react-scripts
npm add @rsbuild/core @rsbuild/plugin-react -D

Updating npm scripts
package.json npm scripts を rsbuild のものに置き換え。
{
"scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "eject": "react-scripts eject"
+ "start": "rsbuild dev",
+ "build": "rsbuild build",
+ "preview": "rsbuild preview"
}
}

rsbuild preview
The rsbuild preview command is used to preview the production build outputs locally. Note that you need to execute the rsbuild build command beforehand to generate the build outputs.
preview
command は eject に対応してるものではないので注意。
producion build を local で実行するためのもの。

Creating Configuration File
rsbuild 用の config file rsbuild.config.ts
を以下の内容で作成。
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
export default defineConfig({
plugins: [pluginReact()],
});

HTML Template
html.template
option に "public/index.html" を指定する。
export default defineConfig({
+ html: {
+ template: './public/index.html',
+ },
//...
});

%PUBLIC_URL%
の置き換え
index.html で %PUBLIC_URL%
を利用している場合、<%= assetPrefix %>
に置き換えればOK。
- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+ <link rel="icon" href="<%= assetPrefix %>/favicon.ico" />
html-rspack-plugin の templateParameters の機能。
config file で指定した parameters を html で利用するためのもの。
assetPrefix
はデフォルトで利用できる parameters の一つ。

Output Directory
output.distPath.root
に output directory を設定。CRA デフォルトの値をそのまま利用している場合は、 "dist" を指定すればOK。
export default defineConfig({
//...
+ output: {
+ distPath: {
+ root: 'build',
+ },
+ },
//...
});

Environment Variables
CRA では REACT_APP_
から始まる環境変数を client code で利用できるわけだが、この機能を利用している場合の対応。
rsbuild の loadEnv を利用すればOK。
import { defineConfig, loadEnv } from '@rsbuild/core';
const { publicVars } = loadEnv({ prefixes: ['REACT_APP_'] });
export default defineConfig({
source: {
define: publicVars,
},
});

souce.defined
Replaces variables in your code with other values or expressions at compile time. This can be useful for allowing different behavior between development builds and production builds.
webpack の DefinePlugin 同等のやつ。内部では rspack の DefinePlugiin を利用している。
export default {
source: {
define: {
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify('5fa3b9'),
BROWSER_SUPPORTS_HTML5: true,
TWO: '1 + 1',
'typeof window': JSON.stringify('object'),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'import.meta': { test: undefined },
},
},
};

最終的な rsbuild.config.ts
import { defineConfig, loadEnv } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
const { publicVars } = loadEnv({ prefixes: ['REACT_APP_'] });
export default defineConfig({
plugins: [pluginReact()],
html: {
template: './public/index.html',
},
output: {
distPath: {
root: 'build',
},
},
source: {
define: publicVars,
},
});

source map
CRA の GENERATE_SOURCEMAP
を利用して sourcemap を出力している場合の対応。
output.sourceMap
で指定可能。
//...
export default defineConfig({
output: {
//...
+ sourceMap: {
+ js: 'source-map',
+ },
},
//...
});