# Basic CRA with Rsbuild
:::tip Demo Reference
Check out the example project list here: [Rsbuild CRA](https://github.com/module-federation/module-federation-examples/tree/master/cra)
:::
## Setup Environment
Before getting started, you will need to install [Node.js](https://nodejs.org/), and ensure that your Node.js version >= 16. **We recommend using the LTS version of Node.js 20.**
You can check the currently used Node.js version with the following command:
```bash
node -v
```
If you do not have Node.js installed in your current environment, or the installed version is too low, you can use [nvm](https://github.com/nvm-sh/nvm) or [fnm](https://github.com/Schniz/fnm) to install the required version.
Here is an example of how to install the Node.js 20 LTS version via nvm:
```bash
# Install the long-term support version of Node.js 20
nvm install 20 --lts
# Make the newly installed Node.js 20 as the default version
nvm alias default 20
# Switch to the newly installed Node.js 20
nvm use 20
```
## Step 1: Setup React Applications
### Create React Project
You can use `create-rsbuild` to create a project with Rsbuild + React. Just execute the following command:
```sh [npm]
npm create rsbuild@latest
```
```sh [yarn]
yarn create rsbuild
```
```sh [pnpm]
pnpm create rsbuild@latest
```
```sh [bun]
bun create rsbuild@latest
```
#
### Create App 1
```bash
create rsbuild@latest
"Input target folder":
> mfe1
"Select framework":
> React
"Select language":
> TypeScript
```
### Create App 2
```bash
create rsbuild@latest
"Input target folder":
> mfe2
"Select framework":
> React
"Select language":
> TypeScript
```
### Install
```bash
cd mfe1
pnpm i
```
```bash
cd mfe2
pnpm i
```
### Use React in an existing project
To compile React, you need to register the Rsbuild [React Plugin](https://rsbuild.dev/plugins/list/plugin-react). The plugin will automatically add the necessary configuration for React builds.
For example, register in `rsbuild.config.ts`:
```ts title="rsbuild.config.ts"
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
export default defineConfig({
plugins: [pluginReact()],
});
```
:::tip
For projects using Create React App, you can refer to the [CRA Migration Guide](https://rsbuild.dev/guide/migration/cra).
:::
Ensure that Webpack version 5 or above is installed by checking the installation report provided by Yarn.
## Step 2: Installing Module Federation Build Plugin
```bash
pnpm add @module-federation/enhanced
pnpm add @module-federation/rsbuild-plugin --save-dev
```
## Step 3: Update Entry Files
In both applications, rename the `index.js` file to `bootstrap.js`. This change allows `bootstrap.js` to load asynchronously, which is essential for Module Federation to function correctly between the two applications.
```bash
mv src/index.tsx src/bootstrap.tsx
```
Update the contents of bootstrap.tsx to the following:
```typescript
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
```
Now, create a new `index.tsx` file in both applications with the following content to import `bootstrap.tsx`:
```typescript
import('./bootstrap');
```
## Step 4: Create and Expose
Now, create a component to expose from `MFE2`
### 4.1 Create Button Component
In `MFE2`, create a new file named `Button.tsx` in the src directory with the following content:
```typescript
const Button = () => (
<button>MFE2 Button</button>
);
export default Button;
```
### 4.2 Update App.tsx
Update `App.tsx` in `MFE2` to import and render the Button component:
```typescript
import './App.css';
import Button from './Button';
const App = () => {
return (
<div className="content">
<h1>MFE2</h1>
<Button />
</div>
);
};
export default App;
```
## Step 5: Configure Rsbuild in MFE2
First create `module-federation.config.ts` in file in the root directory of `MFE2` with the following configuration:
```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/rsbuild-plugin';
export default createModuleFederationConfig({
name: 'remote',
exposes: {
'./Button': './src/Button',
},
filename: 'remoteEntry.js',
shared: {
...dependencies,
react: {
singleton: true,
},
'react-dom': {
singleton: true,
},
},
});
```
And then modify the `rsbuild.config.ts` file in the root directory of `MFE2` with the following configuration:
```diff title="rsbuild.config.ts"
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
+ import { pluginModuleFederation } from '@module-federation/rsbuild-plugin';
+ import mfConfig from './module-federation.config';
export default defineConfig({
server: {
port: 3002
},
plugins: [
pluginReact()
+ pluginModuleFederation(mfConfig)
]
});
```
## Step 6: Consume Remote Module
Consume the exposed module from `MFE2` in `MFE1`
### 6.1 Update App.tsx
Update `App.tsx` in `MFE1` to import and render the `MFE2` Button component:
```typescript
import React from 'react';
import Button from 'remote/Button'; // federated import
function App() {
return (
<div>
<h1>MFE1</h1>
<Button />
</div>
);
}
export default App;
```
### Step 6.2: Configure Rsbuild in MFE1
First create `module-federation.config.ts` in file in the root directory of `MFE1` with the following configuration:
```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/rsbuild-plugin';
export default createModuleFederationConfig({
name: 'host',
remotes: {
remote: 'remote@http://localhost:3002/remoteEntry.js',
},
shared: {
react: {
singleton: true,
},
'react-dom': {
singleton: true,
},
},
});
```
And then modify the `rsbuild.config.ts` file in the root directory of `MFE1` with the following configuration:
```diff title="rsbuild.config.ts"
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
+ import { pluginModuleFederation } from '@module-federation/rsbuild-plugin';
+ import mfConfig from './module-federation.config';
export default defineConfig({
server: {
port: 3001
},
plugins: [
pluginReact(),
+ pluginModuleFederation(mfConfig)
]
});
```
This setup initiates Module Federation within `MFE1`, and upon initiating the development server, it is accessible at `http://localhost:3001`.
Similarly, the configuration activates Module Federation for `MFE2`, thereby exposing the `Button` component at `http://localhost:3002/remoteEntry.js`. With the development server operational, it becomes accessible at `http://localhost:3002`.