加载模块
本章将介绍如何使用 createLazyComponent
在宿主应用中加载和集成远程 React 组件模块。
什么是 createLazyComponent?
createLazyComponent
是 React Bridge 提供的用于加载单个远程组件的 API。与 createRemoteAppComponent
不同,它专门用于加载具体的 React 组件,而不是完整的应用。
createLazyComponent vs createRemoteAppComponent
特性 | createLazyComponent | createRemoteAppComponent |
---|
适用场景 | 加载单个远程组件 | 加载完整的远程应用 |
路由支持 | ❌ 不包含路由功能 | ✅ 完整的路由集成 |
生命周期 | ✅ 基本的组件生命周期 | ✅ 完整的应用生命周期 |
数据预取 | ✅ 支持数据预取 | ❌ 依赖应用内部处理 |
SSR 控制 | ✅ 可控制 SSR | ❌ 由应用决定 |
安装
npm install @module-federation/bridge-react@latest
基本使用
步骤 1: 注册 lazyLoadComponentPlugin
在运行时注册 lazyLoadComponentPlugin 插件,用于注册 createLazyComponent、prefetch API。
import { getInstance } from '@module-federation/runtime';
import { lazyLoadComponentPlugin } from '@module-federation/bridge-react';
const instance = getInstance();
// 注册 lazyLoadComponentPlugin 插件
instance.registerPlugins([lazyLoadComponentPlugin()]);
步骤 2: 调用 createLazyComponent
注册完 lazyLoadComponentPlugin
插件后,可通过 instance.createLazyComponent
方法创建懒加载组件。
import { getInstance } from '@module-federation/runtime';
import { lazyLoadComponentPlugin } from '@module-federation/bridge-react';
const instance = getInstance();
// 注册 lazyLoadComponentPlugin 插件后, 注册后即可使用 `createLazyComponent` 或 `prefetch` API
instance.registerPlugins([lazyLoadComponentPlugin()]);
// 使用 instance.prefetch 进行远程模块数据预取
instance.prefetch({
id: 'dynamic_remote'
});
// 使用 instance.createLazyComponent 进行加载远程模块懒加载
const LazyComponent = instance.createLazyComponent({
loader: () => loadRemote('dynamic_remote'),
loading: 'loading...',
fallback: ({ error }) => {
if (error instanceof Error && error.message.includes('not exist')) {
return <div>fallback - not existed id</div>;
}
return <div>fallback</div>;
},
});
createLazyComponent API 参考
函数签名
function createLazyComponent<T, E extends keyof T>(
options: CreateLazyComponentOptions<T, E>
): React.ComponentType<ComponentProps>
createLazyComponent
该 API 需要先注册 lazyLoadComponentPlugin 插件,才可以调用。
Type declaration
declare function createLazyComponent(
props: CreateLazyComponentOptions
): (props: ComponentType) => React.JSX.Element;
type CreateLazyComponentOptions<T, E extends keyof T> = {
loader: () => Promise<T>;
loading: React.ReactNode;
delayLoading?: number;
fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode);
export?: E;
dataFetchParams?: DataFetchParams;
noSSR?: boolean;
injectScript?: boolean;
injectLink?: boolean;
};
type ComponentType = T[E] extends (...args: any) => any
? Parameters<T[E]>[0] extends undefined
? Record<string, never>
: Parameters<T[E]>[0]
: Record<string, never>;
type DataFetchParams = {
isDowngrade: boolean;
} & Record<string, unknown>;
type ErrorInfo = {
error: Error;
errorType: number;
dataFetchMapKey?: string;
};
该函数除了支持加载组件之外,还支持下列能力:
- SSR 模式中会注入对应生产者的样式标签/脚本资源 ,此行为可以帮助避免流式渲染带来的 CSS 闪烁问题以及加速 PID (首屏可交互时间)。
- 如果生产者存在数据获取函数,那么会自动调用此函数并注入数据。
import React, { FC, memo, useEffect } from 'react';
import { getInstance } from '@module-federation/enhanced/runtime';
import { ERROR_TYPE } from '@module-federation/bridge-react';
const instance = getInstance();
const LazyComponent = instance.createLazyComponent({
loader: () => import('remote/Image'),
loading: <div>loading...</div>,
fallback: ({error,errorType,dataFetchMapKey}) => {
console.error(error)
if(errorType === ERROR_TYPE.LOAD_REMOTE){
return <div>load remote failed</div>
}
if(errorType === ERROR_TYPE.DATA_FETCH){
return <div>data fetch failed, the dataFetchMapKey key is: {dataFetchMapKey}</div>
}
return <div>error type is unknown</div>;
},
});
const App: FC = () => {
return <>
<LazyComponent />
</>;
};
export default App;
loader
- 类型:
() => Promise<T>
- 是否必填:是
- 默认值:
undefined
加载远程组件的函数,通常为 ()=>loadRemote(id)
或者 ()=>import(id)
。
loading
- 类型:
React.ReactNode
- 是否必填:是
- 默认值:
undefined
设置模块载入状态。
delayLoading
- 类型:
number
- 是否必填:否
- 默认值:
undefined
设置显示延迟加载时间,单位为毫秒,如果加载时间小于该时间,那么不会显示 loading 状态。
fallback
- 类型:
(({ error }: { error: ErrorInfo}) => React.ReactElement)
- 是否必填:是
- 默认值:
undefined
当组件加载或渲染失败时,所渲染的容错组件。
export
- 类型:
string
- 是否必填:否
- 默认值:
'default'
如果远程组件是具名导出,那么可以通过此参数指定需要导出的组件名称,默认加载 default 导出。
dataFetchParams
- 类型:
DataFetchParams
- 是否必填:否
- 默认值:
undefined
如果远程组件存在数据获取函数,设置后会传递给数据获取函数。
noSSR
- 类型:
boolean
- 是否必填:否
- 默认值:
false
设置 true
后该组件不会在 SSR 场景渲染。
injectScript
- 类型:
boolean
- 是否必填:否
- 默认值:
false
SSR 环境中,如果设置 true
后创建的组件会注入对应脚本资源 script。
例如 remote/button
有 __federation_button.js
,那么在 SSR 返回的 html 中会在组件前面注入相应的 script ,来加速交互速度。
<script async src="__federation_button.js" crossOrigin="anonymous"/>
<button>remote button</button>
injectLink
- 类型:
boolean
- 是否必填:否
- 默认值:
true
SSR 环境中,如果设置 true
后创建的组件会注入对应样式资源 link。
例如 remote/button
有 __federation_button.css
,那么在 SSR 返回的 html 中会在组件前面注入相应的 link ,来避免页面闪烁的问题。
<link href="__federation_button.css" rel="stylesheet" type="text/css">
<button>remote button</button>
prefetch
该 API 需要先注册 lazyLoadComponentPlugin 插件,才可以调用。
Type declaration
type PrefetchOptions = {
id: string;
dataFetchParams?: DataFetchParams;
preloadComponentResource?: boolean;
};
type DataFetchParams = {
isDowngrade: boolean;
_id?: string;
} & Record<string, unknown>;
预加载组件资源文件以及组件的 data loader 。
import React, { FC, memo, useEffect } from 'react';
import { getInstance } from '@module-federation/enhanced/runtime';
const instance = getInstance();
instance.prefetch({
id: 'remote/Image',
preloadComponentResource: true,
});
id
- 类型:
string
- 是否必填:是
- 默认值:
undefined
预加载组件的 id 。
preloadComponentResource
- 类型:
boolean
- 是否必填:否
- 默认值:
false
是否预加载组件的资源文件。
dataFetchParams
- 类型:
DataFetchParams
- 是否必填:否
- 默认值:
undefined
如果远程组件存在数据获取函数,设置后会传递给数据获取函数。