# Loading Applications This chapter introduces how to use `createRemoteAppComponent` to load and integrate remote React applications in a host application. ## What is createRemoteAppComponent? `createRemoteAppComponent` is the core React Bridge API for loading remote React applications. It provides: - **Automatic Lazy Loading**: Loads remotes only when needed - **Lifecycle Management**: Handles mount/unmount automatically - **Router Integration**: Integrates with React Router and supports basename injection - **Error Handling**: Built-in loading/runtime error fallback support - **Styling**: Supports `className` / `style` on the wrapper component ## Installation ```sh [npm] npm install @module-federation/bridge-react@latest ``` ```sh [yarn] yarn add @module-federation/bridge-react@latest ``` ```sh [pnpm] pnpm add @module-federation/bridge-react@latest ``` ## Basic Usage ### Step 1: Configure Remote Modules Add remote configuration to the host application's Module Federation config. :::tip Build Tool Support The following example uses Rsbuild configuration. Please adjust according to your build tool: - **Rsbuild**: `@module-federation/rsbuild-plugin` - **Rspack**: `@module-federation/enhanced/rspack` - **Webpack**: `@module-federation/enhanced/webpack` - **Vite**: `@module-federation/vite` ::: ```ts // rsbuild.config.ts import { pluginModuleFederation } from '@module-federation/rsbuild-plugin'; import { defineConfig } from '@rsbuild/core'; export default defineConfig({ plugins: [ pluginModuleFederation({ name: 'host-app', remotes: { remote1: 'remote1@http://localhost:3001/remoteEntry.js', }, }), ], }); ``` ### Step 2: Create Remote Components #### 2.1 Define Loading and Error Components ```tsx // ./src/components/RemoteComponents.tsx import React from 'react'; export const LoadingComponent = () => ( <div style={{ padding: '20px', textAlign: 'center' }}> <div>Loading remote application...</div> </div> ); export const ErrorFallback = ({ error }: { error: Error }) => ( <div style={{ padding: '20px', border: '1px solid #ff6b6b', borderRadius: '8px' }}> <h3>Remote Application Load Failed</h3> <p>Error details: {error.message}</p> <button onClick={() => window.location.reload()}>Reload Page</button> </div> ); ``` #### 2.2 Create Remote Application Component ```tsx // ./src/remotes/Remote1App.tsx import { createRemoteAppComponent } from '@module-federation/bridge-react'; import { loadRemote } from '@module-federation/runtime'; import { LoadingComponent, ErrorFallback } from '../components/RemoteComponents'; export const Remote1App = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), loading: LoadingComponent, fallback: ErrorFallback, }); ``` #### 2.3 Main Application Router Configuration ```tsx // ./src/App.tsx import React, { useRef } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; import { Remote1App } from './remotes/Remote1App'; const HomePage = () => ( <div style={{ padding: '20px' }}> <h1>Host Application Home</h1> <p>This is the home content of the host application</p> </div> ); const App = () => { const ref = useRef<HTMLDivElement | null>(null); return ( <BrowserRouter> <Routes> <Route path="/" element={<HomePage />} /> <Route path="/remote1/*" Component={() => ( <Remote1App className="remote1" style={{ color: 'red' }} name="Ming" age={12} ref={ref} /> )} /> </Routes> </BrowserRouter> ); }; export default App; ``` ## Remote Component Props ### Router Props - `basename`: Set the base path for the remote application - `memoryRoute`: Memory router configuration ### Style Props - `style`: `React.CSSProperties` - `className`: `string` ### Ref Support - `ref`: `React.Ref<HTMLDivElement>` (forwarded to the internal container) ### Data Passing - Pass props directly (e.g. `userId="123"`) or via the `props` object. ## createRemoteAppComponent API Reference ### Function Signature ```tsx function createRemoteAppComponent<T = Record<string, unknown>, E extends keyof T = keyof T>( config: RemoteComponentParams<T, E> ): React.ForwardRefExoticComponent< Omit<RemoteComponentProps<T>, "ref"> & React.RefAttributes<HTMLDivElement> > ``` ### RemoteComponentParams\<T, E> ```tsx interface RemoteComponentParams<T = Record<string, unknown>, E extends keyof T = keyof T> { loader: () => Promise<T>; loading: React.ReactNode; fallback: React.ComponentType<{ error: Error }>; export?: E; props?: T; } ``` ### RemoteComponentProps\<T> ```tsx interface RemoteComponentProps<T = Record<string, unknown>> { props?: T; fallback?: React.ComponentType<{ error: Error }>; loading?: React.ReactNode; basename?: string; memoryRoute?: { entryPath: string; initialState?: Record<string, unknown>; }; style?: React.CSSProperties; className?: string; [key: string]: unknown; } ``` ### Parameter Details ### loader - Type: `() => Promise<T>` - Required: Yes - Description: Loads the remote module object - Examples: ```tsx loader: () => loadRemote('remote1/export-app') loader: () => import('remote1/export-app') ``` ### loading - Type: `React.ReactNode` - Required: Yes - Description: UI shown while the remote is loading - Examples: ```tsx loading: <div>Loading...</div> loading: 'Loading remote app...' loading: <Spinner /> ``` ### fallback - Type: `React.ComponentType<{ error: Error }>` - Required: Yes - Description: UI shown when loading/rendering fails; receives `error` - Examples: ```tsx fallback: ({ error }) => <div>Error: {error.message}</div> fallback: ErrorBoundaryComponent ``` ### export - Type: `E extends keyof T` - Required: No - Default: `'default'` - Description: Selects which export to render from the loaded remote module Example: if your remote module exports: ```tsx export default App; export const dashboard = Dashboard; ``` Host usage: ```tsx createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), }) createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), export: 'dashboard', }) ``` ## Bundle Size Optimization ### React Router Dependency Explanation By default, `@module-federation/bridge-react` includes `react-router-dom` in your bundle to provide: - Automatic basename injection - Router context passing - Nested routing support If you don't need React Router integration (or you use a different router), disable `enableBridgeRouter` to reduce bundle size (about \~3KB gzipped) and avoid unnecessary router integration. ### How to Disable Router Dependency ```ts title="rsbuild.config.ts" import { pluginModuleFederation } from '@module-federation/rsbuild-plugin'; export default { plugins: [ pluginModuleFederation({ name: 'host-app', remotes: { remote1: 'remote1@http://localhost:3001/mf-manifest.json', }, bridge: { enableBridgeRouter: false, }, }), ], }; ``` :::tip Configuration Behavior - `enableBridgeRouter: false`: Automatically aliases to the router-free `/base` entry. - `enableBridgeRouter: true` / `undefined`: Includes router support (default). ::: :::info How It Works When `enableBridgeRouter: false`, the plugin sets up an alias: ``` '@module-federation/bridge-react' → '@module-federation/bridge-react/base' ``` :::