Basic CRA with Rsbuild

Demo Reference

Check out the example project list here: Rsbuild CRA

Setup Environment

Before getting started, you will need to install Node.js, 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:

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 or fnm to install the required version.

Here is an example of how to install the Node.js 20 LTS version via nvm:

# 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:

npm
yarn
pnpm
bun
npm create rsbuild@latest

Create App 1

create rsbuild@latest

"Input target folder":
> mfe1

"Select framework":
> React

"Select language":
> TypeScript

Create App 2

create rsbuild@latest

"Input target folder":
> mfe2

"Select framework":
> React

"Select language":
> TypeScript

Install

cd mfe1
pnpm i
cd mfe2
pnpm i

Use React in an existing project

To compile React, you need to register the Rsbuild React Plugin. The plugin will automatically add the necessary configuration for React builds.

For example, register in rsbuild.config.ts:

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.

Ensure that Webpack version 5 or above is installed by checking the installation report provided by Yarn.

Step 2: 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.

mv src/index.tsx src/bootstrap.tsx

Update the contents of bootstrap.tsx to the following:

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:

import('./bootstrap');

Step 3: Create and Expose

Now, create a component to expose from MFE2

3.1 Create Button Component

In MFE2, create a new file named Button.tsx in the src directory with the following content:

const Button = () => (
  <button>MFE2 Button</button>
);

export default Button;

3.2 Update App.tsx

Update App.tsx in MFE2 to import and render the Button component:

import './App.css';
import Button from './Button';

const App = () => {
  return (
    <div className="content">
      <h1>MFE2</h1>
      <Button />
    </div>
  );
};

export default App;

Step 3.3: Configure Rsbuild in MFE2

Create a rsbuild.config.ts file in the root directory of MFE2 with the following configuration:

rsbuild.config.ts
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
import { dependencies }  from './package.json';

export default defineConfig({
  server: {
    port: 3002
  },
  moduleFederation: {
    options: {
     name: 'remote',
      exposes: {
        './Button': './src/Button',
      },
      filename: 'remoteEntry.js',
      shared: {
        ...dependencies,
        react: {
          singleton: true,
          requiredVersion: dependencies['react'],
        },
        'react-dom': {
          singleton: true,
          requiredVersion: dependencies['react-dom'],
        },
      },
    }
  },
  plugins: [pluginReact()]
});

Step 4: Consume Remote Module

Consume the exposed module from MFE2 in MFE1

4.1 Update App.tsx

Update App.tsx in MFE1 to import and render the MFE2 Button component:

import React from 'react';
import Button from 'remote/Button'; // federated import

function App() {
  return (
    <div>
      <h1>MFE1</h1>
      <Button />
    </div>
  );
}

export default App;

Step 4.2: Configure Rsbuild in MFE1

Create a rsbuild.config.ts file in the root directory of MFE1 with the following configuration:

rsbuild.config.ts
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
import { dependencies }  from './package.json';

export default defineConfig({
  server: {
    port: 3001
  },
  moduleFederation: {
    options: {
     name: 'host',
     remotes: {
       remote: 'remote@http://localhost:3002/remoteEntry.js',
     },
     shared: {
       ...dependencies,
       react: {
         singleton: true,
         requiredVersion: dependencies['react'],
       },
       'react-dom': {
         singleton: true,
         requiredVersion: dependencies['react-dom'],
       },
     },
    }
  },
  plugins: [pluginReact()]
});

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.