@module-federation/bridge-react 0.0.0-next-20250708121428 → 0.0.0-next-20250709032753
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -8
- package/__tests__/bridge.spec.tsx +7 -7
- package/dist/{bridge-base-UGCwcMnG.js → bridge-base-BBH982Tz.cjs} +1 -1
- package/dist/{bridge-base-BoshEggF.mjs → bridge-base-P6pEjY1q.js} +1 -1
- package/dist/index-Cv3p6r66.cjs +235 -0
- package/dist/index-D4yt7Udv.js +236 -0
- package/dist/index.cjs.js +9 -35
- package/dist/index.d.ts +0 -143
- package/dist/index.es.js +12 -38
- package/dist/plugin.d.ts +0 -9
- package/dist/router-v5.cjs.js +1 -1
- package/dist/router-v5.d.ts +0 -9
- package/dist/router-v5.es.js +1 -1
- package/dist/router-v6.cjs.js +1 -1
- package/dist/router-v6.d.ts +0 -9
- package/dist/router-v6.es.js +1 -1
- package/dist/router.cjs.js +1 -1
- package/dist/router.d.ts +0 -9
- package/dist/router.es.js +1 -1
- package/dist/v18.cjs.js +1 -1
- package/dist/v18.d.ts +0 -9
- package/dist/v18.es.js +1 -1
- package/dist/v19.cjs.js +1 -1
- package/dist/v19.d.ts +0 -9
- package/dist/v19.es.js +1 -1
- package/package.json +5 -46
- package/src/.eslintrc.js +9 -0
- package/src/index.ts +1 -32
- package/src/remote/component.tsx +3 -3
- package/src/remote/create.tsx +4 -17
- package/tsconfig.json +1 -1
- package/vite.config.ts +0 -13
- package/dist/data-fetch-server-middleware.cjs.js +0 -163
- package/dist/data-fetch-server-middleware.d.ts +0 -15
- package/dist/data-fetch-server-middleware.es.js +0 -164
- package/dist/data-fetch-utils.cjs.js +0 -24
- package/dist/data-fetch-utils.d.ts +0 -86
- package/dist/data-fetch-utils.es.js +0 -26
- package/dist/index-C0fDZB5b.js +0 -45
- package/dist/index-CqxytsLY.mjs +0 -46
- package/dist/index.esm-BCeUd-x9.mjs +0 -418
- package/dist/index.esm-j_1sIRzg.js +0 -417
- package/dist/lazy-load-component-plugin-BbqmMGKu.mjs +0 -492
- package/dist/lazy-load-component-plugin-DgYHamxE.js +0 -491
- package/dist/lazy-load-component-plugin.cjs.js +0 -6
- package/dist/lazy-load-component-plugin.d.ts +0 -16
- package/dist/lazy-load-component-plugin.es.js +0 -6
- package/dist/lazy-utils.cjs.js +0 -24
- package/dist/lazy-utils.d.ts +0 -149
- package/dist/lazy-utils.es.js +0 -24
- package/dist/prefetch-BWabXlKU.js +0 -1332
- package/dist/prefetch-CXJhiNUD.mjs +0 -1333
- package/dist/utils-BTYYwZcb.mjs +0 -2016
- package/dist/utils-iEVlDmyk.js +0 -2015
- package/src/lazy/AwaitDataFetch.tsx +0 -215
- package/src/lazy/constant.ts +0 -30
- package/src/lazy/createLazyComponent.tsx +0 -418
- package/src/lazy/data-fetch/cache.ts +0 -296
- package/src/lazy/data-fetch/call-data-fetch.ts +0 -13
- package/src/lazy/data-fetch/data-fetch-server-middleware.ts +0 -196
- package/src/lazy/data-fetch/index.ts +0 -16
- package/src/lazy/data-fetch/inject-data-fetch.ts +0 -109
- package/src/lazy/data-fetch/prefetch.ts +0 -106
- package/src/lazy/data-fetch/runtime-plugin.ts +0 -115
- package/src/lazy/index.ts +0 -35
- package/src/lazy/logger.ts +0 -6
- package/src/lazy/types.ts +0 -75
- package/src/lazy/utils.ts +0 -372
- package/src/lazy/wrapNoSSR.tsx +0 -10
- package/src/plugins/lazy-load-component-plugin.ts +0 -62
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
MutableRefObject,
|
|
3
|
-
ReactNode,
|
|
4
|
-
Suspense,
|
|
5
|
-
useRef,
|
|
6
|
-
useState,
|
|
7
|
-
} from 'react';
|
|
8
|
-
import logger from './logger';
|
|
9
|
-
import {
|
|
10
|
-
DATA_FETCH_ERROR_PREFIX,
|
|
11
|
-
LOAD_REMOTE_ERROR_PREFIX,
|
|
12
|
-
ERROR_TYPE,
|
|
13
|
-
DATA_FETCH_FUNCTION,
|
|
14
|
-
} from './constant';
|
|
15
|
-
|
|
16
|
-
import { getDataFetchIdWithErrorMsgs, wrapDataFetchId } from './utils';
|
|
17
|
-
import type { DataFetchParams } from './types';
|
|
18
|
-
|
|
19
|
-
function isPromise<T>(obj: any): obj is PromiseLike<T> {
|
|
20
|
-
return (
|
|
21
|
-
!!obj &&
|
|
22
|
-
(typeof obj === 'object' || typeof obj === 'function') &&
|
|
23
|
-
typeof obj.then === 'function'
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
const AWAIT_ERROR_PREFIX =
|
|
27
|
-
'<Await /> caught the following error during render: ';
|
|
28
|
-
|
|
29
|
-
export type ErrorInfo = {
|
|
30
|
-
error: Error;
|
|
31
|
-
errorType: number;
|
|
32
|
-
dataFetchMapKey?: string;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export const transformError = (err: string | Error): ErrorInfo => {
|
|
36
|
-
const errMsg = err instanceof Error ? err.message : err;
|
|
37
|
-
const originalMsg = errMsg.replace(AWAIT_ERROR_PREFIX, '');
|
|
38
|
-
const dataFetchMapKey = getDataFetchIdWithErrorMsgs(originalMsg);
|
|
39
|
-
if (originalMsg.indexOf(DATA_FETCH_ERROR_PREFIX) === 0) {
|
|
40
|
-
return {
|
|
41
|
-
error: new Error(
|
|
42
|
-
originalMsg
|
|
43
|
-
.replace(DATA_FETCH_ERROR_PREFIX, '')
|
|
44
|
-
.replace(wrapDataFetchId(dataFetchMapKey), ''),
|
|
45
|
-
),
|
|
46
|
-
errorType: ERROR_TYPE.DATA_FETCH,
|
|
47
|
-
dataFetchMapKey,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
if (originalMsg.indexOf(LOAD_REMOTE_ERROR_PREFIX) === 0) {
|
|
51
|
-
return {
|
|
52
|
-
error: new Error(
|
|
53
|
-
originalMsg
|
|
54
|
-
.replace(LOAD_REMOTE_ERROR_PREFIX, '')
|
|
55
|
-
.replace(wrapDataFetchId(dataFetchMapKey), ''),
|
|
56
|
-
),
|
|
57
|
-
errorType: ERROR_TYPE.LOAD_REMOTE,
|
|
58
|
-
dataFetchMapKey,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
error: new Error(originalMsg.replace(wrapDataFetchId(dataFetchMapKey), '')),
|
|
64
|
-
errorType: ERROR_TYPE.UNKNOWN,
|
|
65
|
-
dataFetchMapKey,
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export interface AwaitProps<T> {
|
|
70
|
-
resolve: T | Promise<T>;
|
|
71
|
-
loading?: ReactNode;
|
|
72
|
-
delayLoading?: number;
|
|
73
|
-
errorElement?: ReactNode | ((errorInfo: ErrorInfo) => ReactNode);
|
|
74
|
-
children: (data: T) => ReactNode;
|
|
75
|
-
params?: DataFetchParams;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export interface AwaitErrorHandlerProps<T = any>
|
|
79
|
-
extends Omit<AwaitProps<T>, 'resolve'> {
|
|
80
|
-
resolve: () => T | string;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const DefaultLoading = <></>;
|
|
84
|
-
const DefaultErrorElement = (_data: any) => <div>Error</div>;
|
|
85
|
-
|
|
86
|
-
export function AwaitDataFetch<T>({
|
|
87
|
-
resolve,
|
|
88
|
-
loading = DefaultLoading,
|
|
89
|
-
errorElement = DefaultErrorElement,
|
|
90
|
-
children,
|
|
91
|
-
params,
|
|
92
|
-
delayLoading,
|
|
93
|
-
}: AwaitProps<T>) {
|
|
94
|
-
const dataRef = useRef<T>();
|
|
95
|
-
const data = dataRef.current || resolve;
|
|
96
|
-
const getData = isPromise(data) ? fetchData(data, dataRef) : () => data;
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<AwaitSuspense
|
|
100
|
-
params={params}
|
|
101
|
-
loading={loading}
|
|
102
|
-
errorElement={errorElement}
|
|
103
|
-
delayLoading={delayLoading}
|
|
104
|
-
// @ts-expect-error
|
|
105
|
-
resolve={getData}
|
|
106
|
-
>
|
|
107
|
-
{children}
|
|
108
|
-
</AwaitSuspense>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export const DelayedLoading = ({
|
|
113
|
-
delayLoading,
|
|
114
|
-
children,
|
|
115
|
-
}: {
|
|
116
|
-
delayLoading?: number;
|
|
117
|
-
children: ReactNode;
|
|
118
|
-
}) => {
|
|
119
|
-
const [show, setShow] = useState(false);
|
|
120
|
-
const timerSet = useRef(false);
|
|
121
|
-
|
|
122
|
-
if (!delayLoading) {
|
|
123
|
-
return children;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (typeof window !== 'undefined' && !show && !timerSet.current) {
|
|
127
|
-
timerSet.current = true;
|
|
128
|
-
setTimeout(() => {
|
|
129
|
-
setShow(true);
|
|
130
|
-
}, delayLoading);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return show ? children : null;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
function AwaitSuspense<T>({
|
|
137
|
-
resolve,
|
|
138
|
-
children,
|
|
139
|
-
loading = DefaultLoading,
|
|
140
|
-
errorElement = DefaultErrorElement,
|
|
141
|
-
delayLoading,
|
|
142
|
-
}: AwaitErrorHandlerProps<T>) {
|
|
143
|
-
return (
|
|
144
|
-
<Suspense
|
|
145
|
-
fallback={
|
|
146
|
-
<DelayedLoading delayLoading={delayLoading}>{loading}</DelayedLoading>
|
|
147
|
-
}
|
|
148
|
-
>
|
|
149
|
-
<ResolveAwait resolve={resolve} errorElement={errorElement}>
|
|
150
|
-
{children}
|
|
151
|
-
</ResolveAwait>
|
|
152
|
-
</Suspense>
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function ResolveAwait<T>({
|
|
157
|
-
children,
|
|
158
|
-
resolve,
|
|
159
|
-
errorElement,
|
|
160
|
-
params,
|
|
161
|
-
}: AwaitErrorHandlerProps<T>) {
|
|
162
|
-
const data = resolve();
|
|
163
|
-
logger.debug('resolve data: ', data);
|
|
164
|
-
if (typeof data === 'string' && data.indexOf(AWAIT_ERROR_PREFIX) === 0) {
|
|
165
|
-
const transformedError = transformError(data);
|
|
166
|
-
return (
|
|
167
|
-
<>
|
|
168
|
-
{typeof errorElement === 'function' ? (
|
|
169
|
-
<>
|
|
170
|
-
{globalThis.FEDERATION_SSR && (
|
|
171
|
-
<script
|
|
172
|
-
suppressHydrationWarning
|
|
173
|
-
// eslint-disable-next-line react/no-danger
|
|
174
|
-
dangerouslySetInnerHTML={{
|
|
175
|
-
__html: String.raw`
|
|
176
|
-
globalThis['${DATA_FETCH_FUNCTION}'] = globalThis['${DATA_FETCH_FUNCTION}'] || []
|
|
177
|
-
globalThis['${DATA_FETCH_FUNCTION}'].push([${transformedError.dataFetchMapKey ? `'${transformedError.dataFetchMapKey}'` : ''},${params ? JSON.stringify(params) : null},true]);`,
|
|
178
|
-
}}
|
|
179
|
-
></script>
|
|
180
|
-
)}
|
|
181
|
-
{errorElement(transformedError)}
|
|
182
|
-
</>
|
|
183
|
-
) : (
|
|
184
|
-
errorElement
|
|
185
|
-
)}
|
|
186
|
-
</>
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
const toRender =
|
|
190
|
-
typeof children === 'function' ? children(data as T) : children;
|
|
191
|
-
return <>{toRender}</>;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// return string when promise is rejected
|
|
195
|
-
const fetchData = <T,>(promise: Promise<T>, ref: MutableRefObject<T>) => {
|
|
196
|
-
let data: T | string;
|
|
197
|
-
let status: 'pending' | 'success' = 'pending';
|
|
198
|
-
const suspender = promise
|
|
199
|
-
.then((res) => {
|
|
200
|
-
status = 'success';
|
|
201
|
-
data = res;
|
|
202
|
-
ref.current = res;
|
|
203
|
-
})
|
|
204
|
-
.catch((e) => {
|
|
205
|
-
status = 'success';
|
|
206
|
-
console.warn(e);
|
|
207
|
-
data = AWAIT_ERROR_PREFIX + e;
|
|
208
|
-
});
|
|
209
|
-
return () => {
|
|
210
|
-
if (status === 'pending') {
|
|
211
|
-
throw suspender;
|
|
212
|
-
}
|
|
213
|
-
return data;
|
|
214
|
-
};
|
|
215
|
-
};
|
package/src/lazy/constant.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
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: ';
|
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
import type { FederationHost, getInstance } from '@module-federation/runtime';
|
|
2
|
-
import type { BasicProviderModuleInfo } from '@module-federation/sdk';
|
|
3
|
-
import React, { ReactNode, useState, useEffect } from 'react';
|
|
4
|
-
import type { ErrorInfo } from './AwaitDataFetch';
|
|
5
|
-
import type { DataFetchParams, NoSSRRemoteInfo } from './types';
|
|
6
|
-
|
|
7
|
-
import logger from './logger';
|
|
8
|
-
import {
|
|
9
|
-
AwaitDataFetch,
|
|
10
|
-
DelayedLoading,
|
|
11
|
-
transformError,
|
|
12
|
-
} from './AwaitDataFetch';
|
|
13
|
-
import {
|
|
14
|
-
fetchData,
|
|
15
|
-
getDataFetchItem,
|
|
16
|
-
getDataFetchMapKey,
|
|
17
|
-
getDataFetchInfo,
|
|
18
|
-
getLoadedRemoteInfos,
|
|
19
|
-
setDataFetchItemLoadedStatus,
|
|
20
|
-
wrapDataFetchId,
|
|
21
|
-
} from './utils';
|
|
22
|
-
import {
|
|
23
|
-
DATA_FETCH_ERROR_PREFIX,
|
|
24
|
-
DATA_FETCH_FUNCTION,
|
|
25
|
-
FS_HREF,
|
|
26
|
-
LOAD_REMOTE_ERROR_PREFIX,
|
|
27
|
-
MF_DATA_FETCH_TYPE,
|
|
28
|
-
} from './constant';
|
|
29
|
-
|
|
30
|
-
export type IProps = {
|
|
31
|
-
id: string;
|
|
32
|
-
instance: ReturnType<typeof getInstance>;
|
|
33
|
-
injectScript?: boolean;
|
|
34
|
-
injectLink?: boolean;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export type CreateLazyComponentOptions<T, E extends keyof T> = {
|
|
38
|
-
loader: () => Promise<T>;
|
|
39
|
-
instance: ReturnType<typeof getInstance>;
|
|
40
|
-
loading: React.ReactNode;
|
|
41
|
-
delayLoading?: number;
|
|
42
|
-
fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode);
|
|
43
|
-
export?: E;
|
|
44
|
-
dataFetchParams?: DataFetchParams;
|
|
45
|
-
// noSSR?: boolean;
|
|
46
|
-
cacheData?: boolean;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
type ReactKey = { key?: React.Key | null };
|
|
50
|
-
|
|
51
|
-
function getTargetModuleInfo(
|
|
52
|
-
id: string,
|
|
53
|
-
instance?: FederationHost,
|
|
54
|
-
):
|
|
55
|
-
| {
|
|
56
|
-
module: BasicProviderModuleInfo['modules'][0];
|
|
57
|
-
publicPath: string;
|
|
58
|
-
remoteEntry: string;
|
|
59
|
-
}
|
|
60
|
-
| undefined {
|
|
61
|
-
if (!instance) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
const loadedRemoteInfo = getLoadedRemoteInfos(id, instance);
|
|
65
|
-
if (!loadedRemoteInfo) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const { snapshot } = loadedRemoteInfo;
|
|
69
|
-
if (!snapshot) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const publicPath: string =
|
|
73
|
-
'publicPath' in snapshot
|
|
74
|
-
? snapshot.publicPath
|
|
75
|
-
: 'getPublicPath' in snapshot
|
|
76
|
-
? new Function(snapshot.getPublicPath)()
|
|
77
|
-
: '';
|
|
78
|
-
if (!publicPath) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const modules = 'modules' in snapshot ? snapshot.modules : [];
|
|
82
|
-
const targetModule = modules.find(
|
|
83
|
-
(m) => m.modulePath === loadedRemoteInfo.expose,
|
|
84
|
-
);
|
|
85
|
-
if (!targetModule) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const remoteEntry = 'remoteEntry' in snapshot ? snapshot.remoteEntry : '';
|
|
90
|
-
if (!remoteEntry) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
module: targetModule,
|
|
95
|
-
publicPath,
|
|
96
|
-
remoteEntry,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function collectSSRAssets(options: IProps) {
|
|
101
|
-
const {
|
|
102
|
-
id,
|
|
103
|
-
injectLink = true,
|
|
104
|
-
injectScript = false,
|
|
105
|
-
} = typeof options === 'string' ? { id: options } : options;
|
|
106
|
-
const links: React.ReactNode[] = [];
|
|
107
|
-
const scripts: React.ReactNode[] = [];
|
|
108
|
-
const instance = options.instance;
|
|
109
|
-
if (!instance || (!injectLink && !injectScript)) {
|
|
110
|
-
return [...scripts, ...links];
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const moduleAndPublicPath = getTargetModuleInfo(id, instance);
|
|
114
|
-
if (!moduleAndPublicPath) {
|
|
115
|
-
return [...scripts, ...links];
|
|
116
|
-
}
|
|
117
|
-
const { module: targetModule, publicPath, remoteEntry } = moduleAndPublicPath;
|
|
118
|
-
if (injectLink) {
|
|
119
|
-
[...targetModule.assets.css.sync, ...targetModule.assets.css.async]
|
|
120
|
-
.sort()
|
|
121
|
-
.forEach((file, index) => {
|
|
122
|
-
links.push(
|
|
123
|
-
<link
|
|
124
|
-
key={`${file.split('.')[0]}_${index}`}
|
|
125
|
-
href={`${publicPath}${file}`}
|
|
126
|
-
rel="stylesheet"
|
|
127
|
-
type="text/css"
|
|
128
|
-
/>,
|
|
129
|
-
);
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (injectScript) {
|
|
134
|
-
scripts.push(
|
|
135
|
-
<script
|
|
136
|
-
async={true}
|
|
137
|
-
key={remoteEntry.split('.')[0]}
|
|
138
|
-
src={`${publicPath}${remoteEntry}`}
|
|
139
|
-
crossOrigin="anonymous"
|
|
140
|
-
/>,
|
|
141
|
-
);
|
|
142
|
-
[...targetModule.assets.js.sync].sort().forEach((file, index) => {
|
|
143
|
-
scripts.push(
|
|
144
|
-
<script
|
|
145
|
-
key={`${file.split('.')[0]}_${index}`}
|
|
146
|
-
async={true}
|
|
147
|
-
src={`${publicPath}${file}`}
|
|
148
|
-
crossOrigin="anonymous"
|
|
149
|
-
/>,
|
|
150
|
-
);
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return [...scripts, ...links];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function getServerNeedRemoteInfo(
|
|
158
|
-
loadedRemoteInfo: ReturnType<typeof getLoadedRemoteInfos>,
|
|
159
|
-
id: string,
|
|
160
|
-
// noSSR?: boolean,
|
|
161
|
-
): NoSSRRemoteInfo | undefined {
|
|
162
|
-
if (
|
|
163
|
-
// noSSR ||
|
|
164
|
-
typeof window !== 'undefined' &&
|
|
165
|
-
window.location.href !== window[FS_HREF]
|
|
166
|
-
) {
|
|
167
|
-
if (!loadedRemoteInfo?.version) {
|
|
168
|
-
throw new Error(`${loadedRemoteInfo?.name} version is empty`);
|
|
169
|
-
}
|
|
170
|
-
const { snapshot } = loadedRemoteInfo;
|
|
171
|
-
if (!snapshot) {
|
|
172
|
-
throw new Error(`${loadedRemoteInfo?.name} snapshot is empty`);
|
|
173
|
-
}
|
|
174
|
-
const dataFetchItem = getDataFetchItem(id);
|
|
175
|
-
const isFetchServer =
|
|
176
|
-
dataFetchItem?.[0]?.[1] === MF_DATA_FETCH_TYPE.FETCH_SERVER;
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
isFetchServer &&
|
|
180
|
-
(!('ssrPublicPath' in snapshot) || !snapshot.ssrPublicPath)
|
|
181
|
-
) {
|
|
182
|
-
throw new Error(
|
|
183
|
-
`ssrPublicPath is required while fetching ${loadedRemoteInfo?.name} data in SSR project!`,
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (
|
|
188
|
-
isFetchServer &&
|
|
189
|
-
(!('ssrRemoteEntry' in snapshot) || !snapshot.ssrRemoteEntry)
|
|
190
|
-
) {
|
|
191
|
-
throw new Error(
|
|
192
|
-
`ssrRemoteEntry is required while loading ${loadedRemoteInfo?.name} data loader in SSR project!`,
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return {
|
|
197
|
-
name: loadedRemoteInfo.name,
|
|
198
|
-
version: loadedRemoteInfo.version,
|
|
199
|
-
ssrPublicPath:
|
|
200
|
-
'ssrPublicPath' in snapshot ? snapshot.ssrPublicPath || '' : '',
|
|
201
|
-
ssrRemoteEntry:
|
|
202
|
-
'ssrRemoteEntry' in snapshot ? snapshot.ssrRemoteEntry || '' : '',
|
|
203
|
-
globalName: loadedRemoteInfo.entryGlobalName,
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
return undefined;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export function createLazyComponent<T, E extends keyof T>(
|
|
210
|
-
options: CreateLazyComponentOptions<T, E>,
|
|
211
|
-
) {
|
|
212
|
-
const { instance, cacheData } = options;
|
|
213
|
-
if (!instance) {
|
|
214
|
-
throw new Error('instance is required for createLazyComponent!');
|
|
215
|
-
}
|
|
216
|
-
let dataCache: unknown = null;
|
|
217
|
-
|
|
218
|
-
type ComponentType = T[E] extends (...args: any) => any
|
|
219
|
-
? Parameters<T[E]>[0] extends undefined
|
|
220
|
-
? ReactKey
|
|
221
|
-
: Parameters<T[E]>[0] & ReactKey
|
|
222
|
-
: ReactKey;
|
|
223
|
-
const exportName = options?.export || 'default';
|
|
224
|
-
|
|
225
|
-
const callLoader = async () => {
|
|
226
|
-
logger.debug('callLoader start', Date.now());
|
|
227
|
-
const m = (await options.loader()) as Record<string, React.FC> &
|
|
228
|
-
Record<symbol, string>;
|
|
229
|
-
logger.debug('callLoader end', Date.now());
|
|
230
|
-
if (!m) {
|
|
231
|
-
throw new Error('load remote failed');
|
|
232
|
-
}
|
|
233
|
-
return m;
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
// const getData = async (noSSR?: boolean) => {
|
|
237
|
-
const getData = async () => {
|
|
238
|
-
let loadedRemoteInfo: ReturnType<typeof getLoadedRemoteInfos>;
|
|
239
|
-
let moduleId: string;
|
|
240
|
-
try {
|
|
241
|
-
const m = await callLoader();
|
|
242
|
-
moduleId = m && m[Symbol.for('mf_module_id')];
|
|
243
|
-
if (!moduleId) {
|
|
244
|
-
throw new Error('moduleId is empty');
|
|
245
|
-
}
|
|
246
|
-
loadedRemoteInfo = getLoadedRemoteInfos(moduleId, instance);
|
|
247
|
-
if (!loadedRemoteInfo) {
|
|
248
|
-
throw new Error(`can not find loaded remote('${moduleId}') info!`);
|
|
249
|
-
}
|
|
250
|
-
} catch (e) {
|
|
251
|
-
const errMsg = `${LOAD_REMOTE_ERROR_PREFIX}${e}`;
|
|
252
|
-
logger.debug(e);
|
|
253
|
-
throw new Error(errMsg);
|
|
254
|
-
}
|
|
255
|
-
let dataFetchMapKey: string | undefined;
|
|
256
|
-
try {
|
|
257
|
-
dataFetchMapKey = getDataFetchMapKey(
|
|
258
|
-
getDataFetchInfo({
|
|
259
|
-
name: loadedRemoteInfo.name,
|
|
260
|
-
alias: loadedRemoteInfo.alias,
|
|
261
|
-
id: moduleId,
|
|
262
|
-
remoteSnapshot: loadedRemoteInfo.snapshot,
|
|
263
|
-
}),
|
|
264
|
-
{ name: instance.name, version: instance.options.version },
|
|
265
|
-
);
|
|
266
|
-
logger.debug('getData dataFetchMapKey: ', dataFetchMapKey);
|
|
267
|
-
if (!dataFetchMapKey) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
const data = await fetchData(
|
|
271
|
-
dataFetchMapKey,
|
|
272
|
-
{
|
|
273
|
-
...options.dataFetchParams,
|
|
274
|
-
isDowngrade: false,
|
|
275
|
-
},
|
|
276
|
-
// getServerNeedRemoteInfo(loadedRemoteInfo, dataFetchMapKey, noSSR),
|
|
277
|
-
getServerNeedRemoteInfo(loadedRemoteInfo, dataFetchMapKey),
|
|
278
|
-
);
|
|
279
|
-
setDataFetchItemLoadedStatus(dataFetchMapKey);
|
|
280
|
-
logger.debug('get data res: \n', data);
|
|
281
|
-
dataCache = data;
|
|
282
|
-
return data;
|
|
283
|
-
} catch (err) {
|
|
284
|
-
const errMsg = `${DATA_FETCH_ERROR_PREFIX}${wrapDataFetchId(dataFetchMapKey)}${err}`;
|
|
285
|
-
logger.debug(errMsg);
|
|
286
|
-
throw new Error(errMsg);
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
const LazyComponent = React.lazy(async () => {
|
|
291
|
-
const m = await callLoader();
|
|
292
|
-
const moduleId = m && m[Symbol.for('mf_module_id')];
|
|
293
|
-
const loadedRemoteInfo = getLoadedRemoteInfos(moduleId, instance);
|
|
294
|
-
loadedRemoteInfo?.snapshot;
|
|
295
|
-
const dataFetchMapKey = loadedRemoteInfo
|
|
296
|
-
? getDataFetchMapKey(
|
|
297
|
-
getDataFetchInfo({
|
|
298
|
-
name: loadedRemoteInfo.name,
|
|
299
|
-
alias: loadedRemoteInfo.alias,
|
|
300
|
-
id: moduleId,
|
|
301
|
-
remoteSnapshot: loadedRemoteInfo.snapshot,
|
|
302
|
-
}),
|
|
303
|
-
{ name: instance.name, version: instance?.options.version },
|
|
304
|
-
)
|
|
305
|
-
: undefined;
|
|
306
|
-
logger.debug('LazyComponent dataFetchMapKey: ', dataFetchMapKey);
|
|
307
|
-
|
|
308
|
-
const assets = collectSSRAssets({
|
|
309
|
-
id: moduleId,
|
|
310
|
-
instance,
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
const Com = m[exportName] as React.FC<ComponentType>;
|
|
314
|
-
if (exportName in m && typeof Com === 'function') {
|
|
315
|
-
return {
|
|
316
|
-
default: (props: Omit<ComponentType, 'key'> & { mfData?: unknown }) => (
|
|
317
|
-
<>
|
|
318
|
-
{globalThis.FEDERATION_SSR && dataFetchMapKey && (
|
|
319
|
-
<script
|
|
320
|
-
suppressHydrationWarning
|
|
321
|
-
dangerouslySetInnerHTML={{
|
|
322
|
-
__html: String.raw`
|
|
323
|
-
globalThis['${DATA_FETCH_FUNCTION}'] = globalThis['${DATA_FETCH_FUNCTION}'] || [];
|
|
324
|
-
globalThis['${DATA_FETCH_FUNCTION}'].push(['${dataFetchMapKey}',${JSON.stringify(props.mfData)}]);
|
|
325
|
-
`,
|
|
326
|
-
}}
|
|
327
|
-
></script>
|
|
328
|
-
)}
|
|
329
|
-
{globalThis.FEDERATION_SSR && assets}
|
|
330
|
-
<Com {...props} />
|
|
331
|
-
</>
|
|
332
|
-
),
|
|
333
|
-
};
|
|
334
|
-
// eslint-disable-next-line max-lines
|
|
335
|
-
} else {
|
|
336
|
-
throw Error(
|
|
337
|
-
`Make sure that ${moduleId} has the correct export when export is ${String(
|
|
338
|
-
exportName,
|
|
339
|
-
)}`,
|
|
340
|
-
);
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
return (props: ComponentType) => {
|
|
345
|
-
const { key, ...args } = props;
|
|
346
|
-
if (cacheData && dataCache) {
|
|
347
|
-
// @ts-expect-error ignore
|
|
348
|
-
return <LazyComponent {...args} mfData={dataCache} />;
|
|
349
|
-
}
|
|
350
|
-
return (
|
|
351
|
-
<AwaitDataFetch
|
|
352
|
-
// resolve={getData(options.noSSR)}
|
|
353
|
-
resolve={getData()}
|
|
354
|
-
loading={options.loading}
|
|
355
|
-
delayLoading={options.delayLoading}
|
|
356
|
-
errorElement={options.fallback}
|
|
357
|
-
>
|
|
358
|
-
{/* @ts-expect-error ignore */}
|
|
359
|
-
{(data) => <LazyComponent {...args} mfData={data} />}
|
|
360
|
-
</AwaitDataFetch>
|
|
361
|
-
);
|
|
362
|
-
// if (!options.noSSR) {
|
|
363
|
-
|
|
364
|
-
// } else {
|
|
365
|
-
// // Client-side rendering logic
|
|
366
|
-
// const [data, setData] = useState<unknown>(null);
|
|
367
|
-
// const [loading, setLoading] = useState<boolean>(true);
|
|
368
|
-
// const [error, setError] = useState<ErrorInfo | null>(null);
|
|
369
|
-
|
|
370
|
-
// useEffect(() => {
|
|
371
|
-
// let isMounted = true;
|
|
372
|
-
// const fetchDataAsync = async () => {
|
|
373
|
-
// try {
|
|
374
|
-
// setLoading(true);
|
|
375
|
-
// const result = await getData(options.noSSR);
|
|
376
|
-
// if (isMounted) {
|
|
377
|
-
// setData(result);
|
|
378
|
-
// }
|
|
379
|
-
// } catch (e) {
|
|
380
|
-
// if (isMounted) {
|
|
381
|
-
// setError(transformError(e as Error));
|
|
382
|
-
// }
|
|
383
|
-
// } finally {
|
|
384
|
-
// if (isMounted) {
|
|
385
|
-
// setLoading(false);
|
|
386
|
-
// }
|
|
387
|
-
// }
|
|
388
|
-
// };
|
|
389
|
-
|
|
390
|
-
// fetchDataAsync();
|
|
391
|
-
|
|
392
|
-
// return () => {
|
|
393
|
-
// isMounted = false;
|
|
394
|
-
// };
|
|
395
|
-
// }, []);
|
|
396
|
-
|
|
397
|
-
// if (loading) {
|
|
398
|
-
// return (
|
|
399
|
-
// <DelayedLoading delayLoading={options.delayLoading}>
|
|
400
|
-
// {options.loading}
|
|
401
|
-
// </DelayedLoading>
|
|
402
|
-
// );
|
|
403
|
-
// }
|
|
404
|
-
|
|
405
|
-
// if (error) {
|
|
406
|
-
// return (
|
|
407
|
-
// <>
|
|
408
|
-
// {typeof options.fallback === 'function'
|
|
409
|
-
// ? options.fallback(error)
|
|
410
|
-
// : options.fallback}
|
|
411
|
-
// </>
|
|
412
|
-
// );
|
|
413
|
-
// }
|
|
414
|
-
// // @ts-expect-error ignore
|
|
415
|
-
// return <LazyComponent {...args} mfData={data} />;
|
|
416
|
-
// }
|
|
417
|
-
};
|
|
418
|
-
}
|