Skip to content

Commit f1fb23a

Browse files
committed
chore(bridge-react): export createRemoteComponent and related utils
1 parent a40d744 commit f1fb23a

27 files changed

+709
-375
lines changed

.changeset/spicy-parents-greet.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@module-federation/bridge-react': patch
3+
'@module-federation/modern-js': patch
4+
---
5+
6+
chore(bridge-react): export createRemoteComponent and related utils

packages/bridge/bridge-react/package.json

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,76 @@
3232
"require": "./dist/v19.cjs.js"
3333
},
3434
"./router": {
35-
"types": "./dist/router.d.ts",
35+
"types": "./dist/router/default.d.ts",
3636
"import": "./dist/router.es.js",
3737
"require": "./dist/router.cjs.js"
3838
},
3939
"./plugin": {
40-
"types": "./dist/plugin.d.ts",
40+
"types": "./dist/provider/plugin.d.ts",
4141
"import": "./dist/plugin.es.js",
4242
"require": "./dist/plugin.es.js"
4343
},
4444
"./router-v5": {
45-
"types": "./dist/router-v5.d.ts",
45+
"types": "./dist/router/v5.d.ts",
4646
"import": "./dist/router-v5.es.js",
4747
"require": "./dist/router-v5.cjs.js"
4848
},
4949
"./router-v6": {
50-
"types": "./dist/router-v6.d.ts",
50+
"types": "./dist/router/v6.d.ts",
5151
"import": "./dist/router-v6.es.js",
5252
"require": "./dist/router-v6.cjs.js"
5353
},
54+
"./data-fetch-runtime-plugin": {
55+
"types": "./dist/module/data-fetch/runtime-plugin.d.ts",
56+
"import": "./dist/data-fetch-runtime-plugin.es.js",
57+
"require": "./dist/data-fetch-runtime-plugin.cjs.js"
58+
},
59+
"./data-fetch-utils": {
60+
"types": "./dist/module/utils.d.ts",
61+
"import": "./dist/data-fetch-utils.es.js",
62+
"require": "./dist/data-fetch-utils.cjs.js"
63+
},
64+
"./data-fetch-constant": {
65+
"types": "./dist/module/constant.d.ts",
66+
"import": "./dist/data-fetch-constant.es.js",
67+
"require": "./dist/data-fetch-constant.cjs.js"
68+
},
5469
"./*": "./*"
5570
},
71+
"typesVersions": {
72+
"*": {
73+
".": [
74+
"./dist/index.d.ts"
75+
],
76+
"v18": [
77+
"./dist/v18.d.ts"
78+
],
79+
"v19": [
80+
"./dist/v19.d.ts"
81+
],
82+
"router": [
83+
"./dist/router/default.d.ts"
84+
],
85+
"plugin": [
86+
"./dist/provider/plugin.d.ts"
87+
],
88+
"router-v5": [
89+
"./dist/router/v5.d.ts"
90+
],
91+
"router-v6": [
92+
"./dist/router/v6.d.ts"
93+
],
94+
"data-fetch-runtime-plugin": [
95+
"./dist/module/data-fetch/runtime-plugin.d.ts"
96+
],
97+
"data-fetch-utils": [
98+
"./dist/module/utils.d.ts"
99+
],
100+
"data-fetch-constant": [
101+
"./dist/module/constant.d.ts"
102+
]
103+
}
104+
},
56105
"scripts": {
57106
"dev": "vite",
58107
"build": "vite build",
@@ -66,7 +115,13 @@
66115
"peerDependencies": {
67116
"react": ">=16.9.0",
68117
"react-dom": ">=16.9.0",
69-
"react-router-dom": "^4 || ^5 || ^6 || ^7"
118+
"react-router-dom": "^4 || ^5 || ^6 || ^7",
119+
"@module-federation/runtime": ">=0.15.0"
120+
},
121+
"peerDependenciesMeta": {
122+
"@module-federation/runtime": {
123+
"optional": true
124+
}
70125
},
71126
"devDependencies": {
72127
"@testing-library/react": "15.0.7",
@@ -81,7 +136,7 @@
81136
"react-router-dom": "6.22.3",
82137
"typescript": "^5.2.2",
83138
"vite": "^5.4.18",
84-
"vite-plugin-dts": "^4.3.0",
139+
"vite-plugin-dts": "^4.5.4",
85140
"@module-federation/runtime": "workspace:*"
86141
}
87142
}

packages/bridge/bridge-react/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ export type {
1212
DestroyParams,
1313
RenderParams,
1414
} from './types';
15+
16+
export { kit, ERROR_TYPE, autoFetchDataPlugin } from './module';
17+
export type { DataFetchParams, NoSSRRemoteInfo } from './module';

packages/modernjs/src/runtime/AwaitDataFetch.tsx renamed to packages/bridge/bridge-react/src/module/AwaitDataFetch.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import React, { MutableRefObject, ReactNode, Suspense, useRef } from 'react';
2-
import logger from '../logger';
2+
import logger from './logger';
33
import {
44
DATA_FETCH_ERROR_PREFIX,
55
LOAD_REMOTE_ERROR_PREFIX,
66
ERROR_TYPE,
7-
DOWNGRADE_KEY,
87
DATA_FETCH_FUNCTION,
9-
} from '../constant';
10-
import { getDataFetchIdWithErrorMsgs, wrapDataFetchId } from '../utils';
11-
import type { DataFetchParams } from '../interfaces/global';
8+
} from './constant';
9+
10+
import { getDataFetchIdWithErrorMsgs, wrapDataFetchId } from './utils';
11+
import type { DataFetchParams } from './types';
1212

1313
function isPromise<T>(obj: any): obj is PromiseLike<T> {
1414
return (
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
export const PLUGIN_IDENTIFIER = '[ Module Federation React ]';
2+
export const DOWNGRADE_KEY = '_mfSSRDowngrade';
3+
export const DATA_FETCH_MAP_KEY = '__MF_DATA_FETCH_MAP__';
4+
export const DATA_FETCH_FUNCTION = '_mfDataFetch';
5+
export const FS_HREF = '_mfFSHref';
6+
export const ERROR_TYPE = {
7+
DATA_FETCH: 1,
8+
LOAD_REMOTE: 2,
9+
UNKNOWN: 3,
10+
};
11+
export const WRAP_DATA_FETCH_ID_IDENTIFIER = 'wrap_dfip_identifier';
12+
export const enum MF_DATA_FETCH_TYPE {
13+
FETCH_SERVER = 1,
14+
FETCH_CLIENT = 2,
15+
}
16+
17+
export const enum MF_DATA_FETCH_STATUS {
18+
LOADED = 1,
19+
LOADING = 2,
20+
AWAIT = 0,
21+
ERROR = 3,
22+
}
23+
24+
export const DATA_FETCH_IDENTIFIER = 'data';
25+
export const DATA_FETCH_CLIENT_SUFFIX = '.client';
26+
export const DATA_FETCH_QUERY = 'x-mf-data-fetch';
27+
export const DATA_FETCH_ERROR_PREFIX =
28+
'caught the following error during dataFetch: ';
29+
export const LOAD_REMOTE_ERROR_PREFIX =
30+
'caught the following error during loadRemote: ';

packages/modernjs/src/runtime/createRemoteComponent.tsx renamed to packages/bridge/bridge-react/src/module/createRemoteComponent.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
import React, { ReactNode, useEffect, useState } from 'react';
2-
import logger from '../logger';
3-
import { getInstance } from '@module-federation/enhanced/runtime';
2+
import logger from './logger';
3+
import { getInstance } from '@module-federation/runtime';
44
import { AwaitDataFetch, transformError } from './AwaitDataFetch';
5+
import { injectDataFetch } from './data-fetch/inject-data-fetch';
56
import {
67
fetchData,
78
getDataFetchItem,
89
getDataFetchMapKey,
9-
} from '../utils/dataFetch';
10-
import {
1110
getDataFetchInfo,
1211
getLoadedRemoteInfos,
1312
setDataFetchItemLoadedStatus,
1413
wrapDataFetchId,
15-
} from '../utils';
14+
} from './utils';
1615
import {
1716
DATA_FETCH_ERROR_PREFIX,
1817
DATA_FETCH_FUNCTION,
1918
FS_HREF,
2019
LOAD_REMOTE_ERROR_PREFIX,
2120
MF_DATA_FETCH_TYPE,
22-
} from '../constant';
21+
} from './constant';
22+
2323
import type { ErrorInfo } from './AwaitDataFetch';
24-
import type { DataFetchParams, NoSSRRemoteInfo } from '../interfaces/global';
24+
import type { DataFetchParams, NoSSRRemoteInfo } from './types';
2525

2626
type IProps = {
2727
id: string;
@@ -192,6 +192,7 @@ function getServerNeedRemoteInfo(
192192
export function createRemoteComponent<T, E extends keyof T>(
193193
options: CreateRemoteComponentOptions<T, E>,
194194
) {
195+
injectDataFetch();
195196
type ComponentType = T[E] extends (...args: any) => any
196197
? Parameters<T[E]>[0] extends undefined
197198
? ReactKey
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { DATA_FETCH_FUNCTION } from '../constant';
2+
import { dataFetchFunction } from './inject-data-fetch';
3+
4+
export async function callDataFetch() {
5+
const dataFetch = globalThis[DATA_FETCH_FUNCTION];
6+
if (dataFetch) {
7+
await Promise.all(
8+
dataFetch.map(async (options) => {
9+
await dataFetchFunction(options);
10+
}),
11+
);
12+
}
13+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import {
2+
DATA_FETCH_FUNCTION,
3+
DOWNGRADE_KEY,
4+
FS_HREF,
5+
MF_DATA_FETCH_STATUS,
6+
MF_DATA_FETCH_TYPE,
7+
} from '../constant';
8+
import logger from '../logger';
9+
import {
10+
dataFetchFunctionOptions,
11+
MF_DATA_FETCH_MAP_VALUE_PROMISE_SET,
12+
} from '../types';
13+
import {
14+
callAllDowngrade,
15+
callDowngrade,
16+
getDataFetchItem,
17+
getDataFetchMap,
18+
getDowngradeTag,
19+
initDataFetchMap,
20+
setSSREnv,
21+
} from '../utils';
22+
23+
const dataFetchFunction = async function (options: dataFetchFunctionOptions) {
24+
const [id, data, downgrade] = options;
25+
logger.debug('==========call data fetch function!');
26+
if (data) {
27+
if (!id) {
28+
throw new Error('id is required!');
29+
}
30+
if (!getDataFetchMap()) {
31+
initDataFetchMap();
32+
}
33+
const dataFetchItem = getDataFetchItem(id);
34+
if (dataFetchItem) {
35+
dataFetchItem[1]?.[1]?.(data);
36+
dataFetchItem[2] = MF_DATA_FETCH_STATUS.LOADED;
37+
return;
38+
}
39+
if (!dataFetchItem) {
40+
const dataFetchMap = getDataFetchMap();
41+
let res: MF_DATA_FETCH_MAP_VALUE_PROMISE_SET[1];
42+
let rej: MF_DATA_FETCH_MAP_VALUE_PROMISE_SET[2];
43+
const p = new Promise((resolve, reject) => {
44+
res = resolve;
45+
rej = reject;
46+
});
47+
48+
dataFetchMap[id] = [
49+
[
50+
async () => async () => {
51+
return '';
52+
},
53+
MF_DATA_FETCH_TYPE.FETCH_SERVER,
54+
],
55+
[p, res, rej],
56+
MF_DATA_FETCH_STATUS.LOADED,
57+
];
58+
res && res(data);
59+
return;
60+
}
61+
}
62+
63+
if (downgrade) {
64+
const mfDowngrade = getDowngradeTag();
65+
if (!mfDowngrade) {
66+
globalThis[DOWNGRADE_KEY] = id ? [id] : true;
67+
} else if (Array.isArray(mfDowngrade) && id && !mfDowngrade.includes(id)) {
68+
mfDowngrade.push(id);
69+
}
70+
}
71+
72+
const mfDowngrade = getDowngradeTag();
73+
74+
if (typeof mfDowngrade === 'boolean') {
75+
return callAllDowngrade();
76+
}
77+
if (Array.isArray(mfDowngrade)) {
78+
if (!id) {
79+
globalThis[DOWNGRADE_KEY] = true;
80+
return callAllDowngrade();
81+
}
82+
83+
if (!mfDowngrade.includes(id)) {
84+
mfDowngrade.push(id);
85+
}
86+
87+
return callDowngrade(id);
88+
}
89+
};
90+
91+
export function injectDataFetch() {
92+
// @ts-ignore
93+
if (dataFetch.push === dataFetchFunction) {
94+
return;
95+
}
96+
97+
if (typeof window === 'undefined') {
98+
return;
99+
}
100+
101+
globalThis[FS_HREF] = window.location.href;
102+
globalThis[DATA_FETCH_FUNCTION] ||= [];
103+
104+
const dataFetch: Array<dataFetchFunctionOptions> =
105+
globalThis[DATA_FETCH_FUNCTION];
106+
107+
// @ts-ignore
108+
dataFetch.push = dataFetchFunction;
109+
}
110+
111+
export { dataFetchFunction };

packages/modernjs/src/cli/mfRuntimePlugins/auto-fetch-data.ts renamed to packages/bridge/bridge-react/src/module/data-fetch/runtime-plugin.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@ import {
44
getDataFetchItem,
55
getDataFetchMap,
66
isCSROnly,
7-
} from '../../utils';
8-
import logger from '../../logger';
9-
import {
107
getDataFetchMapKey,
118
isDataLoaderExpose,
129
loadDataFetchModule,
13-
} from '../../utils/dataFetch';
14-
import { MF_DATA_FETCH_TYPE, MF_DATA_FETCH_STATUS } from '../../constant';
15-
import { DATA_FETCH_CLIENT_SUFFIX } from '@module-federation/rsbuild-plugin/constant';
10+
} from '../utils';
11+
import logger from '../logger';
12+
import {
13+
MF_DATA_FETCH_TYPE,
14+
MF_DATA_FETCH_STATUS,
15+
DATA_FETCH_CLIENT_SUFFIX,
16+
} from '../constant';
1617

17-
import type { MF_DATA_FETCH_MAP_VALUE } from '../../interfaces/global';
18-
import type { FederationRuntimePlugin } from '@module-federation/enhanced/runtime';
18+
import type { MF_DATA_FETCH_MAP_VALUE } from '../types';
19+
import type { FederationRuntimePlugin } from '@module-federation/runtime';
1920

2021
const autoFetchData: () => FederationRuntimePlugin = () => ({
2122
name: 'auto-fetch-data-plugin',
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import autoFetchDataPlugin from './data-fetch/runtime-plugin';
2+
3+
export type { DataFetchParams, NoSSRRemoteInfo } from './types';
4+
export { ERROR_TYPE } from './constant';
5+
6+
// avoid import react directly https://github.com/web-infra-dev/modern.js/issues/7096
7+
export const kit = {
8+
get createRemoteSSRComponent(): typeof import('./createRemoteComponent').createRemoteSSRComponent {
9+
return require('./createRemoteComponent').createRemoteSSRComponent;
10+
},
11+
get createRemoteComponent(): typeof import('./createRemoteComponent').createRemoteComponent {
12+
return require('./createRemoteComponent').createRemoteComponent;
13+
},
14+
get collectSSRAssets(): typeof import('./createRemoteComponent').collectSSRAssets {
15+
return require('./createRemoteComponent').collectSSRAssets;
16+
},
17+
get wrapNoSSR(): typeof import('./wrapNoSSR').wrapNoSSR {
18+
return require('./wrapNoSSR').wrapNoSSR;
19+
},
20+
get injectDataFetch(): typeof import('./data-fetch/inject-data-fetch').injectDataFetch {
21+
return require('./data-fetch/inject-data-fetch').injectDataFetch;
22+
},
23+
get callDataFetch(): typeof import('./data-fetch/call-data-fetch').callDataFetch {
24+
return require('./data-fetch/call-data-fetch').callDataFetch;
25+
},
26+
get setSSREnv(): typeof import('./utils').setSSREnv {
27+
return require('./utils').setSSREnv;
28+
},
29+
};
30+
31+
export { autoFetchDataPlugin };

0 commit comments

Comments
 (0)