Skip to content

Commit ae5ee1e

Browse files
feat: add BridgeReactPlugin to get federation instance (#3234)
Co-authored-by: Zack Jackson <[email protected]>
1 parent 8e47a69 commit ae5ee1e

File tree

10 files changed

+67
-33
lines changed

10 files changed

+67
-33
lines changed

.changeset/small-bats-leave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@module-federation/bridge-react': patch
3+
---
4+
5+
feat: mount bridge api to module instance

apps/router-demo/router-host-2000/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import Navigation from './navigation';
77
import Detail from './pages/Detail';
88
import Home from './pages/Home';
99
import './App.css';
10+
import BridgeReactPlugin from '@module-federation/bridge-react/plugin';
1011

1112
init({
1213
name: 'federation_consumer',
1314
remotes: [],
1415
plugins: [
16+
BridgeReactPlugin(),
1517
RetryPlugin({
1618
fetch: {
1719
url: 'http://localhost:2008/not-exist-mf-manifest.json',

apps/router-demo/router-remote1-2001/rsbuild.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export default defineConfig({
3333
pluginReact(),
3434
pluginModuleFederation({
3535
name: 'remote1',
36+
runtimePlugins: [
37+
require.resolve('@module-federation/bridge-react/plugin'),
38+
],
3639
exposes: {
3740
'./button': './src/button.tsx',
3841
'./export-app': './src/export-App.tsx',

packages/bridge/bridge-react/package.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
"import": "./dist/router.es.js",
2727
"require": "./dist/router.cjs.js"
2828
},
29+
"./plugin": {
30+
"types": "./dist/plugin.d.ts",
31+
"import": "./dist/plugin.es.js",
32+
"require": "./dist/plugin.es.js"
33+
},
2934
"./router-v5": {
3035
"types": "./dist/router-v5.d.ts",
3136
"import": "./dist/router-v5.es.js",
@@ -47,8 +52,7 @@
4752
"@loadable/component": "^5.16.4",
4853
"@module-federation/bridge-shared": "workspace:*",
4954
"@module-federation/sdk": "workspace:*",
50-
"react-error-boundary": "^4.0.13",
51-
"@module-federation/runtime": "workspace:*"
55+
"react-error-boundary": "^4.0.13"
5256
},
5357
"peerDependencies": {
5458
"react": ">=16.9.0",
@@ -68,6 +72,7 @@
6872
"react-router-dom": "6.22.3",
6973
"typescript": "^5.2.2",
7074
"vite": "^5.2.14",
71-
"vite-plugin-dts": "^3.9.1"
75+
"vite-plugin-dts": "^3.9.1",
76+
"@module-federation/runtime": "workspace:*"
7277
}
7378
}

packages/bridge/bridge-react/src/create.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ interface RemoteModule {
1818
};
1919
}
2020

21-
function createLazyRemoteComponent<T, E extends keyof T>(info: {
21+
type LazyRemoteComponentInfo<T, E extends keyof T> = {
2222
loader: () => Promise<T>;
2323
loading: React.ReactNode;
2424
fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
2525
export?: E;
26-
}) {
26+
};
27+
28+
function createLazyRemoteComponent<T, E extends keyof T>(
29+
info: LazyRemoteComponentInfo<T, E>,
30+
) {
2731
const exportName = info?.export || 'default';
2832
return React.lazy(async () => {
2933
LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
@@ -83,12 +87,9 @@ function createLazyRemoteComponent<T, E extends keyof T>(info: {
8387
});
8488
}
8589

86-
export function createRemoteComponent<T, E extends keyof T>(info: {
87-
loader: () => Promise<T>;
88-
loading: React.ReactNode;
89-
fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
90-
export?: E;
91-
}) {
90+
export function createRemoteComponent<T, E extends keyof T>(
91+
info: LazyRemoteComponentInfo<T, E>,
92+
) {
9293
type ExportType = T[E] extends (...args: any) => any
9394
? ReturnType<T[E]>
9495
: never;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { FederationRuntimePlugin } from '@module-federation/runtime';
2+
import type { FederationHost } from '@module-federation/runtime';
3+
4+
export type FederationRuntimeType = {
5+
instance: FederationHost | null;
6+
};
7+
8+
export const federationRuntime: FederationRuntimeType = { instance: null };
9+
10+
function BridgeReactPlugin(): FederationRuntimePlugin {
11+
return {
12+
name: 'bridge-react-plugin',
13+
beforeInit(args) {
14+
federationRuntime.instance = args.origin;
15+
return args;
16+
},
17+
};
18+
}
19+
20+
export default BridgeReactPlugin;

packages/bridge/bridge-react/src/provider.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type {
99
import { ErrorBoundary } from 'react-error-boundary';
1010
import { RouterContext } from './context';
1111
import { LoggerInstance, atLeastReact18 } from './utils';
12-
import { getInstance } from '@module-federation/runtime';
12+
import { federationRuntime } from './plugin';
1313

1414
type RenderParams = RenderFnParams & {
1515
[key: string]: unknown;
@@ -20,7 +20,7 @@ type DestroyParams = {
2020
};
2121
type RootType = HTMLElement | ReactDOMClient.Root;
2222

23-
type ProviderFnParams<T> = {
23+
export type ProviderFnParams<T> = {
2424
rootComponent: React.ComponentType<T>;
2525
render?: (
2626
App: React.ReactElement,
@@ -31,8 +31,11 @@ type ProviderFnParams<T> = {
3131
export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
3232
return () => {
3333
const rootMap = new Map<any, RootType>();
34-
const instance = getInstance();
35-
LoggerInstance.log(`createBridgeComponent remote instance`, instance);
34+
const instance = federationRuntime.instance;
35+
LoggerInstance.log(
36+
`createBridgeComponent instance from props >>>`,
37+
instance,
38+
);
3639

3740
const RawComponent = (info: { propsInfo: T; appInfo: ProviderParams }) => {
3841
const { appInfo, propsInfo, ...restProps } = info;
@@ -95,15 +98,13 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
9598
const renderFn = bridgeInfo?.render || ReactDOM.render;
9699
renderFn?.(rootComponentWithErrorBoundary, info.dom);
97100
}
98-
99101
instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info) || {};
100102
},
101103

102104
async destroy(info: DestroyParams) {
103105
LoggerInstance.log(`createBridgeComponent destroy Info`, {
104106
dom: info.dom,
105107
});
106-
107108
instance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit(info);
108109

109110
// call destroy function

packages/bridge/bridge-react/src/remote/index.tsx

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { ProviderParams } from '@module-federation/bridge-shared';
1010
import { dispatchPopstateEnv } from '@module-federation/bridge-shared';
1111
import { ErrorBoundaryPropsWithComponent } from 'react-error-boundary';
1212
import { LoggerInstance, pathJoin, getRootDomDefaultClassName } from '../utils';
13-
import { getInstance } from '@module-federation/runtime';
13+
import { federationRuntime } from '../plugin';
1414

1515
declare const __APP_VERSION__: string;
1616
export interface RenderFnParams extends ProviderParams {
@@ -53,15 +53,16 @@ const RemoteAppWrapper = forwardRef(function (
5353
...resProps
5454
} = props;
5555

56+
const instance = federationRuntime.instance;
5657
const rootRef: React.MutableRefObject<HTMLDivElement | null> =
5758
ref && 'current' in ref
5859
? (ref as React.MutableRefObject<HTMLDivElement | null>)
5960
: useRef(null);
6061

6162
const renderDom: React.MutableRefObject<HTMLElement | null> = useRef(null);
6263
const providerInfoRef = useRef<any>(null);
63-
const hostInstance = getInstance();
64-
LoggerInstance.log(`RemoteAppWrapper hostInstance >>>`, hostInstance);
64+
65+
LoggerInstance.log(`RemoteAppWrapper instance from props >>>`, instance);
6566

6667
useEffect(() => {
6768
const renderTimeout = setTimeout(() => {
@@ -84,18 +85,16 @@ const RemoteAppWrapper = forwardRef(function (
8485

8586
LoggerInstance.log(
8687
`createRemoteComponent LazyComponent hostInstance >>>`,
87-
hostInstance,
88+
instance,
8889
);
8990
const beforeBridgeRenderRes =
90-
hostInstance?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(
91+
instance?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(
9192
renderProps,
9293
) || {};
9394
// @ts-ignore
9495
renderProps = { ...renderProps, ...beforeBridgeRenderRes.extraProps };
9596
providerReturn.render(renderProps);
96-
hostInstance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(
97-
renderProps,
98-
);
97+
instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(renderProps);
9998
});
10099

101100
return () => {
@@ -107,7 +106,7 @@ const RemoteAppWrapper = forwardRef(function (
107106
{ moduleName, basename, dom: renderDom.current },
108107
);
109108

110-
hostInstance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit({
109+
instance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit({
111110
moduleName,
112111
dom: renderDom.current,
113112
basename,
@@ -121,7 +120,7 @@ const RemoteAppWrapper = forwardRef(function (
121120
dom: renderDom.current,
122121
});
123122

124-
hostInstance?.bridgeHook?.lifecycle?.afterBridgeDestroy?.emit({
123+
instance?.bridgeHook?.lifecycle?.afterBridgeDestroy?.emit({
125124
moduleName,
126125
dom: renderDom.current,
127126
basename,

packages/bridge/bridge-react/vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default defineConfig({
2121
lib: {
2222
entry: {
2323
index: path.resolve(__dirname, 'src/index.ts'),
24+
plugin: path.resolve(__dirname, 'src/plugin.ts'),
2425
router: path.resolve(__dirname, 'src/router.tsx'),
2526
'router-v5': path.resolve(__dirname, 'src/router-v5.tsx'),
2627
'router-v6': path.resolve(__dirname, 'src/router-v6.tsx'),
@@ -36,7 +37,6 @@ export default defineConfig({
3637
'react-router-dom/',
3738
'react-router-dom/index.js',
3839
'react-router-dom/dist/index.js',
39-
'@module-federation/runtime',
4040
],
4141
plugins: [
4242
{

pnpm-lock.yaml

Lines changed: 3 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)