Skip to content

Commit 8ff85f2

Browse files
authored
feat: support inject dev lib with eager mode (#4193)
1 parent c78e996 commit 8ff85f2

File tree

4 files changed

+109
-7
lines changed

4 files changed

+109
-7
lines changed

.changeset/famous-months-learn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@module-federation/devtools': patch
3+
---
4+
5+
feat(chrome-devtools): support inject dev lib with eager mode

packages/chrome-devtools/src/component/Layout/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
__ENABLE_FAST_REFRESH__,
3434
BROWSER_ENV_KEY,
3535
__FEDERATION_DEVTOOLS__,
36+
__EAGER_SHARE__,
3637
} from '../../template/constant';
3738
interface FormItemType {
3839
key: string;
@@ -197,6 +198,7 @@ const Layout = (
197198
mergeStorage(__FEDERATION_DEVTOOLS__, __ENABLE_FAST_REFRESH__, on);
198199
} else {
199200
removeStorageKey(__FEDERATION_DEVTOOLS__, __ENABLE_FAST_REFRESH__);
201+
removeStorageKey(__FEDERATION_DEVTOOLS__, __EAGER_SHARE__);
200202
}
201203
injectScript(reloadPage, false);
202204
};

packages/chrome-devtools/src/template/constant.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const statusInfo: Record<
5151
};
5252

5353
export const __ENABLE_FAST_REFRESH__ = 'enableFastRefresh';
54+
export const __EAGER_SHARE__ = 'eagerShare';
5455

5556
export const BROWSER_ENV_KEY = 'MF_ENV';
5657

packages/chrome-devtools/src/utils/chrome/fast-refresh.ts

Lines changed: 101 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,99 @@ import type {
22
ModuleFederationRuntimePlugin,
33
Shared,
44
} from '@module-federation/runtime/types';
5-
import { loadScript } from '@module-federation/sdk';
5+
import { loadScript, createScript } from '@module-federation/sdk';
66

77
import { isObject, getUnpkgUrl } from '../index';
88
import { definePropertyGlobalVal } from '../sdk';
9-
import { __FEDERATION_DEVTOOLS__ } from '../../template';
9+
import {
10+
__FEDERATION_DEVTOOLS__,
11+
__EAGER_SHARE__,
12+
__ENABLE_FAST_REFRESH__,
13+
} from '../../template/constant';
14+
15+
const SUPPORT_PKGS = ['react', 'react-dom'];
16+
17+
/**
18+
* Fetch and execute a UMD module synchronously
19+
* @param url - URL of the UMD module to load
20+
* @returns The module exports
21+
*/
22+
const fetchAndExecuteUmdSync = (url: string): any => {
23+
try {
24+
const response = new XMLHttpRequest();
25+
response.open('GET', url, false);
26+
response.overrideMimeType('text/plain');
27+
response.send();
28+
29+
if (response.status === 200) {
30+
const scriptContent = response.responseText;
31+
32+
// Create a new Function constructor to execute the script synchronously
33+
const moduleFunction = new Function(scriptContent);
34+
35+
// Execute the function and return the module exports
36+
return moduleFunction(window);
37+
} else {
38+
throw new Error(
39+
`Failed to load module from ${url}: HTTP ${response.status}`,
40+
);
41+
}
42+
} catch (error: any) {
43+
throw new Error(`Failed to fetch module from ${url}: ${error.message}`);
44+
}
45+
};
46+
47+
const getDevtoolsMessage = () => {
48+
const devtoolsMessageStr = localStorage.getItem(__FEDERATION_DEVTOOLS__);
49+
if (devtoolsMessageStr) {
50+
try {
51+
return JSON.parse(devtoolsMessageStr);
52+
} catch (e) {
53+
console.debug('Fast Refresh Plugin Error: ', e);
54+
}
55+
}
56+
return null;
57+
};
58+
59+
const devtoolsMessage = getDevtoolsMessage();
60+
if (
61+
devtoolsMessage?.[__ENABLE_FAST_REFRESH__] &&
62+
devtoolsMessage?.[__EAGER_SHARE__]
63+
) {
64+
// eagerShare is [react, 19.0.0]
65+
const [_name, version] = devtoolsMessage[__EAGER_SHARE__] as [string, string];
66+
fetchAndExecuteUmdSync(getUnpkgUrl('react', version) as string);
67+
fetchAndExecuteUmdSync(getUnpkgUrl('react-dom', version) as string);
68+
}
1069

1170
const fastRefreshPlugin = (): ModuleFederationRuntimePlugin => {
1271
return {
1372
name: 'mf-fast-refresh-plugin',
1473
beforeInit({ userOptions, ...args }) {
1574
const shareInfo = userOptions.shared;
1675
const twinsShareInfo = args.shareInfo;
17-
let enableFastRefresh: boolean;
18-
let devtoolsMessage;
76+
let enableFastRefresh = false;
77+
let devtoolsMessage: Record<string, unknown> = {};
1978

2079
const devtoolsMessageStr = localStorage.getItem(__FEDERATION_DEVTOOLS__);
2180
if (devtoolsMessageStr) {
2281
try {
2382
devtoolsMessage = JSON.parse(devtoolsMessageStr);
24-
enableFastRefresh = devtoolsMessage?.enableFastRefresh;
83+
enableFastRefresh = devtoolsMessage?.[
84+
__ENABLE_FAST_REFRESH__
85+
] as boolean;
2586
} catch (e) {
2687
console.debug('Fast Refresh Plugin Error: ', e);
2788
}
2889
}
2990

91+
if (!enableFastRefresh) {
92+
return {
93+
userOptions,
94+
...args,
95+
};
96+
}
97+
3098
if (shareInfo && isObject(shareInfo)) {
3199
let orderResolve: (value?: unknown) => void;
32100
const orderPromise = new Promise((resolve) => {
@@ -47,11 +115,37 @@ const fastRefreshPlugin = (): ModuleFederationRuntimePlugin => {
47115
}
48116

49117
sharedArr.forEach((shared, idx) => {
118+
if (!SUPPORT_PKGS.includes(share)) {
119+
return;
120+
}
121+
if (shared.shareConfig?.eager) {
122+
if (!devtoolsMessage?.[__EAGER_SHARE__]) {
123+
const eagerShare: string[] = [];
124+
eagerShare.push(share, shared.version);
125+
devtoolsMessage[__EAGER_SHARE__] = eagerShare;
126+
localStorage.setItem(
127+
__FEDERATION_DEVTOOLS__,
128+
JSON.stringify(devtoolsMessage),
129+
);
130+
window.location.reload();
131+
}
132+
if (share === 'react-dom') {
133+
shared.lib = () => window.ReactDOM;
134+
}
135+
if (share === 'react') {
136+
shared.lib = () => window.React;
137+
}
138+
return;
139+
}
50140
let get: () => any;
51141
if (share === 'react') {
52142
get = () =>
53143
loadScript(getUnpkgUrl(share, shared.version) as string, {
54-
attrs: { defer: true, async: false },
144+
attrs: {
145+
defer: false,
146+
async: false,
147+
'data-mf-injected': 'true',
148+
},
55149
}).then(() => {
56150
orderResolve();
57151
});
@@ -65,7 +159,7 @@ const fastRefreshPlugin = (): ModuleFederationRuntimePlugin => {
65159
);
66160
}
67161
// @ts-expect-error
68-
if (enableFastRefresh && typeof get === 'function') {
162+
if (typeof get === 'function') {
69163
if (share === 'react') {
70164
shared.get = async () => {
71165
if (!window.React) {

0 commit comments

Comments
 (0)