remote-reload-utils 0.0.14 → 0.0.16
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 +18 -0
- package/dist/index.d.ts +0 -3
- package/dist/main.cjs +785 -988
- package/dist/main.js +169 -334
- package/dist/plugins/register-shared-react.d.ts +6 -0
- package/package.json +28 -2
- package/dist/components/ErrorBoundary.d.ts +0 -34
- package/dist/components/RemoteModuleProvider.d.ts +0 -95
- package/dist/components/SuspenseLoader.d.ts +0 -131
- package/dist/components/index.d.ts +0 -6
package/dist/main.js
CHANGED
|
@@ -1,19 +1,4 @@
|
|
|
1
1
|
import { createInstance } from "@module-federation/enhanced/runtime";
|
|
2
|
-
import react, { Suspense, lazy, useCallback, useEffect, useState } from "react";
|
|
3
|
-
var __webpack_modules__ = {
|
|
4
|
-
"./src/styles/index.css": function() {}
|
|
5
|
-
};
|
|
6
|
-
var __webpack_module_cache__ = {};
|
|
7
|
-
function __webpack_require__(moduleId) {
|
|
8
|
-
var cachedModule = __webpack_module_cache__[moduleId];
|
|
9
|
-
if (void 0 !== cachedModule) return cachedModule.exports;
|
|
10
|
-
var module = __webpack_module_cache__[moduleId] = {
|
|
11
|
-
exports: {}
|
|
12
|
-
};
|
|
13
|
-
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
14
|
-
return module.exports;
|
|
15
|
-
}
|
|
16
|
-
__webpack_require__("./src/styles/index.css");
|
|
17
2
|
async function loadReactVersion(version) {
|
|
18
3
|
const runtime = await createInstance({
|
|
19
4
|
name: `react_${version}_runtime`,
|
|
@@ -195,15 +180,46 @@ const DEFAULT_SHARED_CONFIG = {
|
|
|
195
180
|
shareConfig: {
|
|
196
181
|
singleton: true,
|
|
197
182
|
eager: true,
|
|
198
|
-
requiredVersion: false
|
|
199
|
-
|
|
183
|
+
requiredVersion: false,
|
|
184
|
+
strictVersion: false
|
|
185
|
+
},
|
|
186
|
+
strategy: 'loaded-first'
|
|
200
187
|
},
|
|
201
188
|
'react-dom': {
|
|
202
189
|
shareConfig: {
|
|
203
190
|
singleton: true,
|
|
204
191
|
eager: true,
|
|
205
|
-
requiredVersion: false
|
|
206
|
-
|
|
192
|
+
requiredVersion: false,
|
|
193
|
+
strictVersion: false
|
|
194
|
+
},
|
|
195
|
+
strategy: 'loaded-first'
|
|
196
|
+
},
|
|
197
|
+
'react-dom/client': {
|
|
198
|
+
shareConfig: {
|
|
199
|
+
singleton: true,
|
|
200
|
+
eager: true,
|
|
201
|
+
requiredVersion: false,
|
|
202
|
+
strictVersion: false
|
|
203
|
+
},
|
|
204
|
+
strategy: 'loaded-first'
|
|
205
|
+
},
|
|
206
|
+
'react/jsx-runtime': {
|
|
207
|
+
shareConfig: {
|
|
208
|
+
singleton: true,
|
|
209
|
+
eager: true,
|
|
210
|
+
requiredVersion: false,
|
|
211
|
+
strictVersion: false
|
|
212
|
+
},
|
|
213
|
+
strategy: 'loaded-first'
|
|
214
|
+
},
|
|
215
|
+
'react/jsx-dev-runtime': {
|
|
216
|
+
shareConfig: {
|
|
217
|
+
singleton: true,
|
|
218
|
+
eager: true,
|
|
219
|
+
requiredVersion: false,
|
|
220
|
+
strictVersion: false
|
|
221
|
+
},
|
|
222
|
+
strategy: 'loaded-first'
|
|
207
223
|
}
|
|
208
224
|
};
|
|
209
225
|
async function fetchLatestVersion(pkg) {
|
|
@@ -238,41 +254,146 @@ function setVersionCache(pkg, version) {
|
|
|
238
254
|
function buildCdnUrls(pkg, version) {
|
|
239
255
|
return DEFAULT_CDN_TEMPLATES.map((template)=>template.replace('{pkg}', pkg).replace('{version}', version));
|
|
240
256
|
}
|
|
257
|
+
const mfInstanceCache = new Map();
|
|
258
|
+
const mfInstanceLoadingCache = new Map();
|
|
241
259
|
async function tryLoadRemote(scopeName, url, retries, delay, sharedConfig, plugins) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
260
|
+
const cacheKey = `${scopeName}::${url}`;
|
|
261
|
+
const cachedMfs = mfInstanceCache.get(cacheKey);
|
|
262
|
+
if (cachedMfs) return {
|
|
263
|
+
scopeName,
|
|
264
|
+
mf: cachedMfs
|
|
265
|
+
};
|
|
266
|
+
const loadingMfs = mfInstanceLoadingCache.get(cacheKey);
|
|
267
|
+
if (loadingMfs) return loadingMfs;
|
|
268
|
+
const createProcess = (async ()=>{
|
|
269
|
+
let lastError;
|
|
270
|
+
for(let i = 0; i < retries; i++)try {
|
|
271
|
+
const mf = createInstance({
|
|
272
|
+
name: 'host',
|
|
273
|
+
remotes: [
|
|
274
|
+
{
|
|
275
|
+
name: scopeName,
|
|
276
|
+
entry: url
|
|
277
|
+
}
|
|
278
|
+
],
|
|
279
|
+
shared: sharedConfig,
|
|
280
|
+
plugins: [
|
|
281
|
+
...plugins,
|
|
282
|
+
fallbackPlugin()
|
|
283
|
+
]
|
|
284
|
+
});
|
|
285
|
+
const result = {
|
|
286
|
+
scopeName,
|
|
287
|
+
mf
|
|
288
|
+
};
|
|
289
|
+
mfInstanceCache.set(cacheKey, mf);
|
|
290
|
+
return result;
|
|
291
|
+
} catch (e) {
|
|
292
|
+
lastError = e;
|
|
293
|
+
console.warn(`[MF] URL ${url} 加载失败,第 ${i + 1} 次重试...`);
|
|
294
|
+
if (i < retries - 1) await new Promise((res)=>setTimeout(res, delay));
|
|
295
|
+
}
|
|
296
|
+
throw new Error(`[MF] URL ${url} 经过 ${retries} 次重试仍加载失败。`, {
|
|
297
|
+
cause: lastError
|
|
257
298
|
});
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
console.warn(`[MF] URL ${url} 加载失败,第 ${i + 1} 次重试...`);
|
|
265
|
-
if (i < retries - 1) await new Promise((res)=>setTimeout(res, delay));
|
|
299
|
+
})();
|
|
300
|
+
mfInstanceLoadingCache.set(cacheKey, createProcess);
|
|
301
|
+
try {
|
|
302
|
+
return await createProcess;
|
|
303
|
+
} finally{
|
|
304
|
+
mfInstanceLoadingCache.delete(cacheKey);
|
|
266
305
|
}
|
|
267
|
-
throw new Error(`[MF] URL ${url} 经过 ${retries} 次重试仍加载失败。`, {
|
|
268
|
-
cause: lastError
|
|
269
|
-
});
|
|
270
306
|
}
|
|
271
307
|
function getFinalSharedConfig(customShared) {
|
|
272
|
-
|
|
308
|
+
const globalReact = window.React;
|
|
309
|
+
const globalReactDOM = window.ReactDOM;
|
|
310
|
+
const globalShared = {};
|
|
311
|
+
if (globalReact && globalReactDOM) {
|
|
312
|
+
const isValidReact = 'object' == typeof globalReact && 'function' == typeof globalReact.useCallback;
|
|
313
|
+
if (isValidReact) {
|
|
314
|
+
globalShared.react = {
|
|
315
|
+
version: globalReact.version || '18.0.0',
|
|
316
|
+
lib: ()=>globalReact,
|
|
317
|
+
shareConfig: {
|
|
318
|
+
singleton: true,
|
|
319
|
+
eager: true,
|
|
320
|
+
requiredVersion: false,
|
|
321
|
+
strictVersion: false
|
|
322
|
+
},
|
|
323
|
+
strategy: 'loaded-first'
|
|
324
|
+
};
|
|
325
|
+
globalShared['react-dom'] = {
|
|
326
|
+
version: globalReactDOM.version || '18.0.0',
|
|
327
|
+
lib: ()=>globalReactDOM,
|
|
328
|
+
shareConfig: {
|
|
329
|
+
singleton: true,
|
|
330
|
+
eager: true,
|
|
331
|
+
requiredVersion: false,
|
|
332
|
+
strictVersion: false
|
|
333
|
+
},
|
|
334
|
+
strategy: 'loaded-first'
|
|
335
|
+
};
|
|
336
|
+
globalShared['react-dom/client'] = {
|
|
337
|
+
version: globalReactDOM.version || '18.0.0',
|
|
338
|
+
lib: ()=>globalReactDOM,
|
|
339
|
+
shareConfig: {
|
|
340
|
+
singleton: true,
|
|
341
|
+
eager: true,
|
|
342
|
+
requiredVersion: false,
|
|
343
|
+
strictVersion: false
|
|
344
|
+
},
|
|
345
|
+
strategy: 'loaded-first'
|
|
346
|
+
};
|
|
347
|
+
console.log('[getFinalSharedConfig] Using global React instance', {
|
|
348
|
+
version: globalReact.version
|
|
349
|
+
});
|
|
350
|
+
} else console.warn('[getFinalSharedConfig] Global React found but is invalid', {
|
|
351
|
+
type: typeof globalReact,
|
|
352
|
+
useCallback: typeof globalReact?.useCallback
|
|
353
|
+
});
|
|
354
|
+
} else console.log('[getFinalSharedConfig] No global React found, using default shared config');
|
|
355
|
+
const mergedShared = {
|
|
273
356
|
...DEFAULT_SHARED_CONFIG,
|
|
357
|
+
...globalShared,
|
|
274
358
|
...customShared || {}
|
|
275
359
|
};
|
|
360
|
+
const keepSingletonPackages = [
|
|
361
|
+
'react',
|
|
362
|
+
'react-dom',
|
|
363
|
+
'react-dom/client',
|
|
364
|
+
'react/jsx-runtime',
|
|
365
|
+
'react/jsx-dev-runtime'
|
|
366
|
+
];
|
|
367
|
+
for (const pkgName of keepSingletonPackages){
|
|
368
|
+
const base = mergedShared[pkgName] || {};
|
|
369
|
+
mergedShared[pkgName] = {
|
|
370
|
+
...base,
|
|
371
|
+
strategy: 'loaded-first',
|
|
372
|
+
shareConfig: {
|
|
373
|
+
singleton: true,
|
|
374
|
+
eager: true,
|
|
375
|
+
requiredVersion: false,
|
|
376
|
+
strictVersion: false,
|
|
377
|
+
...base.shareConfig || {}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
if ('function' == typeof globalShared.react?.lib) mergedShared.react = {
|
|
382
|
+
...mergedShared.react || {},
|
|
383
|
+
lib: globalShared.react.lib,
|
|
384
|
+
version: globalShared.react.version
|
|
385
|
+
};
|
|
386
|
+
if ('function' == typeof globalShared['react-dom']?.lib) mergedShared['react-dom'] = {
|
|
387
|
+
...mergedShared['react-dom'] || {},
|
|
388
|
+
lib: globalShared['react-dom'].lib,
|
|
389
|
+
version: globalShared['react-dom'].version
|
|
390
|
+
};
|
|
391
|
+
if ('function' == typeof globalShared['react-dom/client']?.lib) mergedShared['react-dom/client'] = {
|
|
392
|
+
...mergedShared['react-dom/client'] || {},
|
|
393
|
+
lib: globalShared['react-dom/client'].lib,
|
|
394
|
+
version: globalShared['react-dom/client'].version
|
|
395
|
+
};
|
|
396
|
+
return mergedShared;
|
|
276
397
|
}
|
|
277
398
|
async function resolveFinalVersion(pkg, version, cacheTTL, revalidate) {
|
|
278
399
|
let finalVersion = version;
|
|
@@ -306,6 +427,7 @@ async function loadRemoteMultiVersion(options, plugins) {
|
|
|
306
427
|
const scopeName = `${name}`;
|
|
307
428
|
const urls = buildFinalUrls(pkg, finalVersion, localFallback);
|
|
308
429
|
const finalSharedConfig = getFinalSharedConfig(customShared);
|
|
430
|
+
console.log(finalSharedConfig, 'finalSharedConfig');
|
|
309
431
|
for (const url of urls)try {
|
|
310
432
|
return await tryLoadRemote(scopeName, url, retries, delay, finalSharedConfig, plugins);
|
|
311
433
|
} catch (e) {
|
|
@@ -699,291 +821,4 @@ const eventBus = EventBusClass.create();
|
|
|
699
821
|
function createEventBus() {
|
|
700
822
|
return EventBusClass.create();
|
|
701
823
|
}
|
|
702
|
-
|
|
703
|
-
constructor(props){
|
|
704
|
-
super(props);
|
|
705
|
-
this.state = {
|
|
706
|
-
hasError: false,
|
|
707
|
-
error: null,
|
|
708
|
-
errorInfo: null
|
|
709
|
-
};
|
|
710
|
-
}
|
|
711
|
-
static getDerivedStateFromError(error) {
|
|
712
|
-
return {
|
|
713
|
-
hasError: true,
|
|
714
|
-
error,
|
|
715
|
-
errorInfo: null
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
componentDidCatch(error, errorInfo) {
|
|
719
|
-
this.setState({
|
|
720
|
-
errorInfo
|
|
721
|
-
});
|
|
722
|
-
this.props.onError?.(error, errorInfo);
|
|
723
|
-
console.error('[RemoteReloadUtils] ErrorBoundary caught error:', error, errorInfo);
|
|
724
|
-
}
|
|
725
|
-
handleReset = ()=>{
|
|
726
|
-
this.setState({
|
|
727
|
-
hasError: false,
|
|
728
|
-
error: null,
|
|
729
|
-
errorInfo: null
|
|
730
|
-
});
|
|
731
|
-
this.props.onReset?.();
|
|
732
|
-
};
|
|
733
|
-
render() {
|
|
734
|
-
if (this.state.hasError && this.state.error) {
|
|
735
|
-
if ('function' == typeof this.props.fallback) return this.props.fallback(this.state.error, this.handleReset);
|
|
736
|
-
if (void 0 !== this.props.fallback) return this.props.fallback;
|
|
737
|
-
return /*#__PURE__*/ react.createElement("div", {
|
|
738
|
-
role: "alert",
|
|
739
|
-
className: "p-4 border border-red-200 bg-red-50 rounded-lg"
|
|
740
|
-
}, /*#__PURE__*/ react.createElement("h3", {
|
|
741
|
-
className: "text-lg font-semibold mb-2"
|
|
742
|
-
}, "Something went wrong"), /*#__PURE__*/ react.createElement("p", {
|
|
743
|
-
className: "text-red-700"
|
|
744
|
-
}, this.state.error.message), /*#__PURE__*/ react.createElement("button", {
|
|
745
|
-
onClick: this.handleReset,
|
|
746
|
-
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"
|
|
747
|
-
}, "Try again"));
|
|
748
|
-
}
|
|
749
|
-
return this.props.children;
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
function useRemoteModule({ pkg, version, moduleName, scopeName, onError, onLoad, retryKey = 0 }) {
|
|
753
|
-
const [moduleState, setModuleState] = useState({
|
|
754
|
-
loading: true,
|
|
755
|
-
error: null,
|
|
756
|
-
component: null
|
|
757
|
-
});
|
|
758
|
-
useEffect(()=>{
|
|
759
|
-
let mounted = true;
|
|
760
|
-
async function loadModule() {
|
|
761
|
-
try {
|
|
762
|
-
setModuleState((prev)=>({
|
|
763
|
-
...prev,
|
|
764
|
-
loading: true,
|
|
765
|
-
error: null
|
|
766
|
-
}));
|
|
767
|
-
const { mf } = await loadRemoteMultiVersion({
|
|
768
|
-
name: scopeName,
|
|
769
|
-
pkg,
|
|
770
|
-
version
|
|
771
|
-
}, []);
|
|
772
|
-
if (!mf || !mounted) return;
|
|
773
|
-
const mod = await mf.loadRemote(`${scopeName}/${moduleName}`);
|
|
774
|
-
if (!mounted) return;
|
|
775
|
-
if (mod && 'object' == typeof mod && 'default' in mod) {
|
|
776
|
-
const Component = mod.default;
|
|
777
|
-
setModuleState({
|
|
778
|
-
loading: false,
|
|
779
|
-
error: null,
|
|
780
|
-
component: Component
|
|
781
|
-
});
|
|
782
|
-
onLoad?.(Component);
|
|
783
|
-
} else throw new Error(`Module "${scopeName}/${moduleName}" does not export a default component`);
|
|
784
|
-
} catch (err) {
|
|
785
|
-
if (mounted) {
|
|
786
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
787
|
-
setModuleState({
|
|
788
|
-
loading: false,
|
|
789
|
-
error,
|
|
790
|
-
component: null
|
|
791
|
-
});
|
|
792
|
-
onError?.(error);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
loadModule();
|
|
797
|
-
return ()=>{
|
|
798
|
-
mounted = false;
|
|
799
|
-
};
|
|
800
|
-
}, [
|
|
801
|
-
pkg,
|
|
802
|
-
version,
|
|
803
|
-
moduleName,
|
|
804
|
-
scopeName,
|
|
805
|
-
onError,
|
|
806
|
-
onLoad,
|
|
807
|
-
retryKey
|
|
808
|
-
]);
|
|
809
|
-
return moduleState;
|
|
810
|
-
}
|
|
811
|
-
function RemoteModuleRenderer({ pkg, version, moduleName, scopeName, loadingFallback, errorFallback, componentProps, className, style, onError, onLoad }) {
|
|
812
|
-
const moduleState = useRemoteModule({
|
|
813
|
-
pkg,
|
|
814
|
-
version,
|
|
815
|
-
moduleName,
|
|
816
|
-
scopeName,
|
|
817
|
-
onError,
|
|
818
|
-
onLoad
|
|
819
|
-
});
|
|
820
|
-
const [retryKey, setRetryKey] = useState(0);
|
|
821
|
-
const handleRetry = useCallback(()=>{
|
|
822
|
-
setRetryKey((prev)=>prev + 1);
|
|
823
|
-
}, []);
|
|
824
|
-
useEffect(()=>{}, [
|
|
825
|
-
retryKey
|
|
826
|
-
]);
|
|
827
|
-
if (moduleState.loading) return /*#__PURE__*/ react.createElement("div", {
|
|
828
|
-
className: className,
|
|
829
|
-
style: style,
|
|
830
|
-
role: "status",
|
|
831
|
-
"aria-live": "polite"
|
|
832
|
-
}, loadingFallback || /*#__PURE__*/ react.createElement("div", {
|
|
833
|
-
className: "module-card module-card--loading"
|
|
834
|
-
}, /*#__PURE__*/ react.createElement("div", {
|
|
835
|
-
className: "loading-spinner",
|
|
836
|
-
"aria-hidden": "true"
|
|
837
|
-
}), /*#__PURE__*/ react.createElement("span", {
|
|
838
|
-
className: "text-gray-600"
|
|
839
|
-
}, "Loading ", moduleName, "...")));
|
|
840
|
-
if (moduleState.error) {
|
|
841
|
-
if ('function' == typeof errorFallback) return /*#__PURE__*/ react.createElement(react.Fragment, null, errorFallback(moduleState.error, handleRetry));
|
|
842
|
-
if (void 0 !== errorFallback) return /*#__PURE__*/ react.createElement(react.Fragment, null, errorFallback);
|
|
843
|
-
return /*#__PURE__*/ react.createElement("div", {
|
|
844
|
-
className: className,
|
|
845
|
-
style: style,
|
|
846
|
-
role: "alert"
|
|
847
|
-
}, /*#__PURE__*/ react.createElement("div", {
|
|
848
|
-
className: "module-card module-card--error"
|
|
849
|
-
}, /*#__PURE__*/ react.createElement("span", {
|
|
850
|
-
className: "error-icon",
|
|
851
|
-
"aria-hidden": "true"
|
|
852
|
-
}, "!"), /*#__PURE__*/ react.createElement("span", null, "Failed to load ", moduleName), /*#__PURE__*/ react.createElement("p", {
|
|
853
|
-
className: "error-message"
|
|
854
|
-
}, moduleState.error.message), /*#__PURE__*/ react.createElement("button", {
|
|
855
|
-
onClick: handleRetry,
|
|
856
|
-
className: "retry-button",
|
|
857
|
-
type: "button"
|
|
858
|
-
}, "Retry")));
|
|
859
|
-
}
|
|
860
|
-
if (!moduleState.component) return null;
|
|
861
|
-
const Component = moduleState.component;
|
|
862
|
-
return /*#__PURE__*/ react.createElement("div", {
|
|
863
|
-
className: className,
|
|
864
|
-
style: style
|
|
865
|
-
}, /*#__PURE__*/ react.createElement(Component, componentProps));
|
|
866
|
-
}
|
|
867
|
-
function RemoteModuleProvider(props) {
|
|
868
|
-
const { disableErrorBoundary, errorFallback, loadingFallback, errorBoundaryOptions } = props;
|
|
869
|
-
if (disableErrorBoundary) return /*#__PURE__*/ react.createElement(Suspense, {
|
|
870
|
-
fallback: loadingFallback || /*#__PURE__*/ react.createElement("div", null, "Loading...")
|
|
871
|
-
}, /*#__PURE__*/ react.createElement(RemoteModuleRenderer, props));
|
|
872
|
-
return /*#__PURE__*/ react.createElement(ErrorBoundary, {
|
|
873
|
-
fallback: errorFallback,
|
|
874
|
-
onError: errorBoundaryOptions?.onError,
|
|
875
|
-
onReset: errorBoundaryOptions?.onReset
|
|
876
|
-
}, /*#__PURE__*/ react.createElement(Suspense, {
|
|
877
|
-
fallback: loadingFallback || /*#__PURE__*/ react.createElement("div", null, "Loading...")
|
|
878
|
-
}, /*#__PURE__*/ react.createElement(RemoteModuleRenderer, props)));
|
|
879
|
-
}
|
|
880
|
-
function lazyRemote(options) {
|
|
881
|
-
const { pkg, version = 'latest', moduleName, scopeName, maxRetries = 3, retryDelay = 1000 } = options;
|
|
882
|
-
let retryCount = 0;
|
|
883
|
-
const loadComponent = async ()=>{
|
|
884
|
-
try {
|
|
885
|
-
const { mf } = await loadRemoteMultiVersion({
|
|
886
|
-
name: scopeName,
|
|
887
|
-
pkg,
|
|
888
|
-
version
|
|
889
|
-
}, []);
|
|
890
|
-
if (!mf) throw new Error(`[RemoteReloadUtils] Failed to get Module Federation instance for ${scopeName}`);
|
|
891
|
-
const mod = await mf.loadRemote(`${scopeName}/${moduleName}`);
|
|
892
|
-
if (!mod || 'object' != typeof mod || !('default' in mod)) throw new Error(`[RemoteReloadUtils] Module "${scopeName}/${moduleName}" does not export a default component`);
|
|
893
|
-
return {
|
|
894
|
-
default: mod.default
|
|
895
|
-
};
|
|
896
|
-
} catch (error) {
|
|
897
|
-
if (retryCount < maxRetries) {
|
|
898
|
-
retryCount++;
|
|
899
|
-
await new Promise((resolve)=>setTimeout(resolve, retryDelay * retryCount));
|
|
900
|
-
return loadComponent();
|
|
901
|
-
}
|
|
902
|
-
throw error;
|
|
903
|
-
}
|
|
904
|
-
};
|
|
905
|
-
return /*#__PURE__*/ lazy(loadComponent);
|
|
906
|
-
}
|
|
907
|
-
function SuspenseRemote({ fallback, children }) {
|
|
908
|
-
return /*#__PURE__*/ react.createElement(Suspense, {
|
|
909
|
-
fallback: fallback || /*#__PURE__*/ react.createElement("div", null, "Loading...")
|
|
910
|
-
}, children);
|
|
911
|
-
}
|
|
912
|
-
function SuspenseRemoteLoader({ pkg, version = 'latest', moduleName, scopeName, fallback, errorFallback, componentProps }) {
|
|
913
|
-
const RemoteComponent = lazyRemote({
|
|
914
|
-
pkg,
|
|
915
|
-
version,
|
|
916
|
-
moduleName,
|
|
917
|
-
scopeName
|
|
918
|
-
});
|
|
919
|
-
if (errorFallback) return /*#__PURE__*/ react.createElement(ErrorBoundary, {
|
|
920
|
-
fallback: errorFallback
|
|
921
|
-
}, /*#__PURE__*/ react.createElement(Suspense, {
|
|
922
|
-
fallback: fallback || /*#__PURE__*/ react.createElement("div", null, "Loading...")
|
|
923
|
-
}, /*#__PURE__*/ react.createElement(RemoteComponent, componentProps)));
|
|
924
|
-
return /*#__PURE__*/ react.createElement(Suspense, {
|
|
925
|
-
fallback: fallback || /*#__PURE__*/ react.createElement("div", null, "Loading...")
|
|
926
|
-
}, /*#__PURE__*/ react.createElement(RemoteComponent, componentProps));
|
|
927
|
-
}
|
|
928
|
-
function withRemote(WrappedComponent, options) {
|
|
929
|
-
const RemoteComponent = lazyRemote(options);
|
|
930
|
-
return function(props) {
|
|
931
|
-
return /*#__PURE__*/ react.createElement(Suspense, {
|
|
932
|
-
fallback: /*#__PURE__*/ react.createElement("div", null, "Loading...")
|
|
933
|
-
}, /*#__PURE__*/ react.createElement(RemoteComponent, props));
|
|
934
|
-
};
|
|
935
|
-
}
|
|
936
|
-
function useRemoteModuleHook(options) {
|
|
937
|
-
const { pkg, version = 'latest', moduleName, scopeName } = options;
|
|
938
|
-
const [state, setState] = useState({
|
|
939
|
-
component: null,
|
|
940
|
-
loading: true,
|
|
941
|
-
error: null
|
|
942
|
-
});
|
|
943
|
-
useEffect(()=>{
|
|
944
|
-
let mounted = true;
|
|
945
|
-
async function load() {
|
|
946
|
-
try {
|
|
947
|
-
setState((prev)=>({
|
|
948
|
-
...prev,
|
|
949
|
-
loading: true,
|
|
950
|
-
error: null
|
|
951
|
-
}));
|
|
952
|
-
const { mf } = await loadRemoteMultiVersion({
|
|
953
|
-
name: scopeName,
|
|
954
|
-
pkg,
|
|
955
|
-
version
|
|
956
|
-
}, []);
|
|
957
|
-
if (!mf) throw new Error(`[RemoteReloadUtils] Failed to get Module Federation instance for ${scopeName}`);
|
|
958
|
-
const mod = await mf.loadRemote(`${scopeName}/${moduleName}`);
|
|
959
|
-
if (mounted) if (mod && 'object' == typeof mod && 'default' in mod) setState({
|
|
960
|
-
component: mod.default,
|
|
961
|
-
loading: false,
|
|
962
|
-
error: null
|
|
963
|
-
});
|
|
964
|
-
else throw new Error(`[RemoteReloadUtils] Module "${scopeName}/${moduleName}" does not export a default component`);
|
|
965
|
-
} catch (err) {
|
|
966
|
-
if (mounted) setState({
|
|
967
|
-
component: null,
|
|
968
|
-
loading: false,
|
|
969
|
-
error: err instanceof Error ? err : new Error(String(err))
|
|
970
|
-
});
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
load();
|
|
974
|
-
return ()=>{
|
|
975
|
-
mounted = false;
|
|
976
|
-
};
|
|
977
|
-
}, [
|
|
978
|
-
pkg,
|
|
979
|
-
version,
|
|
980
|
-
moduleName,
|
|
981
|
-
scopeName
|
|
982
|
-
]);
|
|
983
|
-
return {
|
|
984
|
-
component: state.component,
|
|
985
|
-
loading: state.loading,
|
|
986
|
-
error: state.error
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
|
-
export { ErrorBoundary, RemoteModuleProvider, RemoteModuleRenderer, SuspenseRemote, SuspenseRemoteLoader, buildCdnUrls, buildFinalUrls, cancelPreload, checkModuleLoadable, checkRemoteHealth, checkVersionCompatibility, clearPreloadCache, compareVersions, createEventBus, eventBus, extractMajorVersion, fallbackPlugin, fetchAvailableVersions, fetchLatestVersion, findCompatibleVersion, formatHealthStatus, getCompatibleReactVersions, getFinalSharedConfig, getLatestVersion, getLoadedRemotes, getPreloadStatus, getRemoteHealthReport, getStableVersions, getVersionCache, isPrerelease, isRemoteLoaded, lazyRemote, loadReactVersion, loadRemoteMultiVersion, parseVersion, preloadRemote, preloadRemoteList, registerLoadedModule, registerRemoteInstance, resolveFinalVersion, satisfiesVersion, setVersionCache, sortVersions, tryLoadRemote, unloadAll, unloadRemote, useRemoteModule, useRemoteModuleHook, withRemote };
|
|
824
|
+
export { buildCdnUrls, buildFinalUrls, cancelPreload, checkModuleLoadable, checkRemoteHealth, checkVersionCompatibility, clearPreloadCache, compareVersions, createEventBus, eventBus, extractMajorVersion, fallbackPlugin, fetchAvailableVersions, fetchLatestVersion, findCompatibleVersion, formatHealthStatus, getCompatibleReactVersions, getFinalSharedConfig, getLatestVersion, getLoadedRemotes, getPreloadStatus, getRemoteHealthReport, getStableVersions, getVersionCache, isPrerelease, isRemoteLoaded, loadReactVersion, loadRemoteMultiVersion, parseVersion, preloadRemote, preloadRemoteList, registerLoadedModule, registerRemoteInstance, resolveFinalVersion, satisfiesVersion, setVersionCache, sortVersions, tryLoadRemote, unloadAll, unloadRemote };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ModuleFederationRuntimePlugin } from '@module-federation/enhanced/runtime';
|
|
2
|
+
export declare function initSharedScope(): void;
|
|
3
|
+
/**
|
|
4
|
+
* 注册全局 React/ReactDOM 到 Module Federation 共享作用域
|
|
5
|
+
*/
|
|
6
|
+
export declare const registerSharedReact: () => ModuleFederationRuntimePlugin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remote-reload-utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Utilities for remote reload in Module Federation & React Component",
|
|
6
6
|
"exports": {
|
|
@@ -13,6 +13,26 @@
|
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"default": "./dist/main.cjs"
|
|
15
15
|
}
|
|
16
|
+
},
|
|
17
|
+
"./vue": {
|
|
18
|
+
"import": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/main.js"
|
|
21
|
+
},
|
|
22
|
+
"require": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/main.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./react": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/main.js"
|
|
31
|
+
},
|
|
32
|
+
"require": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"default": "./dist/main.cjs"
|
|
35
|
+
}
|
|
16
36
|
}
|
|
17
37
|
},
|
|
18
38
|
"main": "./dist/main.cjs",
|
|
@@ -29,7 +49,13 @@
|
|
|
29
49
|
},
|
|
30
50
|
"peerDependencies": {
|
|
31
51
|
"react": ">=17.0.0",
|
|
32
|
-
"react-dom": ">=17.0.0"
|
|
52
|
+
"react-dom": ">=17.0.0",
|
|
53
|
+
"vue": ">=3.0.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"vue": {
|
|
57
|
+
"optional": true
|
|
58
|
+
}
|
|
33
59
|
},
|
|
34
60
|
"scripts": {
|
|
35
61
|
"build": "rslib build",
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
export interface ErrorBoundaryProps {
|
|
3
|
-
children: React.ReactNode;
|
|
4
|
-
fallback?: React.ReactNode | ((error: Error, resetError: () => void) => React.ReactNode);
|
|
5
|
-
onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
|
|
6
|
-
onReset?: () => void;
|
|
7
|
-
}
|
|
8
|
-
interface ErrorBoundaryState {
|
|
9
|
-
hasError: boolean;
|
|
10
|
-
error: Error | null;
|
|
11
|
-
errorInfo?: React.ErrorInfo | null;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* 错误边界组件
|
|
15
|
-
* 用于捕获子组件树中的错误,并显示降级 UI
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```tsx
|
|
19
|
-
* <ErrorBoundary
|
|
20
|
-
* fallback={(error, reset) => <div onClick={reset}>Error: {error.message}</div>}
|
|
21
|
-
* onError={(error, info) => console.error(error, info)}
|
|
22
|
-
* >
|
|
23
|
-
* <MyComponent />
|
|
24
|
-
* </ErrorBoundary>
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export declare class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
28
|
-
constructor(props: ErrorBoundaryProps);
|
|
29
|
-
static getDerivedStateFromError(error: Error): ErrorBoundaryState;
|
|
30
|
-
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
|
|
31
|
-
handleReset: () => void;
|
|
32
|
-
render(): string | number | boolean | Iterable<React.ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
|
33
|
-
}
|
|
34
|
-
export {};
|