remote-reload-utils 0.0.14 → 0.0.17

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/dist/main.cjs CHANGED
@@ -1,25 +1,5 @@
1
- var __webpack_modules__ = {
2
- "./src/styles/index.css": function() {}
3
- };
4
- var __webpack_module_cache__ = {};
5
- function __webpack_require__(moduleId) {
6
- var cachedModule = __webpack_module_cache__[moduleId];
7
- if (void 0 !== cachedModule) return cachedModule.exports;
8
- var module = __webpack_module_cache__[moduleId] = {
9
- exports: {}
10
- };
11
- __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
12
- return module.exports;
13
- }
14
- (()=>{
15
- __webpack_require__.n = (module)=>{
16
- var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
17
- __webpack_require__.d(getter, {
18
- a: getter
19
- });
20
- return getter;
21
- };
22
- })();
1
+ "use strict";
2
+ var __webpack_require__ = {};
23
3
  (()=>{
24
4
  __webpack_require__.d = (exports1, definition)=>{
25
5
  for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
@@ -42,1042 +22,916 @@ function __webpack_require__(moduleId) {
42
22
  };
43
23
  })();
44
24
  var __webpack_exports__ = {};
45
- (()=>{
46
- "use strict";
47
- __webpack_require__.r(__webpack_exports__);
48
- __webpack_require__.d(__webpack_exports__, {
49
- compareVersions: ()=>compareVersions,
50
- fetchAvailableVersions: ()=>fetchAvailableVersions,
51
- sortVersions: ()=>sortVersions,
52
- useRemoteModuleHook: ()=>useRemoteModuleHook,
53
- registerRemoteInstance: ()=>registerRemoteInstance,
54
- fallbackPlugin: ()=>fallbackPlugin,
55
- createEventBus: ()=>createEventBus,
56
- withRemote: ()=>withRemote,
57
- getPreloadStatus: ()=>getPreloadStatus,
58
- parseVersion: ()=>parseVersion,
59
- resolveFinalVersion: ()=>resolveFinalVersion,
60
- buildFinalUrls: ()=>buildFinalUrls,
61
- fetchLatestVersion: ()=>fetchLatestVersion,
62
- ErrorBoundary: ()=>ErrorBoundary,
63
- getFinalSharedConfig: ()=>getFinalSharedConfig,
64
- isRemoteLoaded: ()=>isRemoteLoaded,
65
- tryLoadRemote: ()=>tryLoadRemote,
66
- getVersionCache: ()=>getVersionCache,
67
- eventBus: ()=>eventBus,
68
- RemoteModuleRenderer: ()=>RemoteModuleRenderer,
69
- clearPreloadCache: ()=>clearPreloadCache,
70
- loadRemoteMultiVersion: ()=>loadRemoteMultiVersion,
71
- getRemoteHealthReport: ()=>getRemoteHealthReport,
72
- checkModuleLoadable: ()=>checkModuleLoadable,
73
- getStableVersions: ()=>getStableVersions,
74
- extractMajorVersion: ()=>extractMajorVersion,
75
- buildCdnUrls: ()=>buildCdnUrls,
76
- loadReactVersion: ()=>loadReactVersion,
77
- preloadRemoteList: ()=>preloadRemoteList,
78
- SuspenseRemoteLoader: ()=>SuspenseRemoteLoader,
79
- registerLoadedModule: ()=>registerLoadedModule,
80
- getCompatibleReactVersions: ()=>getCompatibleReactVersions,
81
- SuspenseRemote: ()=>SuspenseRemote,
82
- unloadRemote: ()=>unloadRemote,
83
- useRemoteModule: ()=>useRemoteModule,
84
- RemoteModuleProvider: ()=>RemoteModuleProvider,
85
- cancelPreload: ()=>cancelPreload,
86
- findCompatibleVersion: ()=>findCompatibleVersion,
87
- getLoadedRemotes: ()=>getLoadedRemotes,
88
- getLatestVersion: ()=>getLatestVersion,
89
- preloadRemote: ()=>preloadRemote,
90
- satisfiesVersion: ()=>satisfiesVersion,
91
- formatHealthStatus: ()=>formatHealthStatus,
92
- unloadAll: ()=>unloadAll,
93
- setVersionCache: ()=>setVersionCache,
94
- lazyRemote: ()=>lazyRemote,
95
- checkRemoteHealth: ()=>checkRemoteHealth,
96
- isPrerelease: ()=>isPrerelease,
97
- checkVersionCompatibility: ()=>checkVersionCompatibility
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ compareVersions: ()=>compareVersions,
28
+ fetchAvailableVersions: ()=>fetchAvailableVersions,
29
+ sortVersions: ()=>sortVersions,
30
+ registerRemoteInstance: ()=>registerRemoteInstance,
31
+ fallbackPlugin: ()=>fallbackPlugin,
32
+ createEventBus: ()=>createEventBus,
33
+ getPreloadStatus: ()=>getPreloadStatus,
34
+ parseVersion: ()=>parseVersion,
35
+ resolveFinalVersion: ()=>resolveFinalVersion,
36
+ buildFinalUrls: ()=>buildFinalUrls,
37
+ fetchLatestVersion: ()=>fetchLatestVersion,
38
+ isRemoteLoaded: ()=>isRemoteLoaded,
39
+ getFinalSharedConfig: ()=>getFinalSharedConfig,
40
+ tryLoadRemote: ()=>tryLoadRemote,
41
+ getVersionCache: ()=>getVersionCache,
42
+ eventBus: ()=>eventBus,
43
+ loadRemoteMultiVersion: ()=>loadRemoteMultiVersion,
44
+ clearPreloadCache: ()=>clearPreloadCache,
45
+ loadReactVersion: ()=>loadReactVersion,
46
+ getRemoteHealthReport: ()=>getRemoteHealthReport,
47
+ getStableVersions: ()=>getStableVersions,
48
+ checkModuleLoadable: ()=>checkModuleLoadable,
49
+ buildCdnUrls: ()=>buildCdnUrls,
50
+ extractMajorVersion: ()=>extractMajorVersion,
51
+ preloadRemoteList: ()=>preloadRemoteList,
52
+ registerLoadedModule: ()=>registerLoadedModule,
53
+ unloadRemote: ()=>unloadRemote,
54
+ getCompatibleReactVersions: ()=>getCompatibleReactVersions,
55
+ cancelPreload: ()=>cancelPreload,
56
+ findCompatibleVersion: ()=>findCompatibleVersion,
57
+ getLoadedRemotes: ()=>getLoadedRemotes,
58
+ getLatestVersion: ()=>getLatestVersion,
59
+ preloadRemote: ()=>preloadRemote,
60
+ satisfiesVersion: ()=>satisfiesVersion,
61
+ formatHealthStatus: ()=>formatHealthStatus,
62
+ unloadAll: ()=>unloadAll,
63
+ createRemoteSourcePlugin: ()=>createRemoteSourcePlugin,
64
+ setVersionCache: ()=>setVersionCache,
65
+ isPrerelease: ()=>isPrerelease,
66
+ checkRemoteHealth: ()=>checkRemoteHealth,
67
+ checkVersionCompatibility: ()=>checkVersionCompatibility
68
+ });
69
+ const runtime_namespaceObject = require("@module-federation/enhanced/runtime");
70
+ async function loadReactVersion(version) {
71
+ const runtime = await (0, runtime_namespaceObject.createInstance)({
72
+ name: `react_${version}_runtime`,
73
+ remotes: [
74
+ {
75
+ name: `react@${version}`,
76
+ entry: `https://cdn.jsdelivr.net/npm/react@${version}/umd/react.production.min.js`,
77
+ type: 'var',
78
+ entryGlobalName: 'React'
79
+ },
80
+ {
81
+ name: `react-dom@${version}`,
82
+ entry: `https://cdn.jsdelivr.net/npm/react-dom@${version}/umd/react-dom.production.min.js`,
83
+ type: 'var',
84
+ entryGlobalName: 'ReactDOM'
85
+ }
86
+ ]
98
87
  });
99
- __webpack_require__("./src/styles/index.css");
100
- const runtime_namespaceObject = require("@module-federation/enhanced/runtime");
101
- async function loadReactVersion(version) {
102
- const runtime = await (0, runtime_namespaceObject.createInstance)({
103
- name: `react_${version}_runtime`,
104
- remotes: [
105
- {
106
- name: `react@${version}`,
107
- entry: `https://cdn.jsdelivr.net/npm/react@${version}/umd/react.production.min.js`,
108
- type: 'var',
109
- entryGlobalName: 'React'
110
- },
111
- {
112
- name: `react-dom@${version}`,
113
- entry: `https://cdn.jsdelivr.net/npm/react-dom@${version}/umd/react-dom.production.min.js`,
114
- type: 'var',
115
- entryGlobalName: 'ReactDOM'
116
- }
117
- ]
118
- });
119
- const React = await runtime.loadRemote(`react@${version}`);
120
- const ReactDOM = await runtime.loadRemote(`react-dom@${version}`);
121
- return {
122
- React,
123
- ReactDOM
124
- };
125
- }
126
- function parseVersion(version) {
127
- const cleaned = version.replace(/^v/i, '');
128
- const parts = cleaned.split(/[-+]/);
129
- const [major, minor, patch] = parts[0].split('.').map(Number);
130
- return {
131
- major: isNaN(major) ? 0 : major,
132
- minor: isNaN(minor) ? 0 : minor,
133
- patch: isNaN(patch) ? 0 : patch,
134
- prerelease: parts[1],
135
- build: parts[2],
136
- raw: cleaned
137
- };
138
- }
139
- function compareVersions(v1, v2) {
140
- const p1 = parseVersion(v1);
141
- const p2 = parseVersion(v2);
142
- if (p1.major !== p2.major) return p1.major - p2.major;
143
- if (p1.minor !== p2.minor) return p1.minor - p2.minor;
144
- if (p1.patch !== p2.patch) return p1.patch - p2.patch;
145
- if (p1.prerelease && !p2.prerelease) return -1;
146
- if (!p1.prerelease && p2.prerelease) return 1;
147
- if (p1.prerelease && p2.prerelease) return p1.prerelease.localeCompare(p2.prerelease);
148
- return 0;
149
- }
150
- function satisfiesVersion(current, required) {
151
- const opMatch = required.match(/^(>=|<=|>|<|=|~|\^)?/);
152
- const operator = opMatch?.[1] || '=';
153
- const version = required.replace(/^(>=|<=|>|<|=|~|\^)/, '');
154
- const cmp = compareVersions(current, version);
155
- switch(operator){
156
- case '>':
157
- return cmp > 0;
158
- case '>=':
159
- return cmp >= 0;
160
- case '<':
161
- return cmp < 0;
162
- case '<=':
163
- return cmp <= 0;
164
- case '=':
165
- case '':
166
- return 0 === cmp;
167
- case '^':
168
- return parseVersion(current).major === parseVersion(version).major && (parseVersion(current).major > 0 || parseVersion(current).minor === parseVersion(version).minor);
169
- case '~':
170
- return parseVersion(current).major === parseVersion(version).major && parseVersion(current).minor === parseVersion(version).minor;
171
- default:
172
- return 0 === cmp;
173
- }
88
+ const React = await runtime.loadRemote(`react@${version}`);
89
+ const ReactDOM = await runtime.loadRemote(`react-dom@${version}`);
90
+ return {
91
+ React,
92
+ ReactDOM
93
+ };
94
+ }
95
+ function parseVersion(version) {
96
+ const cleaned = version.replace(/^v/i, '');
97
+ const parts = cleaned.split(/[-+]/);
98
+ const [major, minor, patch] = parts[0].split('.').map(Number);
99
+ return {
100
+ major: isNaN(major) ? 0 : major,
101
+ minor: isNaN(minor) ? 0 : minor,
102
+ patch: isNaN(patch) ? 0 : patch,
103
+ prerelease: parts[1],
104
+ build: parts[2],
105
+ raw: cleaned
106
+ };
107
+ }
108
+ function compareVersions(v1, v2) {
109
+ const p1 = parseVersion(v1);
110
+ const p2 = parseVersion(v2);
111
+ if (p1.major !== p2.major) return p1.major - p2.major;
112
+ if (p1.minor !== p2.minor) return p1.minor - p2.minor;
113
+ if (p1.patch !== p2.patch) return p1.patch - p2.patch;
114
+ if (p1.prerelease && !p2.prerelease) return -1;
115
+ if (!p1.prerelease && p2.prerelease) return 1;
116
+ if (p1.prerelease && p2.prerelease) return p1.prerelease.localeCompare(p2.prerelease);
117
+ return 0;
118
+ }
119
+ function satisfiesVersion(current, required) {
120
+ const opMatch = required.match(/^(>=|<=|>|<|=|~|\^)?/);
121
+ const operator = opMatch?.[1] || '=';
122
+ const version = required.replace(/^(>=|<=|>|<|=|~|\^)/, '');
123
+ const cmp = compareVersions(current, version);
124
+ switch(operator){
125
+ case '>':
126
+ return cmp > 0;
127
+ case '>=':
128
+ return cmp >= 0;
129
+ case '<':
130
+ return cmp < 0;
131
+ case '<=':
132
+ return cmp <= 0;
133
+ case '=':
134
+ case '':
135
+ return 0 === cmp;
136
+ case '^':
137
+ return parseVersion(current).major === parseVersion(version).major && (parseVersion(current).major > 0 || parseVersion(current).minor === parseVersion(version).minor);
138
+ case '~':
139
+ return parseVersion(current).major === parseVersion(version).major && parseVersion(current).minor === parseVersion(version).minor;
140
+ default:
141
+ return 0 === cmp;
174
142
  }
175
- function checkVersionCompatibility(currentVersion, requiredVersion, packageName) {
176
- const isCompatible = satisfiesVersion(currentVersion, requiredVersion);
177
- const current = parseVersion(currentVersion);
178
- const required = parseVersion(requiredVersion);
179
- let message;
180
- let suggestion;
181
- let severity;
182
- if (isCompatible) {
183
- message = `${packageName}@${currentVersion} 满足要求 ${requiredVersion}`;
184
- severity = 'info';
143
+ }
144
+ function checkVersionCompatibility(currentVersion, requiredVersion, packageName) {
145
+ const isCompatible = satisfiesVersion(currentVersion, requiredVersion);
146
+ const current = parseVersion(currentVersion);
147
+ const required = parseVersion(requiredVersion);
148
+ let message;
149
+ let suggestion;
150
+ let severity;
151
+ if (isCompatible) {
152
+ message = `${packageName}@${currentVersion} 满足要求 ${requiredVersion}`;
153
+ severity = 'info';
154
+ } else {
155
+ const cmp = compareVersions(currentVersion, requiredVersion);
156
+ if (cmp < 0) {
157
+ message = `${packageName}@${currentVersion} 版本过低,需要 ${requiredVersion}`;
158
+ severity = 'error';
159
+ current.patch;
160
+ current.major, current.minor;
161
+ suggestion = `建议升级到 ${current.major}.${current.minor}.x 或更高版本`;
185
162
  } else {
186
- const cmp = compareVersions(currentVersion, requiredVersion);
187
- if (cmp < 0) {
188
- message = `${packageName}@${currentVersion} 版本过低,需要 ${requiredVersion}`;
189
- severity = 'error';
190
- current.patch;
191
- current.major, current.minor;
192
- suggestion = `建议升级到 ${current.major}.${current.minor}.x 或更高版本`;
193
- } else {
194
- message = `${packageName}@${currentVersion} 版本过高,需要 ${requiredVersion}`;
195
- severity = 'warning';
196
- suggestion = `建议降级到 ${required.major}.${required.minor}.x 或匹配主版本的兼容版本`;
197
- }
198
- }
199
- return {
200
- compatible: isCompatible,
201
- currentVersion,
202
- requiredVersion,
203
- suggestion,
204
- severity,
205
- message
206
- };
163
+ message = `${packageName}@${currentVersion} 版本过高,需要 ${requiredVersion}`;
164
+ severity = 'warning';
165
+ suggestion = `建议降级到 ${required.major}.${required.minor}.x 或匹配主版本的兼容版本`;
166
+ }
167
+ }
168
+ return {
169
+ compatible: isCompatible,
170
+ currentVersion,
171
+ requiredVersion,
172
+ suggestion,
173
+ severity,
174
+ message
175
+ };
176
+ }
177
+ function findCompatibleVersion(availableVersions, range) {
178
+ let candidates = availableVersions;
179
+ if (range.exact) candidates = candidates.filter((v)=>v === range.exact);
180
+ else {
181
+ if (range.min) candidates = candidates.filter((v)=>compareVersions(v, range.min) >= 0);
182
+ if (range.max) candidates = candidates.filter((v)=>compareVersions(v, range.max) <= 0);
183
+ }
184
+ if (0 === candidates.length) return null;
185
+ return candidates.sort((a, b)=>compareVersions(b, a))[0];
186
+ }
187
+ function getCompatibleReactVersions(hostVersion) {
188
+ const host = parseVersion(hostVersion);
189
+ const versions = [];
190
+ for(let i = host.major; i >= 15; i--)for(let j = 0; j <= 5; j++){
191
+ const version = `${i}.${j}.0`;
192
+ if (checkVersionCompatibility(version, `^${host.major}.0.0`, 'react').compatible) versions.push(version);
193
+ }
194
+ const uniqueVersions = [];
195
+ const seen = new Set();
196
+ for (const v of versions)if (!seen.has(v)) {
197
+ seen.add(v);
198
+ uniqueVersions.push(v);
199
+ }
200
+ return uniqueVersions;
201
+ }
202
+ async function fetchAvailableVersions(pkg) {
203
+ try {
204
+ const res = await fetch(`https://registry.npmjs.org/${pkg}`);
205
+ if (!res.ok) return [];
206
+ const data = await res.json();
207
+ return Object.keys(data.versions || {});
208
+ } catch {
209
+ return [];
207
210
  }
208
- function findCompatibleVersion(availableVersions, range) {
209
- let candidates = availableVersions;
210
- if (range.exact) candidates = candidates.filter((v)=>v === range.exact);
211
- else {
212
- if (range.min) candidates = candidates.filter((v)=>compareVersions(v, range.min) >= 0);
213
- if (range.max) candidates = candidates.filter((v)=>compareVersions(v, range.max) <= 0);
211
+ }
212
+ function sortVersions(versions, order = 'desc') {
213
+ return [
214
+ ...versions
215
+ ].sort((a, b)=>{
216
+ const cmp = compareVersions(a, b);
217
+ return 'desc' === order ? -cmp : cmp;
218
+ });
219
+ }
220
+ function getLatestVersion(versions) {
221
+ if (0 === versions.length) return null;
222
+ return sortVersions(versions, 'desc')[0];
223
+ }
224
+ function getStableVersions(versions) {
225
+ return versions.filter((v)=>!v.includes('alpha') && !v.includes('beta') && !v.includes('rc'));
226
+ }
227
+ function extractMajorVersion(version) {
228
+ return parseVersion(version).major;
229
+ }
230
+ function isPrerelease(version) {
231
+ const v = parseVersion(version);
232
+ return !!v.prerelease;
233
+ }
234
+ const fallbackPlugin = ()=>({
235
+ name: 'fallback-plugin',
236
+ errorLoadRemote (args) {
237
+ const fallback = 'fallback';
238
+ console.log(args, 'args');
239
+ return fallback;
214
240
  }
215
- if (0 === candidates.length) return null;
216
- return candidates.sort((a, b)=>compareVersions(b, a))[0];
241
+ });
242
+ const DEFAULT_CDN_TEMPLATES = [
243
+ 'https://cdn.jsdelivr.net/npm/{pkg}@{version}/dist/remoteEntry.js',
244
+ 'https://unpkg.com/{pkg}@{version}/dist/remoteEntry.js'
245
+ ];
246
+ const DEFAULT_SHARED_CONFIG = {
247
+ react: {
248
+ shareConfig: {
249
+ singleton: true,
250
+ eager: true,
251
+ requiredVersion: false,
252
+ strictVersion: false
253
+ },
254
+ strategy: 'loaded-first'
255
+ },
256
+ 'react-dom': {
257
+ shareConfig: {
258
+ singleton: true,
259
+ eager: true,
260
+ requiredVersion: false,
261
+ strictVersion: false
262
+ },
263
+ strategy: 'loaded-first'
264
+ },
265
+ 'react-dom/client': {
266
+ shareConfig: {
267
+ singleton: true,
268
+ eager: true,
269
+ requiredVersion: false,
270
+ strictVersion: false
271
+ },
272
+ strategy: 'loaded-first'
273
+ },
274
+ 'react/jsx-runtime': {
275
+ shareConfig: {
276
+ singleton: true,
277
+ eager: true,
278
+ requiredVersion: false,
279
+ strictVersion: false
280
+ },
281
+ strategy: 'loaded-first'
282
+ },
283
+ 'react/jsx-dev-runtime': {
284
+ shareConfig: {
285
+ singleton: true,
286
+ eager: true,
287
+ requiredVersion: false,
288
+ strictVersion: false
289
+ },
290
+ strategy: 'loaded-first'
217
291
  }
218
- function getCompatibleReactVersions(hostVersion) {
219
- const host = parseVersion(hostVersion);
220
- const versions = [];
221
- for(let i = host.major; i >= 15; i--)for(let j = 0; j <= 5; j++){
222
- const version = `${i}.${j}.0`;
223
- if (checkVersionCompatibility(version, `^${host.major}.0.0`, 'react').compatible) versions.push(version);
224
- }
225
- const uniqueVersions = [];
226
- const seen = new Set();
227
- for (const v of versions)if (!seen.has(v)) {
228
- seen.add(v);
229
- uniqueVersions.push(v);
230
- }
231
- return uniqueVersions;
292
+ };
293
+ async function fetchLatestVersion(pkg) {
294
+ const res = await fetch(`https://registry.npmjs.org/${pkg}`);
295
+ if (!res.ok) throw new Error(`[MF] 无法获取 ${pkg} 的版本信息,状态码:${res.status}`);
296
+ const data = await res.json();
297
+ const latest = data['dist-tags']?.latest;
298
+ if (!latest) throw new Error(`[MF] 无法从 NPM 获取 ${pkg} 的 latest tag`);
299
+ return latest;
300
+ }
301
+ function getVersionCache() {
302
+ try {
303
+ const cacheStr = localStorage.getItem('mf-multi-version');
304
+ return cacheStr ? JSON.parse(cacheStr) : {};
305
+ } catch (e) {
306
+ console.error('[MF Cache] 读取缓存失败:', e);
307
+ return {};
232
308
  }
233
- async function fetchAvailableVersions(pkg) {
234
- try {
235
- const res = await fetch(`https://registry.npmjs.org/${pkg}`);
236
- if (!res.ok) return [];
237
- const data = await res.json();
238
- return Object.keys(data.versions || {});
239
- } catch {
240
- return [];
241
- }
309
+ }
310
+ function setVersionCache(pkg, version) {
311
+ try {
312
+ const cache = getVersionCache();
313
+ cache[pkg] = cache[pkg] || {};
314
+ cache[pkg][version] = {
315
+ timestamp: Date.now()
316
+ };
317
+ localStorage.setItem('mf-multi-version', JSON.stringify(cache));
318
+ } catch (e) {
319
+ console.error('[MF Cache] 写入缓存失败:', e);
242
320
  }
243
- function sortVersions(versions, order = 'desc') {
244
- return [
245
- ...versions
246
- ].sort((a, b)=>{
247
- const cmp = compareVersions(a, b);
248
- return 'desc' === order ? -cmp : cmp;
321
+ }
322
+ function buildCdnUrls(pkg, version) {
323
+ return DEFAULT_CDN_TEMPLATES.map((template)=>template.replace('{pkg}', pkg).replace('{version}', version));
324
+ }
325
+ const mfInstanceCache = new Map();
326
+ const mfInstanceLoadingCache = new Map();
327
+ function buildRemotesIdentity(remotes) {
328
+ if (0 === remotes.length) return '';
329
+ return remotes.map((remote)=>JSON.stringify({
330
+ name: remote.name,
331
+ entry: 'entry' in remote ? remote.entry : '',
332
+ version: 'version' in remote ? remote.version : '',
333
+ alias: remote.alias || '',
334
+ type: remote.type || '',
335
+ entryGlobalName: remote.entryGlobalName || ''
336
+ })).sort().join('|');
337
+ }
338
+ async function tryLoadRemote(scopeName, url, _retries, _delay, sharedConfig, plugins, extraRemotes = [], registerOptions = {}) {
339
+ const remotesIdentity = buildRemotesIdentity(extraRemotes);
340
+ const cacheKey = `${scopeName}::${url}::${remotesIdentity}::${registerOptions.force ? 'force' : 'normal'}`;
341
+ const cachedMfs = mfInstanceCache.get(cacheKey);
342
+ if (cachedMfs) return {
343
+ scopeName,
344
+ mf: cachedMfs
345
+ };
346
+ const loadingMfs = mfInstanceLoadingCache.get(cacheKey);
347
+ if (loadingMfs) return loadingMfs;
348
+ const loadPromise = Promise.resolve().then(()=>{
349
+ const mf = (0, runtime_namespaceObject.createInstance)({
350
+ name: 'host',
351
+ remotes: [
352
+ {
353
+ name: scopeName,
354
+ entry: url
355
+ }
356
+ ],
357
+ shared: sharedConfig,
358
+ plugins: [
359
+ ...plugins,
360
+ fallbackPlugin()
361
+ ]
249
362
  });
363
+ if (extraRemotes.length > 0) mf.registerRemotes(extraRemotes, registerOptions);
364
+ const result = {
365
+ scopeName,
366
+ mf
367
+ };
368
+ mfInstanceCache.set(cacheKey, mf);
369
+ return result;
370
+ });
371
+ mfInstanceLoadingCache.set(cacheKey, loadPromise);
372
+ try {
373
+ return await loadPromise;
374
+ } finally{
375
+ mfInstanceLoadingCache.delete(cacheKey);
250
376
  }
251
- function getLatestVersion(versions) {
252
- if (0 === versions.length) return null;
253
- return sortVersions(versions, 'desc')[0];
254
- }
255
- function getStableVersions(versions) {
256
- return versions.filter((v)=>!v.includes('alpha') && !v.includes('beta') && !v.includes('rc'));
257
- }
258
- function extractMajorVersion(version) {
259
- return parseVersion(version).major;
260
- }
261
- function isPrerelease(version) {
262
- const v = parseVersion(version);
263
- return !!v.prerelease;
264
- }
265
- const fallbackPlugin = ()=>({
266
- name: 'fallback-plugin',
267
- errorLoadRemote (args) {
268
- const fallback = 'fallback';
269
- console.log(args, 'args');
270
- return fallback;
271
- }
377
+ }
378
+ function getFinalSharedConfig(customShared) {
379
+ const globalReact = window.React;
380
+ const globalReactDOM = window.ReactDOM;
381
+ const globalShared = {};
382
+ if (globalReact && globalReactDOM) {
383
+ const isValidReact = 'object' == typeof globalReact && 'function' == typeof globalReact.useCallback;
384
+ if (isValidReact) {
385
+ globalShared.react = {
386
+ version: globalReact.version || '18.0.0',
387
+ lib: ()=>globalReact,
388
+ shareConfig: {
389
+ singleton: true,
390
+ eager: true,
391
+ requiredVersion: false,
392
+ strictVersion: false
393
+ },
394
+ strategy: 'loaded-first'
395
+ };
396
+ globalShared['react-dom'] = {
397
+ version: globalReactDOM.version || '18.0.0',
398
+ lib: ()=>globalReactDOM,
399
+ shareConfig: {
400
+ singleton: true,
401
+ eager: true,
402
+ requiredVersion: false,
403
+ strictVersion: false
404
+ },
405
+ strategy: 'loaded-first'
406
+ };
407
+ globalShared['react-dom/client'] = {
408
+ version: globalReactDOM.version || '18.0.0',
409
+ lib: ()=>globalReactDOM,
410
+ shareConfig: {
411
+ singleton: true,
412
+ eager: true,
413
+ requiredVersion: false,
414
+ strictVersion: false
415
+ },
416
+ strategy: 'loaded-first'
417
+ };
418
+ console.log('[getFinalSharedConfig] Using global React instance', {
419
+ version: globalReact.version
420
+ });
421
+ } else console.warn('[getFinalSharedConfig] Global React found but is invalid', {
422
+ type: typeof globalReact,
423
+ useCallback: typeof globalReact?.useCallback
272
424
  });
273
- const DEFAULT_CDN_TEMPLATES = [
274
- 'https://cdn.jsdelivr.net/npm/{pkg}@{version}/dist/remoteEntry.js',
275
- 'https://unpkg.com/{pkg}@{version}/dist/remoteEntry.js'
425
+ } else console.log('[getFinalSharedConfig] No global React found, using default shared config');
426
+ const mergedShared = {
427
+ ...DEFAULT_SHARED_CONFIG,
428
+ ...globalShared,
429
+ ...customShared || {}
430
+ };
431
+ const keepSingletonPackages = [
432
+ 'react',
433
+ 'react-dom',
434
+ 'react-dom/client',
435
+ 'react/jsx-runtime',
436
+ 'react/jsx-dev-runtime'
276
437
  ];
277
- const DEFAULT_SHARED_CONFIG = {
278
- react: {
438
+ for (const pkgName of keepSingletonPackages){
439
+ const base = mergedShared[pkgName] || {};
440
+ mergedShared[pkgName] = {
441
+ ...base,
442
+ strategy: 'loaded-first',
279
443
  shareConfig: {
280
444
  singleton: true,
281
445
  eager: true,
282
- requiredVersion: false
446
+ requiredVersion: false,
447
+ strictVersion: false,
448
+ ...base.shareConfig || {}
283
449
  }
284
- },
285
- 'react-dom': {
286
- shareConfig: {
287
- singleton: true,
288
- eager: true,
289
- requiredVersion: false
290
- }
291
- }
292
- };
293
- async function fetchLatestVersion(pkg) {
294
- const res = await fetch(`https://registry.npmjs.org/${pkg}`);
295
- if (!res.ok) throw new Error(`[MF] 无法获取 ${pkg} 的版本信息,状态码:${res.status}`);
296
- const data = await res.json();
297
- const latest = data['dist-tags']?.latest;
298
- if (!latest) throw new Error(`[MF] 无法从 NPM 获取 ${pkg} 的 latest tag`);
299
- return latest;
450
+ };
300
451
  }
301
- function getVersionCache() {
302
- try {
303
- const cacheStr = localStorage.getItem('mf-multi-version');
304
- return cacheStr ? JSON.parse(cacheStr) : {};
305
- } catch (e) {
306
- console.error('[MF Cache] 读取缓存失败:', e);
307
- return {};
452
+ if ('function' == typeof globalShared.react?.lib) mergedShared.react = {
453
+ ...mergedShared.react || {},
454
+ lib: globalShared.react.lib,
455
+ version: globalShared.react.version
456
+ };
457
+ if ('function' == typeof globalShared['react-dom']?.lib) mergedShared['react-dom'] = {
458
+ ...mergedShared['react-dom'] || {},
459
+ lib: globalShared['react-dom'].lib,
460
+ version: globalShared['react-dom'].version
461
+ };
462
+ if ('function' == typeof globalShared['react-dom/client']?.lib) mergedShared['react-dom/client'] = {
463
+ ...mergedShared['react-dom/client'] || {},
464
+ lib: globalShared['react-dom/client'].lib,
465
+ version: globalShared['react-dom/client'].version
466
+ };
467
+ return mergedShared;
468
+ }
469
+ async function resolveFinalVersion(pkg, version, cacheTTL, revalidate) {
470
+ let finalVersion = version;
471
+ if ('latest' === version) {
472
+ const cache = getVersionCache();
473
+ const versions = cache[pkg] || {};
474
+ const latestCached = Object.keys(versions).sort((a, b)=>versions[b].timestamp - versions[a].timestamp)[0];
475
+ if (latestCached && Date.now() - versions[latestCached].timestamp < cacheTTL) {
476
+ finalVersion = latestCached;
477
+ if (revalidate) fetchLatestVersion(pkg).then((latest)=>{
478
+ if (latest !== latestCached) {
479
+ console.log(`[MF] 发现 ${pkg} 新版本 ${latest},已更新缓存。`);
480
+ setVersionCache(pkg, latest);
481
+ }
482
+ }).catch((e)=>console.error(`[MF] 异步检查最新版本失败:`, e));
483
+ } else {
484
+ finalVersion = await fetchLatestVersion(pkg);
485
+ setVersionCache(pkg, finalVersion);
308
486
  }
309
487
  }
310
- function setVersionCache(pkg, version) {
311
- try {
312
- const cache = getVersionCache();
313
- cache[pkg] = cache[pkg] || {};
314
- cache[pkg][version] = {
315
- timestamp: Date.now()
316
- };
317
- localStorage.setItem('mf-multi-version', JSON.stringify(cache));
318
- } catch (e) {
319
- console.error('[MF Cache] 写入缓存失败:', e);
320
- }
488
+ return finalVersion;
489
+ }
490
+ function buildFinalUrls(pkg, version, localFallback) {
491
+ const urls = buildCdnUrls(pkg, version);
492
+ if (localFallback) urls.push(localFallback);
493
+ return urls;
494
+ }
495
+ function dedupeRemotes(remotes) {
496
+ const map = new Map();
497
+ for (const remote of remotes){
498
+ if (!remote?.name) continue;
499
+ const key = [
500
+ remote.name,
501
+ 'entry' in remote ? remote.entry || '' : '',
502
+ 'version' in remote ? remote.version || '' : '',
503
+ remote.alias || ''
504
+ ].join('::');
505
+ if (!map.has(key)) map.set(key, remote);
506
+ }
507
+ return Array.from(map.values());
508
+ }
509
+ async function resolveRegisteredRemotes(context, baseRemotes, remoteSourcePlugins) {
510
+ const remoteList = [
511
+ ...baseRemotes
512
+ ];
513
+ for (const plugin of remoteSourcePlugins)if (plugin.registerRemotes) try {
514
+ const pluginRemotes = await plugin.registerRemotes(context);
515
+ if (pluginRemotes?.length) remoteList.push(...pluginRemotes);
516
+ } catch (error) {
517
+ throw new Error(`[MF] remote 来源插件 ${plugin.name} 执行失败: ${error.message}`);
321
518
  }
322
- function buildCdnUrls(pkg, version) {
323
- return DEFAULT_CDN_TEMPLATES.map((template)=>template.replace('{pkg}', pkg).replace('{version}', version));
519
+ return dedupeRemotes(remoteList).filter((remote)=>!(remote.name === context.scopeName && 'entry' in remote && remote.entry === context.currentEntry));
520
+ }
521
+ function createRemoteSourcePlugin(name, remotes) {
522
+ return {
523
+ name,
524
+ registerRemotes: ()=>remotes
525
+ };
526
+ }
527
+ async function loadRemoteMultiVersion(options, plugins = [], extraOptions = {}) {
528
+ const { name, pkg, version = 'latest', retries = 3, delay = 1000, localFallback, cacheTTL = 86400000, revalidate = true, shared: customShared } = options;
529
+ const { remoteSourcePlugins = [], baseRemotes = [], registerOptions = {} } = extraOptions;
530
+ const finalVersion = await resolveFinalVersion(pkg, version, cacheTTL, revalidate);
531
+ const scopeName = `${name}`;
532
+ const urls = buildFinalUrls(pkg, finalVersion, localFallback);
533
+ const finalSharedConfig = getFinalSharedConfig(customShared);
534
+ for (const url of urls)try {
535
+ const registeredRemotes = await resolveRegisteredRemotes({
536
+ options,
537
+ scopeName,
538
+ pkg,
539
+ finalVersion,
540
+ currentEntry: url,
541
+ allEntries: urls
542
+ }, baseRemotes, remoteSourcePlugins);
543
+ return await tryLoadRemote(scopeName, url, retries, delay, finalSharedConfig, plugins, registeredRemotes, registerOptions);
544
+ } catch (e) {
545
+ console.warn(`[MF] 切换 CDN 路径:${url} 失败,尝试下一个...`, e);
546
+ }
547
+ throw new Error(`[MF] 所有加载源 (${urls.length} 个) 均加载失败。`);
548
+ }
549
+ const preloadCache = {};
550
+ const PRELOAD_CACHE_TTL = 300000;
551
+ function getCachedPreload(pkg, version) {
552
+ const cached = preloadCache[pkg];
553
+ if (!cached) return null;
554
+ if (cached.version !== version) return null;
555
+ if (Date.now() - cached.timestamp > PRELOAD_CACHE_TTL) {
556
+ delete preloadCache[pkg];
557
+ return null;
558
+ }
559
+ return {
560
+ scopeName: cached.scopeName,
561
+ mf: cached.mf
562
+ };
563
+ }
564
+ function setCachedPreload(pkg, version, scopeName, mf) {
565
+ preloadCache[pkg] = {
566
+ version,
567
+ scopeName,
568
+ mf,
569
+ timestamp: Date.now()
570
+ };
571
+ }
572
+ function executeWhenIdle(callback) {
573
+ if ('undefined' != typeof requestIdleCallback) requestIdleCallback(()=>callback());
574
+ else setTimeout(callback, 1);
575
+ }
576
+ async function preloadRemote(options) {
577
+ const { pkg, version = 'latest', priority = 'idle', force = false } = options;
578
+ if (!force) {
579
+ const cached = getCachedPreload(pkg, version);
580
+ if (cached) return cached;
324
581
  }
325
- async function tryLoadRemote(scopeName, url, retries, delay, sharedConfig, plugins) {
326
- let lastError;
327
- for(let i = 0; i < retries; i++)try {
328
- const mf = (0, runtime_namespaceObject.createInstance)({
329
- name: 'host',
330
- remotes: [
331
- {
332
- name: scopeName,
333
- entry: url
334
- }
335
- ],
336
- shared: sharedConfig,
337
- plugins: [
338
- ...plugins,
339
- fallbackPlugin()
340
- ]
341
- });
582
+ const preloadTask = async ()=>{
583
+ try {
584
+ const { scopeName, mf } = await loadRemoteMultiVersion(options, []);
585
+ setCachedPreload(pkg, version, scopeName, mf);
342
586
  return {
343
587
  scopeName,
344
588
  mf
345
589
  };
346
590
  } catch (e) {
347
- lastError = e;
348
- console.warn(`[MF] URL ${url} 加载失败,第 ${i + 1} 次重试...`);
349
- if (i < retries - 1) await new Promise((res)=>setTimeout(res, delay));
350
- }
351
- throw new Error(`[MF] URL ${url} 经过 ${retries} 次重试仍加载失败。`, {
352
- cause: lastError
353
- });
354
- }
355
- function getFinalSharedConfig(customShared) {
356
- return {
357
- ...DEFAULT_SHARED_CONFIG,
358
- ...customShared || {}
359
- };
360
- }
361
- async function resolveFinalVersion(pkg, version, cacheTTL, revalidate) {
362
- let finalVersion = version;
363
- if ('latest' === version) {
364
- const cache = getVersionCache();
365
- const versions = cache[pkg] || {};
366
- const latestCached = Object.keys(versions).sort((a, b)=>versions[b].timestamp - versions[a].timestamp)[0];
367
- if (latestCached && Date.now() - versions[latestCached].timestamp < cacheTTL) {
368
- finalVersion = latestCached;
369
- if (revalidate) fetchLatestVersion(pkg).then((latest)=>{
370
- if (latest !== latestCached) {
371
- console.log(`[MF] 发现 ${pkg} 新版本 ${latest},已更新缓存。`);
372
- setVersionCache(pkg, latest);
373
- }
374
- }).catch((e)=>console.error(`[MF] 异步检查最新版本失败:`, e));
375
- } else {
376
- finalVersion = await fetchLatestVersion(pkg);
377
- setVersionCache(pkg, finalVersion);
378
- }
379
- }
380
- return finalVersion;
381
- }
382
- function buildFinalUrls(pkg, version, localFallback) {
383
- const urls = buildCdnUrls(pkg, version);
384
- if (localFallback) urls.push(localFallback);
385
- return urls;
386
- }
387
- async function loadRemoteMultiVersion(options, plugins) {
388
- const { name, pkg, version = 'latest', retries = 3, delay = 1000, localFallback, cacheTTL = 86400000, revalidate = true, shared: customShared } = options;
389
- const finalVersion = await resolveFinalVersion(pkg, version, cacheTTL, revalidate);
390
- const scopeName = `${name}`;
391
- const urls = buildFinalUrls(pkg, finalVersion, localFallback);
392
- const finalSharedConfig = getFinalSharedConfig(customShared);
393
- for (const url of urls)try {
394
- return await tryLoadRemote(scopeName, url, retries, delay, finalSharedConfig, plugins);
395
- } catch (e) {
396
- console.warn(`[MF] 切换 CDN 路径:${url} 失败,尝试下一个...`, e);
397
- }
398
- throw new Error(`[MF] 所有加载源 (${urls.length} 个) 均加载失败。`);
399
- }
400
- const preloadCache = {};
401
- const PRELOAD_CACHE_TTL = 300000;
402
- function getCachedPreload(pkg, version) {
403
- const cached = preloadCache[pkg];
404
- if (!cached) return null;
405
- if (cached.version !== version) return null;
406
- if (Date.now() - cached.timestamp > PRELOAD_CACHE_TTL) {
407
- delete preloadCache[pkg];
591
+ console.warn(`[MF Preload] 预加载失败 ${pkg}@${version}:`, e);
408
592
  return null;
409
593
  }
410
- return {
411
- scopeName: cached.scopeName,
412
- mf: cached.mf
413
- };
414
- }
415
- function setCachedPreload(pkg, version, scopeName, mf) {
416
- preloadCache[pkg] = {
417
- version,
418
- scopeName,
419
- mf,
420
- timestamp: Date.now()
421
- };
422
- }
423
- function executeWhenIdle(callback) {
424
- if ('undefined' != typeof requestIdleCallback) requestIdleCallback(()=>callback());
425
- else setTimeout(callback, 1);
426
- }
427
- async function preloadRemote(options) {
428
- const { pkg, version = 'latest', priority = 'idle', force = false } = options;
429
- if (!force) {
430
- const cached = getCachedPreload(pkg, version);
431
- if (cached) return cached;
432
- }
433
- const preloadTask = async ()=>{
434
- try {
435
- const { scopeName, mf } = await loadRemoteMultiVersion(options, []);
436
- setCachedPreload(pkg, version, scopeName, mf);
437
- return {
438
- scopeName,
439
- mf
440
- };
441
- } catch (e) {
442
- console.warn(`[MF Preload] 预加载失败 ${pkg}@${version}:`, e);
443
- return null;
444
- }
445
- };
446
- if ('high' === priority) return preloadTask();
447
- return new Promise((resolve)=>{
448
- executeWhenIdle(async ()=>{
449
- const result = await preloadTask();
450
- resolve(result);
451
- });
594
+ };
595
+ if ('high' === priority) return preloadTask();
596
+ return new Promise((resolve)=>{
597
+ executeWhenIdle(async ()=>{
598
+ const result = await preloadTask();
599
+ resolve(result);
452
600
  });
601
+ });
602
+ }
603
+ function preloadRemoteList(optionsList, onProgress) {
604
+ let loaded = 0;
605
+ const total = optionsList.length;
606
+ const promises = optionsList.map((options)=>preloadRemote(options).then((result)=>{
607
+ loaded++;
608
+ onProgress?.(loaded, total);
609
+ return result;
610
+ }));
611
+ return Promise.all(promises);
612
+ }
613
+ function cancelPreload(pkg) {
614
+ const cached = preloadCache[pkg];
615
+ if (cached) delete preloadCache[pkg];
616
+ }
617
+ function clearPreloadCache() {
618
+ Object.keys(preloadCache).forEach((pkg)=>delete preloadCache[pkg]);
619
+ }
620
+ function getPreloadStatus(pkg) {
621
+ const cached = preloadCache[pkg];
622
+ if (!cached) return null;
623
+ return {
624
+ loaded: true,
625
+ timestamp: cached.timestamp
626
+ };
627
+ }
628
+ const remoteInstances = new Map();
629
+ function generateInstanceKey(name, pkg, version) {
630
+ return `${name}::${pkg}@${version}`;
631
+ }
632
+ async function unloadRemote(options) {
633
+ const { name, pkg, version = '*', clearCache = false } = options;
634
+ const keysToDelete = [];
635
+ remoteInstances.forEach((instance, key)=>{
636
+ const versionMatch = '*' === version || instance.version === version;
637
+ const pkgMatch = instance.pkg === pkg;
638
+ const nameMatch = instance.name === name;
639
+ if (nameMatch && pkgMatch && versionMatch) keysToDelete.push(key);
640
+ });
641
+ for (const key of keysToDelete){
642
+ const instance = remoteInstances.get(key);
643
+ if (instance) {
644
+ await cleanupInstance(instance);
645
+ remoteInstances.delete(key);
646
+ }
453
647
  }
454
- function preloadRemoteList(optionsList, onProgress) {
455
- let loaded = 0;
456
- const total = optionsList.length;
457
- const promises = optionsList.map((options)=>preloadRemote(options).then((result)=>{
458
- loaded++;
459
- onProgress?.(loaded, total);
460
- return result;
461
- }));
462
- return Promise.all(promises);
463
- }
464
- function cancelPreload(pkg) {
465
- const cached = preloadCache[pkg];
466
- if (cached) delete preloadCache[pkg];
467
- }
468
- function clearPreloadCache() {
469
- Object.keys(preloadCache).forEach((pkg)=>delete preloadCache[pkg]);
470
- }
471
- function getPreloadStatus(pkg) {
472
- const cached = preloadCache[pkg];
473
- if (!cached) return null;
474
- return {
475
- loaded: true,
476
- timestamp: cached.timestamp
477
- };
648
+ if (clearCache) clearVersionCache(pkg, version);
649
+ return keysToDelete.length > 0;
650
+ }
651
+ async function cleanupInstance(instance) {
652
+ try {
653
+ instance.loadedModules.clear();
654
+ if (instance.mf && 'function' == typeof instance.mf.cleanup) await instance.mf.cleanup();
655
+ console.log(`[MF Unload] 已卸载 ${instance.pkg}@${instance.version}`);
656
+ } catch (e) {
657
+ console.warn(`[MF Unload] 卸载时出错 ${instance.pkg}:`, e);
478
658
  }
479
- const remoteInstances = new Map();
480
- function generateInstanceKey(name, pkg, version) {
481
- return `${name}::${pkg}@${version}`;
659
+ }
660
+ function clearVersionCache(pkg, version) {
661
+ try {
662
+ const cacheKey = 'mf-multi-version';
663
+ const cacheStr = localStorage.getItem(cacheKey);
664
+ if (!cacheStr) return;
665
+ const cache = JSON.parse(cacheStr);
666
+ if (!cache[pkg]) return;
667
+ if ('*' === version) delete cache[pkg];
668
+ else delete cache[pkg][version];
669
+ localStorage.setItem(cacheKey, JSON.stringify(cache));
670
+ console.log(`[MF Unload] 已清除版本缓存 ${pkg}@${version}`);
671
+ } catch (e) {
672
+ console.warn('[MF Unload] 清除缓存失败:', e);
482
673
  }
483
- async function unloadRemote(options) {
484
- const { name, pkg, version = '*', clearCache = false } = options;
485
- const keysToDelete = [];
486
- remoteInstances.forEach((instance, key)=>{
487
- const versionMatch = '*' === version || instance.version === version;
488
- const pkgMatch = instance.pkg === pkg;
489
- const nameMatch = instance.name === name;
490
- if (nameMatch && pkgMatch && versionMatch) keysToDelete.push(key);
491
- });
492
- for (const key of keysToDelete){
674
+ }
675
+ function registerRemoteInstance(name, scopeName, pkg, version, mf) {
676
+ const key = generateInstanceKey(name, pkg, version);
677
+ const instance = {
678
+ name,
679
+ scopeName,
680
+ pkg,
681
+ version,
682
+ mf,
683
+ loadedModules: new Set(),
684
+ timestamp: Date.now()
685
+ };
686
+ remoteInstances.set(key, instance);
687
+ return key;
688
+ }
689
+ function registerLoadedModule(key, moduleId) {
690
+ const instance = remoteInstances.get(key);
691
+ if (instance) instance.loadedModules.add(moduleId);
692
+ }
693
+ function unloadAll(clearAllCache = false) {
694
+ return new Promise((resolve)=>{
695
+ const keys = Array.from(remoteInstances.keys());
696
+ if (0 === keys.length) return void resolve();
697
+ let completed = 0;
698
+ keys.forEach(async (key)=>{
493
699
  const instance = remoteInstances.get(key);
494
700
  if (instance) {
495
701
  await cleanupInstance(instance);
496
702
  remoteInstances.delete(key);
497
703
  }
498
- }
499
- if (clearCache) clearVersionCache(pkg, version);
500
- return keysToDelete.length > 0;
501
- }
502
- async function cleanupInstance(instance) {
503
- try {
504
- instance.loadedModules.clear();
505
- if (instance.mf && 'function' == typeof instance.mf.cleanup) await instance.mf.cleanup();
506
- console.log(`[MF Unload] 已卸载 ${instance.pkg}@${instance.version}`);
507
- } catch (e) {
508
- console.warn(`[MF Unload] 卸载时出错 ${instance.pkg}:`, e);
509
- }
510
- }
511
- function clearVersionCache(pkg, version) {
512
- try {
513
- const cacheKey = 'mf-multi-version';
514
- const cacheStr = localStorage.getItem(cacheKey);
515
- if (!cacheStr) return;
516
- const cache = JSON.parse(cacheStr);
517
- if (!cache[pkg]) return;
518
- if ('*' === version) delete cache[pkg];
519
- else delete cache[pkg][version];
520
- localStorage.setItem(cacheKey, JSON.stringify(cache));
521
- console.log(`[MF Unload] 已清除版本缓存 ${pkg}@${version}`);
522
- } catch (e) {
523
- console.warn('[MF Unload] 清除缓存失败:', e);
524
- }
525
- }
526
- function registerRemoteInstance(name, scopeName, pkg, version, mf) {
527
- const key = generateInstanceKey(name, pkg, version);
528
- const instance = {
529
- name,
530
- scopeName,
531
- pkg,
532
- version,
533
- mf,
534
- loadedModules: new Set(),
535
- timestamp: Date.now()
536
- };
537
- remoteInstances.set(key, instance);
538
- return key;
539
- }
540
- function registerLoadedModule(key, moduleId) {
541
- const instance = remoteInstances.get(key);
542
- if (instance) instance.loadedModules.add(moduleId);
543
- }
544
- function unloadAll(clearAllCache = false) {
545
- return new Promise((resolve)=>{
546
- const keys = Array.from(remoteInstances.keys());
547
- if (0 === keys.length) return void resolve();
548
- let completed = 0;
549
- keys.forEach(async (key)=>{
550
- const instance = remoteInstances.get(key);
551
- if (instance) {
552
- await cleanupInstance(instance);
553
- remoteInstances.delete(key);
554
- }
555
- completed++;
556
- if (completed >= keys.length) {
557
- if (clearAllCache) try {
558
- localStorage.removeItem('mf-multi-version');
559
- } catch (e) {
560
- console.warn('[MF Unload] 清除所有缓存失败:', e);
561
- }
562
- resolve();
704
+ completed++;
705
+ if (completed >= keys.length) {
706
+ if (clearAllCache) try {
707
+ localStorage.removeItem('mf-multi-version');
708
+ } catch (e) {
709
+ console.warn('[MF Unload] 清除所有缓存失败:', e);
563
710
  }
564
- });
711
+ resolve();
712
+ }
565
713
  });
566
- }
567
- function getLoadedRemotes() {
568
- const result = [];
569
- remoteInstances.forEach((instance)=>{
570
- result.push({
571
- name: instance.name,
572
- pkg: instance.pkg,
573
- version: instance.version,
574
- loadedModules: instance.loadedModules.size,
575
- timestamp: instance.timestamp
576
- });
714
+ });
715
+ }
716
+ function getLoadedRemotes() {
717
+ const result = [];
718
+ remoteInstances.forEach((instance)=>{
719
+ result.push({
720
+ name: instance.name,
721
+ pkg: instance.pkg,
722
+ version: instance.version,
723
+ loadedModules: instance.loadedModules.size,
724
+ timestamp: instance.timestamp
577
725
  });
578
- return result;
726
+ });
727
+ return result;
728
+ }
729
+ function isRemoteLoaded(name, pkg, version) {
730
+ const key = generateInstanceKey(name, pkg, version || '*');
731
+ return remoteInstances.has(key);
732
+ }
733
+ const CDN_URLS = [
734
+ 'https://cdn.jsdelivr.net/npm/{pkg}@{version}/dist/remoteEntry.js',
735
+ 'https://unpkg.com/{pkg}@{version}/dist/remoteEntry.js'
736
+ ];
737
+ async function checkCdnAccess(cdnUrl) {
738
+ const start = performance.now();
739
+ try {
740
+ const controller = new AbortController();
741
+ const timeout = setTimeout(()=>controller.abort(), 5000);
742
+ const res = await fetch(cdnUrl, {
743
+ method: 'HEAD',
744
+ signal: controller.signal
745
+ });
746
+ clearTimeout(timeout);
747
+ const latency = Math.round(performance.now() - start);
748
+ return {
749
+ reachable: res.ok,
750
+ latency
751
+ };
752
+ } catch (e) {
753
+ const latency = Math.round(performance.now() - start);
754
+ return {
755
+ reachable: false,
756
+ latency
757
+ };
579
758
  }
580
- function isRemoteLoaded(name, pkg, version) {
581
- const key = generateInstanceKey(name, pkg, version || '*');
582
- return remoteInstances.has(key);
759
+ }
760
+ async function health_fetchLatestVersion(pkg) {
761
+ try {
762
+ const res = await fetch(`https://registry.npmjs.org/${pkg}`);
763
+ if (!res.ok) return null;
764
+ const data = await res.json();
765
+ return data['dist-tags']?.latest || null;
766
+ } catch {
767
+ return null;
583
768
  }
584
- const CDN_URLS = [
585
- 'https://cdn.jsdelivr.net/npm/{pkg}@{version}/dist/remoteEntry.js',
586
- 'https://unpkg.com/{pkg}@{version}/dist/remoteEntry.js'
587
- ];
588
- async function checkCdnAccess(cdnUrl) {
589
- const start = performance.now();
590
- try {
591
- const controller = new AbortController();
592
- const timeout = setTimeout(()=>controller.abort(), 5000);
593
- const res = await fetch(cdnUrl, {
594
- method: 'HEAD',
595
- signal: controller.signal
596
- });
597
- clearTimeout(timeout);
598
- const latency = Math.round(performance.now() - start);
599
- return {
600
- reachable: res.ok,
601
- latency
602
- };
603
- } catch (e) {
604
- const latency = Math.round(performance.now() - start);
605
- return {
606
- reachable: false,
607
- latency
608
- };
609
- }
769
+ }
770
+ async function checkRemoteHealth(options) {
771
+ const { pkg, version = 'latest' } = options;
772
+ const actualVersion = 'latest' === version ? await health_fetchLatestVersion(pkg) || version : version;
773
+ const results = [];
774
+ for (const template of CDN_URLS){
775
+ const url = template.replace('{pkg}', pkg).replace('{version}', actualVersion);
776
+ const result = await checkCdnAccess(url);
777
+ results.push({
778
+ cdn: url,
779
+ ...result
780
+ });
610
781
  }
611
- async function health_fetchLatestVersion(pkg) {
612
- try {
613
- const res = await fetch(`https://registry.npmjs.org/${pkg}`);
614
- if (!res.ok) return null;
615
- const data = await res.json();
616
- return data['dist-tags']?.latest || null;
617
- } catch {
618
- return null;
782
+ const workingCdn = results.find((r)=>r.reachable);
783
+ const bestCdn = results.sort((a, b)=>a.latency - b.latency)[0];
784
+ let status = 'unhealthy';
785
+ if (workingCdn) status = bestCdn.latency < 1000 ? 'healthy' : 'degraded';
786
+ return {
787
+ pkg,
788
+ version: actualVersion,
789
+ status,
790
+ latency: bestCdn?.latency || 0,
791
+ cdn: bestCdn?.cdn || '',
792
+ details: {
793
+ cdnReachable: !!workingCdn,
794
+ remoteEntryValid: false,
795
+ modulesLoadable: false
619
796
  }
797
+ };
798
+ }
799
+ async function checkModuleLoadable(scopeName, modulePath, mf) {
800
+ try {
801
+ if (!mf || 'function' != typeof mf.loadRemote) return false;
802
+ const mod = await mf.loadRemote(`${scopeName}/${modulePath}`);
803
+ return null != mod;
804
+ } catch {
805
+ return false;
620
806
  }
621
- async function checkRemoteHealth(options) {
622
- const { pkg, version = 'latest' } = options;
623
- const actualVersion = 'latest' === version ? await health_fetchLatestVersion(pkg) || version : version;
624
- const results = [];
625
- for (const template of CDN_URLS){
626
- const url = template.replace('{pkg}', pkg).replace('{version}', actualVersion);
627
- const result = await checkCdnAccess(url);
628
- results.push({
629
- cdn: url,
630
- ...result
631
- });
632
- }
633
- const workingCdn = results.find((r)=>r.reachable);
634
- const bestCdn = results.sort((a, b)=>a.latency - b.latency)[0];
635
- let status = 'unhealthy';
636
- if (workingCdn) status = bestCdn.latency < 1000 ? 'healthy' : 'degraded';
637
- return {
638
- pkg,
639
- version: actualVersion,
640
- status,
641
- latency: bestCdn?.latency || 0,
642
- cdn: bestCdn?.cdn || '',
643
- details: {
644
- cdnReachable: !!workingCdn,
645
- remoteEntryValid: false,
646
- modulesLoadable: false
647
- }
807
+ }
808
+ async function getRemoteHealthReport(remotes) {
809
+ const results = await Promise.all(remotes.map((r)=>checkRemoteHealth(r)));
810
+ let overall = 'healthy';
811
+ if (results.some((r)=>'unhealthy' === r.status)) overall = 'unhealthy';
812
+ else if (results.some((r)=>'degraded' === r.status)) overall = 'degraded';
813
+ return {
814
+ timestamp: Date.now(),
815
+ overall,
816
+ remotes: results
817
+ };
818
+ }
819
+ function formatHealthStatus(status) {
820
+ const icons = {
821
+ healthy: '🟢',
822
+ degraded: '🟡',
823
+ unhealthy: '🔴'
824
+ };
825
+ return `${icons[status]} ${status}`;
826
+ }
827
+ class EventBusClass {
828
+ listeners = new Map();
829
+ eventHistory = new Map();
830
+ maxHistorySize = 100;
831
+ generateId() {
832
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
833
+ }
834
+ on(event, callback, options) {
835
+ const onceValue = options?.once ?? false;
836
+ if (!this.listeners.has(event)) this.listeners.set(event, new Set());
837
+ const subscription = {
838
+ callback,
839
+ once: onceValue,
840
+ filter: options?.filter
648
841
  };
649
- }
650
- async function checkModuleLoadable(scopeName, modulePath, mf) {
651
- try {
652
- if (!mf || 'function' != typeof mf.loadRemote) return false;
653
- const mod = await mf.loadRemote(`${scopeName}/${modulePath}`);
654
- return null != mod;
655
- } catch {
656
- return false;
657
- }
658
- }
659
- async function getRemoteHealthReport(remotes) {
660
- const results = await Promise.all(remotes.map((r)=>checkRemoteHealth(r)));
661
- let overall = 'healthy';
662
- if (results.some((r)=>'unhealthy' === r.status)) overall = 'unhealthy';
663
- else if (results.some((r)=>'degraded' === r.status)) overall = 'degraded';
664
- return {
665
- timestamp: Date.now(),
666
- overall,
667
- remotes: results
842
+ this.listeners.get(event).add(subscription);
843
+ return ()=>{
844
+ this.off(event, callback);
668
845
  };
669
846
  }
670
- function formatHealthStatus(status) {
671
- const icons = {
672
- healthy: '🟢',
673
- degraded: '🟡',
674
- unhealthy: '🔴'
675
- };
676
- return `${icons[status]} ${status}`;
847
+ once(event, callback) {
848
+ return this.on(event, callback, {
849
+ once: true
850
+ });
677
851
  }
678
- class EventBusClass {
679
- listeners = new Map();
680
- eventHistory = new Map();
681
- maxHistorySize = 100;
682
- generateId() {
683
- return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
684
- }
685
- on(event, callback, options) {
686
- const onceValue = options?.once ?? false;
687
- if (!this.listeners.has(event)) this.listeners.set(event, new Set());
688
- const subscription = {
689
- callback,
690
- once: onceValue,
691
- filter: options?.filter
692
- };
693
- this.listeners.get(event).add(subscription);
694
- return ()=>{
695
- this.off(event, callback);
696
- };
697
- }
698
- once(event, callback) {
699
- return this.on(event, callback, {
700
- once: true
701
- });
702
- }
703
- off(event, callback) {
704
- if (!this.listeners.has(event)) return;
705
- if (callback) {
706
- const subscriptions = this.listeners.get(event);
707
- subscriptions.forEach((sub)=>{
708
- if (sub.callback === callback) subscriptions.delete(sub);
709
- });
710
- } else this.listeners.delete(event);
711
- }
712
- emit(event, data, meta) {
713
- const eventMeta = {
714
- timestamp: Date.now(),
715
- source: meta?.source,
716
- id: meta?.id || this.generateId()
717
- };
718
- this.addToHistory(event, data, eventMeta);
852
+ off(event, callback) {
853
+ if (!this.listeners.has(event)) return;
854
+ if (callback) {
719
855
  const subscriptions = this.listeners.get(event);
720
- if (!subscriptions) return;
721
- const toRemove = [];
722
856
  subscriptions.forEach((sub)=>{
723
- if (sub.filter && !sub.filter(data, eventMeta)) return;
724
- try {
725
- sub.callback(data, eventMeta);
726
- } catch (e) {
727
- console.error(`[MF EventBus] 事件 ${event} 处理出错:`, e);
728
- }
729
- if (sub.once) toRemove.push(sub);
857
+ if (sub.callback === callback) subscriptions.delete(sub);
730
858
  });
731
- toRemove.forEach((sub)=>subscriptions.delete(sub));
732
- }
733
- addToHistory(event, data, meta) {
734
- if (!this.eventHistory.has(event)) this.eventHistory.set(event, []);
735
- const history = this.eventHistory.get(event);
736
- history.push({
737
- data,
738
- meta
739
- });
740
- if (history.length > this.maxHistorySize) history.shift();
741
- }
742
- getHistory(event) {
743
- return this.eventHistory.get(event) || [];
744
- }
745
- getEvents() {
746
- return Array.from(this.listeners.keys());
747
- }
748
- getListenerCount(event) {
749
- return this.listeners.get(event)?.size || 0;
750
- }
751
- hasListeners(event) {
752
- return this.listeners.has(event) && this.listeners.get(event).size > 0;
753
- }
754
- clear(event) {
755
- if (event) {
756
- this.listeners.delete(event);
757
- this.eventHistory.delete(event);
758
- } else {
759
- this.listeners.clear();
760
- this.eventHistory.clear();
761
- }
762
- }
763
- listenerExists(event, callback) {
764
- const subscriptions = this.listeners.get(event);
765
- if (!subscriptions) return false;
766
- let exists = false;
767
- subscriptions.forEach((sub)=>{
768
- if (sub.callback === callback) exists = true;
769
- });
770
- return exists;
771
- }
772
- emitAsync(event, data, meta) {
773
- return new Promise((resolve)=>{
774
- this.emit(event, data, meta);
775
- resolve();
776
- });
777
- }
778
- static create() {
779
- return new EventBusClass();
780
- }
781
- }
782
- const eventBus = EventBusClass.create();
783
- function createEventBus() {
784
- return EventBusClass.create();
859
+ } else this.listeners.delete(event);
785
860
  }
786
- const external_react_namespaceObject = require("react");
787
- var external_react_default = /*#__PURE__*/ __webpack_require__.n(external_react_namespaceObject);
788
- class ErrorBoundary extends external_react_default().Component {
789
- constructor(props){
790
- super(props);
791
- this.state = {
792
- hasError: false,
793
- error: null,
794
- errorInfo: null
795
- };
796
- }
797
- static getDerivedStateFromError(error) {
798
- return {
799
- hasError: true,
800
- error,
801
- errorInfo: null
802
- };
803
- }
804
- componentDidCatch(error, errorInfo) {
805
- this.setState({
806
- errorInfo
807
- });
808
- this.props.onError?.(error, errorInfo);
809
- console.error('[RemoteReloadUtils] ErrorBoundary caught error:', error, errorInfo);
810
- }
811
- handleReset = ()=>{
812
- this.setState({
813
- hasError: false,
814
- error: null,
815
- errorInfo: null
816
- });
817
- this.props.onReset?.();
861
+ emit(event, data, meta) {
862
+ const eventMeta = {
863
+ timestamp: Date.now(),
864
+ source: meta?.source,
865
+ id: meta?.id || this.generateId()
818
866
  };
819
- render() {
820
- if (this.state.hasError && this.state.error) {
821
- if ('function' == typeof this.props.fallback) return this.props.fallback(this.state.error, this.handleReset);
822
- if (void 0 !== this.props.fallback) return this.props.fallback;
823
- return /*#__PURE__*/ external_react_default().createElement("div", {
824
- role: "alert",
825
- className: "p-4 border border-red-200 bg-red-50 rounded-lg"
826
- }, /*#__PURE__*/ external_react_default().createElement("h3", {
827
- className: "text-lg font-semibold mb-2"
828
- }, "Something went wrong"), /*#__PURE__*/ external_react_default().createElement("p", {
829
- className: "text-red-700"
830
- }, this.state.error.message), /*#__PURE__*/ external_react_default().createElement("button", {
831
- onClick: this.handleReset,
832
- className: "mt-3 px-4 py-2 text-sm font-medium text-white bg-red-600 rounded hover:bg-red-700 cursor-pointer transition-colors"
833
- }, "Try again"));
867
+ this.addToHistory(event, data, eventMeta);
868
+ const subscriptions = this.listeners.get(event);
869
+ if (!subscriptions) return;
870
+ const toRemove = [];
871
+ subscriptions.forEach((sub)=>{
872
+ if (sub.filter && !sub.filter(data, eventMeta)) return;
873
+ try {
874
+ sub.callback(data, eventMeta);
875
+ } catch (e) {
876
+ console.error(`[MF EventBus] 事件 ${event} 处理出错:`, e);
834
877
  }
835
- return this.props.children;
836
- }
837
- }
838
- function useRemoteModule({ pkg, version, moduleName, scopeName, onError, onLoad, retryKey = 0 }) {
839
- const [moduleState, setModuleState] = (0, external_react_namespaceObject.useState)({
840
- loading: true,
841
- error: null,
842
- component: null
878
+ if (sub.once) toRemove.push(sub);
843
879
  });
844
- (0, external_react_namespaceObject.useEffect)(()=>{
845
- let mounted = true;
846
- async function loadModule() {
847
- try {
848
- setModuleState((prev)=>({
849
- ...prev,
850
- loading: true,
851
- error: null
852
- }));
853
- const { mf } = await loadRemoteMultiVersion({
854
- name: scopeName,
855
- pkg,
856
- version
857
- }, []);
858
- if (!mf || !mounted) return;
859
- const mod = await mf.loadRemote(`${scopeName}/${moduleName}`);
860
- if (!mounted) return;
861
- if (mod && 'object' == typeof mod && 'default' in mod) {
862
- const Component = mod.default;
863
- setModuleState({
864
- loading: false,
865
- error: null,
866
- component: Component
867
- });
868
- onLoad?.(Component);
869
- } else throw new Error(`Module "${scopeName}/${moduleName}" does not export a default component`);
870
- } catch (err) {
871
- if (mounted) {
872
- const error = err instanceof Error ? err : new Error(String(err));
873
- setModuleState({
874
- loading: false,
875
- error,
876
- component: null
877
- });
878
- onError?.(error);
879
- }
880
- }
881
- }
882
- loadModule();
883
- return ()=>{
884
- mounted = false;
885
- };
886
- }, [
887
- pkg,
888
- version,
889
- moduleName,
890
- scopeName,
891
- onError,
892
- onLoad,
893
- retryKey
894
- ]);
895
- return moduleState;
896
- }
897
- function RemoteModuleRenderer({ pkg, version, moduleName, scopeName, loadingFallback, errorFallback, componentProps, className, style, onError, onLoad }) {
898
- const moduleState = useRemoteModule({
899
- pkg,
900
- version,
901
- moduleName,
902
- scopeName,
903
- onError,
904
- onLoad
880
+ toRemove.forEach((sub)=>subscriptions.delete(sub));
881
+ }
882
+ addToHistory(event, data, meta) {
883
+ if (!this.eventHistory.has(event)) this.eventHistory.set(event, []);
884
+ const history = this.eventHistory.get(event);
885
+ history.push({
886
+ data,
887
+ meta
905
888
  });
906
- const [retryKey, setRetryKey] = (0, external_react_namespaceObject.useState)(0);
907
- const handleRetry = (0, external_react_namespaceObject.useCallback)(()=>{
908
- setRetryKey((prev)=>prev + 1);
909
- }, []);
910
- (0, external_react_namespaceObject.useEffect)(()=>{}, [
911
- retryKey
912
- ]);
913
- if (moduleState.loading) return /*#__PURE__*/ external_react_default().createElement("div", {
914
- className: className,
915
- style: style,
916
- role: "status",
917
- "aria-live": "polite"
918
- }, loadingFallback || /*#__PURE__*/ external_react_default().createElement("div", {
919
- className: "module-card module-card--loading"
920
- }, /*#__PURE__*/ external_react_default().createElement("div", {
921
- className: "loading-spinner",
922
- "aria-hidden": "true"
923
- }), /*#__PURE__*/ external_react_default().createElement("span", {
924
- className: "text-gray-600"
925
- }, "Loading ", moduleName, "...")));
926
- if (moduleState.error) {
927
- if ('function' == typeof errorFallback) return /*#__PURE__*/ external_react_default().createElement(external_react_default().Fragment, null, errorFallback(moduleState.error, handleRetry));
928
- if (void 0 !== errorFallback) return /*#__PURE__*/ external_react_default().createElement(external_react_default().Fragment, null, errorFallback);
929
- return /*#__PURE__*/ external_react_default().createElement("div", {
930
- className: className,
931
- style: style,
932
- role: "alert"
933
- }, /*#__PURE__*/ external_react_default().createElement("div", {
934
- className: "module-card module-card--error"
935
- }, /*#__PURE__*/ external_react_default().createElement("span", {
936
- className: "error-icon",
937
- "aria-hidden": "true"
938
- }, "!"), /*#__PURE__*/ external_react_default().createElement("span", null, "Failed to load ", moduleName), /*#__PURE__*/ external_react_default().createElement("p", {
939
- className: "error-message"
940
- }, moduleState.error.message), /*#__PURE__*/ external_react_default().createElement("button", {
941
- onClick: handleRetry,
942
- className: "retry-button",
943
- type: "button"
944
- }, "Retry")));
945
- }
946
- if (!moduleState.component) return null;
947
- const Component = moduleState.component;
948
- return /*#__PURE__*/ external_react_default().createElement("div", {
949
- className: className,
950
- style: style
951
- }, /*#__PURE__*/ external_react_default().createElement(Component, componentProps));
889
+ if (history.length > this.maxHistorySize) history.shift();
952
890
  }
953
- function RemoteModuleProvider(props) {
954
- const { disableErrorBoundary, errorFallback, loadingFallback, errorBoundaryOptions } = props;
955
- if (disableErrorBoundary) return /*#__PURE__*/ external_react_default().createElement(external_react_namespaceObject.Suspense, {
956
- fallback: loadingFallback || /*#__PURE__*/ external_react_default().createElement("div", null, "Loading...")
957
- }, /*#__PURE__*/ external_react_default().createElement(RemoteModuleRenderer, props));
958
- return /*#__PURE__*/ external_react_default().createElement(ErrorBoundary, {
959
- fallback: errorFallback,
960
- onError: errorBoundaryOptions?.onError,
961
- onReset: errorBoundaryOptions?.onReset
962
- }, /*#__PURE__*/ external_react_default().createElement(external_react_namespaceObject.Suspense, {
963
- fallback: loadingFallback || /*#__PURE__*/ external_react_default().createElement("div", null, "Loading...")
964
- }, /*#__PURE__*/ external_react_default().createElement(RemoteModuleRenderer, props)));
891
+ getHistory(event) {
892
+ return this.eventHistory.get(event) || [];
965
893
  }
966
- function lazyRemote(options) {
967
- const { pkg, version = 'latest', moduleName, scopeName, maxRetries = 3, retryDelay = 1000 } = options;
968
- let retryCount = 0;
969
- const loadComponent = async ()=>{
970
- try {
971
- const { mf } = await loadRemoteMultiVersion({
972
- name: scopeName,
973
- pkg,
974
- version
975
- }, []);
976
- if (!mf) throw new Error(`[RemoteReloadUtils] Failed to get Module Federation instance for ${scopeName}`);
977
- const mod = await mf.loadRemote(`${scopeName}/${moduleName}`);
978
- if (!mod || 'object' != typeof mod || !('default' in mod)) throw new Error(`[RemoteReloadUtils] Module "${scopeName}/${moduleName}" does not export a default component`);
979
- return {
980
- default: mod.default
981
- };
982
- } catch (error) {
983
- if (retryCount < maxRetries) {
984
- retryCount++;
985
- await new Promise((resolve)=>setTimeout(resolve, retryDelay * retryCount));
986
- return loadComponent();
987
- }
988
- throw error;
989
- }
990
- };
991
- return /*#__PURE__*/ (0, external_react_namespaceObject.lazy)(loadComponent);
894
+ getEvents() {
895
+ return Array.from(this.listeners.keys());
992
896
  }
993
- function SuspenseRemote({ fallback, children }) {
994
- return /*#__PURE__*/ external_react_default().createElement(external_react_namespaceObject.Suspense, {
995
- fallback: fallback || /*#__PURE__*/ external_react_default().createElement("div", null, "Loading...")
996
- }, children);
897
+ getListenerCount(event) {
898
+ return this.listeners.get(event)?.size || 0;
997
899
  }
998
- function SuspenseRemoteLoader({ pkg, version = 'latest', moduleName, scopeName, fallback, errorFallback, componentProps }) {
999
- const RemoteComponent = lazyRemote({
1000
- pkg,
1001
- version,
1002
- moduleName,
1003
- scopeName
1004
- });
1005
- if (errorFallback) return /*#__PURE__*/ external_react_default().createElement(ErrorBoundary, {
1006
- fallback: errorFallback
1007
- }, /*#__PURE__*/ external_react_default().createElement(external_react_namespaceObject.Suspense, {
1008
- fallback: fallback || /*#__PURE__*/ external_react_default().createElement("div", null, "Loading...")
1009
- }, /*#__PURE__*/ external_react_default().createElement(RemoteComponent, componentProps)));
1010
- return /*#__PURE__*/ external_react_default().createElement(external_react_namespaceObject.Suspense, {
1011
- fallback: fallback || /*#__PURE__*/ external_react_default().createElement("div", null, "Loading...")
1012
- }, /*#__PURE__*/ external_react_default().createElement(RemoteComponent, componentProps));
900
+ hasListeners(event) {
901
+ return this.listeners.has(event) && this.listeners.get(event).size > 0;
1013
902
  }
1014
- function withRemote(WrappedComponent, options) {
1015
- const RemoteComponent = lazyRemote(options);
1016
- return function(props) {
1017
- return /*#__PURE__*/ external_react_default().createElement(external_react_namespaceObject.Suspense, {
1018
- fallback: /*#__PURE__*/ external_react_default().createElement("div", null, "Loading...")
1019
- }, /*#__PURE__*/ external_react_default().createElement(RemoteComponent, props));
1020
- };
903
+ clear(event) {
904
+ if (event) {
905
+ this.listeners.delete(event);
906
+ this.eventHistory.delete(event);
907
+ } else {
908
+ this.listeners.clear();
909
+ this.eventHistory.clear();
910
+ }
1021
911
  }
1022
- function useRemoteModuleHook(options) {
1023
- const { pkg, version = 'latest', moduleName, scopeName } = options;
1024
- const [state, setState] = (0, external_react_namespaceObject.useState)({
1025
- component: null,
1026
- loading: true,
1027
- error: null
912
+ listenerExists(event, callback) {
913
+ const subscriptions = this.listeners.get(event);
914
+ if (!subscriptions) return false;
915
+ let exists = false;
916
+ subscriptions.forEach((sub)=>{
917
+ if (sub.callback === callback) exists = true;
1028
918
  });
1029
- (0, external_react_namespaceObject.useEffect)(()=>{
1030
- let mounted = true;
1031
- async function load() {
1032
- try {
1033
- setState((prev)=>({
1034
- ...prev,
1035
- loading: true,
1036
- error: null
1037
- }));
1038
- const { mf } = await loadRemoteMultiVersion({
1039
- name: scopeName,
1040
- pkg,
1041
- version
1042
- }, []);
1043
- if (!mf) throw new Error(`[RemoteReloadUtils] Failed to get Module Federation instance for ${scopeName}`);
1044
- const mod = await mf.loadRemote(`${scopeName}/${moduleName}`);
1045
- if (mounted) if (mod && 'object' == typeof mod && 'default' in mod) setState({
1046
- component: mod.default,
1047
- loading: false,
1048
- error: null
1049
- });
1050
- else throw new Error(`[RemoteReloadUtils] Module "${scopeName}/${moduleName}" does not export a default component`);
1051
- } catch (err) {
1052
- if (mounted) setState({
1053
- component: null,
1054
- loading: false,
1055
- error: err instanceof Error ? err : new Error(String(err))
1056
- });
1057
- }
1058
- }
1059
- load();
1060
- return ()=>{
1061
- mounted = false;
1062
- };
1063
- }, [
1064
- pkg,
1065
- version,
1066
- moduleName,
1067
- scopeName
1068
- ]);
1069
- return {
1070
- component: state.component,
1071
- loading: state.loading,
1072
- error: state.error
1073
- };
919
+ return exists;
1074
920
  }
1075
- })();
1076
- exports.ErrorBoundary = __webpack_exports__.ErrorBoundary;
1077
- exports.RemoteModuleProvider = __webpack_exports__.RemoteModuleProvider;
1078
- exports.RemoteModuleRenderer = __webpack_exports__.RemoteModuleRenderer;
1079
- exports.SuspenseRemote = __webpack_exports__.SuspenseRemote;
1080
- exports.SuspenseRemoteLoader = __webpack_exports__.SuspenseRemoteLoader;
921
+ emitAsync(event, data, meta) {
922
+ return new Promise((resolve)=>{
923
+ this.emit(event, data, meta);
924
+ resolve();
925
+ });
926
+ }
927
+ static create() {
928
+ return new EventBusClass();
929
+ }
930
+ }
931
+ const eventBus = EventBusClass.create();
932
+ function createEventBus() {
933
+ return EventBusClass.create();
934
+ }
1081
935
  exports.buildCdnUrls = __webpack_exports__.buildCdnUrls;
1082
936
  exports.buildFinalUrls = __webpack_exports__.buildFinalUrls;
1083
937
  exports.cancelPreload = __webpack_exports__.cancelPreload;
@@ -1087,6 +941,7 @@ exports.checkVersionCompatibility = __webpack_exports__.checkVersionCompatibilit
1087
941
  exports.clearPreloadCache = __webpack_exports__.clearPreloadCache;
1088
942
  exports.compareVersions = __webpack_exports__.compareVersions;
1089
943
  exports.createEventBus = __webpack_exports__.createEventBus;
944
+ exports.createRemoteSourcePlugin = __webpack_exports__.createRemoteSourcePlugin;
1090
945
  exports.eventBus = __webpack_exports__.eventBus;
1091
946
  exports.extractMajorVersion = __webpack_exports__.extractMajorVersion;
1092
947
  exports.fallbackPlugin = __webpack_exports__.fallbackPlugin;
@@ -1104,7 +959,6 @@ exports.getStableVersions = __webpack_exports__.getStableVersions;
1104
959
  exports.getVersionCache = __webpack_exports__.getVersionCache;
1105
960
  exports.isPrerelease = __webpack_exports__.isPrerelease;
1106
961
  exports.isRemoteLoaded = __webpack_exports__.isRemoteLoaded;
1107
- exports.lazyRemote = __webpack_exports__.lazyRemote;
1108
962
  exports.loadReactVersion = __webpack_exports__.loadReactVersion;
1109
963
  exports.loadRemoteMultiVersion = __webpack_exports__.loadRemoteMultiVersion;
1110
964
  exports.parseVersion = __webpack_exports__.parseVersion;
@@ -1119,15 +973,7 @@ exports.sortVersions = __webpack_exports__.sortVersions;
1119
973
  exports.tryLoadRemote = __webpack_exports__.tryLoadRemote;
1120
974
  exports.unloadAll = __webpack_exports__.unloadAll;
1121
975
  exports.unloadRemote = __webpack_exports__.unloadRemote;
1122
- exports.useRemoteModule = __webpack_exports__.useRemoteModule;
1123
- exports.useRemoteModuleHook = __webpack_exports__.useRemoteModuleHook;
1124
- exports.withRemote = __webpack_exports__.withRemote;
1125
976
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
1126
- "ErrorBoundary",
1127
- "RemoteModuleProvider",
1128
- "RemoteModuleRenderer",
1129
- "SuspenseRemote",
1130
- "SuspenseRemoteLoader",
1131
977
  "buildCdnUrls",
1132
978
  "buildFinalUrls",
1133
979
  "cancelPreload",
@@ -1137,6 +983,7 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
1137
983
  "clearPreloadCache",
1138
984
  "compareVersions",
1139
985
  "createEventBus",
986
+ "createRemoteSourcePlugin",
1140
987
  "eventBus",
1141
988
  "extractMajorVersion",
1142
989
  "fallbackPlugin",
@@ -1154,7 +1001,6 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
1154
1001
  "getVersionCache",
1155
1002
  "isPrerelease",
1156
1003
  "isRemoteLoaded",
1157
- "lazyRemote",
1158
1004
  "loadReactVersion",
1159
1005
  "loadRemoteMultiVersion",
1160
1006
  "parseVersion",
@@ -1168,10 +1014,7 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
1168
1014
  "sortVersions",
1169
1015
  "tryLoadRemote",
1170
1016
  "unloadAll",
1171
- "unloadRemote",
1172
- "useRemoteModule",
1173
- "useRemoteModuleHook",
1174
- "withRemote"
1017
+ "unloadRemote"
1175
1018
  ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
1176
1019
  Object.defineProperty(exports, '__esModule', {
1177
1020
  value: true