remote-reload-utils 0.0.16 → 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/CHANGELOG.md CHANGED
@@ -7,6 +7,13 @@
7
7
 
8
8
  ## [未发布]
9
9
 
10
+ ## [0.0.17] - 2026-03-19
11
+
12
+ ### Release
13
+
14
+ - Published version 0.0.17 with patch bump
15
+
16
+
10
17
  ## [0.0.16] - 2026-03-18
11
18
 
12
19
  ### Release
@@ -172,6 +179,8 @@
172
179
 
173
180
  | 版本 | 日期 | 主要变更 |
174
181
  |------|------|----------|
182
+ | 0.0.17 | 2026-03-19 | patch 版本发布 |
183
+ |------|------|----------|
175
184
  | 0.0.16 | 2026-03-18 | patch 版本发布 |
176
185
  |------|------|----------|
177
186
  | 0.0.15 | 2026-03-17 | patch 版本发布 |
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { loadReactVersion } from './version/react';
2
2
  export { checkVersionCompatibility, satisfiesVersion, findCompatibleVersion, getCompatibleReactVersions, fetchAvailableVersions, sortVersions, getLatestVersion, getStableVersions, extractMajorVersion, isPrerelease, compareVersions, parseVersion, } from './version';
3
- export { loadRemoteMultiVersion } from './loader';
4
- export { fetchLatestVersion, getVersionCache, setVersionCache, buildCdnUrls, tryLoadRemote, getFinalSharedConfig, resolveFinalVersion, buildFinalUrls, type LoadResult, } from './loader/utils';
3
+ export { loadRemoteMultiVersion, createRemoteSourcePlugin, type RemoteSourcePlugin, type RemoteSourcePluginContext, type LoadRemoteExtraOptions, } from './loader';
4
+ export { fetchLatestVersion, getVersionCache, setVersionCache, buildCdnUrls, tryLoadRemote, getFinalSharedConfig, resolveFinalVersion, buildFinalUrls, type LoadResult, type RuntimeRemote, } from './loader/utils';
5
5
  export { preloadRemote, preloadRemoteList, cancelPreload, clearPreloadCache, getPreloadStatus, } from './preload';
6
6
  export { unloadRemote, unloadAll, registerRemoteInstance, registerLoadedModule, getLoadedRemotes, isRemoteLoaded, } from './unload';
7
7
  export { checkRemoteHealth, checkModuleLoadable, getRemoteHealthReport, formatHealthStatus, } from './health';
@@ -1,6 +1,8 @@
1
- import { ModuleFederationRuntimePlugin } from '@module-federation/enhanced/runtime';
1
+ import type { ModuleFederationRuntimePlugin } from '@module-federation/enhanced/runtime';
2
2
  import type { LoadRemoteOptions } from '../types';
3
+ import { createRemoteSourcePlugin, type LoadRemoteExtraOptions, type RemoteSourcePlugin, type RemoteSourcePluginContext } from './remote-source';
4
+ export { createRemoteSourcePlugin, type RemoteSourcePlugin, type RemoteSourcePluginContext, type LoadRemoteExtraOptions, };
3
5
  /**
4
6
  * 多版本共存的 loadRemote
5
7
  */
6
- export declare function loadRemoteMultiVersion(options: LoadRemoteOptions, plugins: ModuleFederationRuntimePlugin[]): Promise<import("./utils").LoadResult>;
8
+ export declare function loadRemoteMultiVersion(options: LoadRemoteOptions, plugins?: ModuleFederationRuntimePlugin[], extraOptions?: LoadRemoteExtraOptions): Promise<import("./utils").LoadResult>;
@@ -0,0 +1,28 @@
1
+ import type { LoadRemoteOptions } from '../../types';
2
+ import type { RuntimeRemote } from '../utils';
3
+ type MaybePromise<T> = T | Promise<T>;
4
+ export interface RemoteSourcePluginContext {
5
+ options: LoadRemoteOptions;
6
+ scopeName: string;
7
+ pkg: string;
8
+ finalVersion: string;
9
+ currentEntry: string;
10
+ allEntries: string[];
11
+ }
12
+ export interface RemoteSourcePlugin {
13
+ name: string;
14
+ registerRemotes?: (context: RemoteSourcePluginContext) => MaybePromise<RuntimeRemote[] | void>;
15
+ }
16
+ export interface LoadRemoteExtraOptions {
17
+ remoteSourcePlugins?: RemoteSourcePlugin[];
18
+ baseRemotes?: RuntimeRemote[];
19
+ registerOptions?: {
20
+ force?: boolean;
21
+ };
22
+ }
23
+ export declare function resolveRegisteredRemotes(context: RemoteSourcePluginContext, baseRemotes: RuntimeRemote[], remoteSourcePlugins: RemoteSourcePlugin[]): Promise<RuntimeRemote[]>;
24
+ /**
25
+ * 创建静态 remote 来源插件
26
+ */
27
+ export declare function createRemoteSourcePlugin(name: string, remotes: RuntimeRemote[]): RemoteSourcePlugin;
28
+ export {};
@@ -20,10 +20,14 @@ export interface LoadResult {
20
20
  scopeName: string;
21
21
  mf: ReturnType<typeof createInstance>;
22
22
  }
23
+ export type RuntimeRemote = Parameters<ReturnType<typeof createInstance>['registerRemotes']>[0][number];
23
24
  /**
24
- * 尝试加载单个远程模块 URL,包含重试逻辑
25
+ * 尝试加载单个远程模块 URL
26
+ * 注意:实际的重试机制在外层 loadRemoteMultiVersion 的 URL 遍历中实现
25
27
  */
26
- export declare function tryLoadRemote(scopeName: string, url: string, retries: number, delay: number, sharedConfig: Record<string, any>, plugins: ModuleFederationRuntimePlugin[]): Promise<LoadResult>;
28
+ export declare function tryLoadRemote(scopeName: string, url: string, _retries: number, _delay: number, sharedConfig: Record<string, any>, plugins: ModuleFederationRuntimePlugin[], extraRemotes?: RuntimeRemote[], registerOptions?: {
29
+ force?: boolean;
30
+ }): Promise<LoadResult>;
27
31
  /**
28
32
  * 获取最终的共享配置
29
33
  */
package/dist/main.cjs CHANGED
@@ -60,6 +60,7 @@ __webpack_require__.d(__webpack_exports__, {
60
60
  satisfiesVersion: ()=>satisfiesVersion,
61
61
  formatHealthStatus: ()=>formatHealthStatus,
62
62
  unloadAll: ()=>unloadAll,
63
+ createRemoteSourcePlugin: ()=>createRemoteSourcePlugin,
63
64
  setVersionCache: ()=>setVersionCache,
64
65
  isPrerelease: ()=>isPrerelease,
65
66
  checkRemoteHealth: ()=>checkRemoteHealth,
@@ -323,8 +324,20 @@ function buildCdnUrls(pkg, version) {
323
324
  }
324
325
  const mfInstanceCache = new Map();
325
326
  const mfInstanceLoadingCache = new Map();
326
- async function tryLoadRemote(scopeName, url, retries, delay, sharedConfig, plugins) {
327
- const cacheKey = `${scopeName}::${url}`;
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'}`;
328
341
  const cachedMfs = mfInstanceCache.get(cacheKey);
329
342
  if (cachedMfs) return {
330
343
  scopeName,
@@ -332,41 +345,32 @@ async function tryLoadRemote(scopeName, url, retries, delay, sharedConfig, plugi
332
345
  };
333
346
  const loadingMfs = mfInstanceLoadingCache.get(cacheKey);
334
347
  if (loadingMfs) return loadingMfs;
335
- const createProcess = (async ()=>{
336
- let lastError;
337
- for(let i = 0; i < retries; i++)try {
338
- const mf = (0, runtime_namespaceObject.createInstance)({
339
- name: 'host',
340
- remotes: [
341
- {
342
- name: scopeName,
343
- entry: url
344
- }
345
- ],
346
- shared: sharedConfig,
347
- plugins: [
348
- ...plugins,
349
- fallbackPlugin()
350
- ]
351
- });
352
- const result = {
353
- scopeName,
354
- mf
355
- };
356
- mfInstanceCache.set(cacheKey, mf);
357
- return result;
358
- } catch (e) {
359
- lastError = e;
360
- console.warn(`[MF] URL ${url} 加载失败,第 ${i + 1} 次重试...`);
361
- if (i < retries - 1) await new Promise((res)=>setTimeout(res, delay));
362
- }
363
- throw new Error(`[MF] URL ${url} 经过 ${retries} 次重试仍加载失败。`, {
364
- cause: lastError
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
+ ]
365
362
  });
366
- })();
367
- mfInstanceLoadingCache.set(cacheKey, createProcess);
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);
368
372
  try {
369
- return await createProcess;
373
+ return await loadPromise;
370
374
  } finally{
371
375
  mfInstanceLoadingCache.delete(cacheKey);
372
376
  }
@@ -488,15 +492,55 @@ function buildFinalUrls(pkg, version, localFallback) {
488
492
  if (localFallback) urls.push(localFallback);
489
493
  return urls;
490
494
  }
491
- async function loadRemoteMultiVersion(options, plugins) {
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}`);
518
+ }
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 = {}) {
492
528
  const { name, pkg, version = 'latest', retries = 3, delay = 1000, localFallback, cacheTTL = 86400000, revalidate = true, shared: customShared } = options;
529
+ const { remoteSourcePlugins = [], baseRemotes = [], registerOptions = {} } = extraOptions;
493
530
  const finalVersion = await resolveFinalVersion(pkg, version, cacheTTL, revalidate);
494
531
  const scopeName = `${name}`;
495
532
  const urls = buildFinalUrls(pkg, finalVersion, localFallback);
496
533
  const finalSharedConfig = getFinalSharedConfig(customShared);
497
- console.log(finalSharedConfig, 'finalSharedConfig');
498
534
  for (const url of urls)try {
499
- return await tryLoadRemote(scopeName, url, retries, delay, finalSharedConfig, plugins);
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);
500
544
  } catch (e) {
501
545
  console.warn(`[MF] 切换 CDN 路径:${url} 失败,尝试下一个...`, e);
502
546
  }
@@ -897,6 +941,7 @@ exports.checkVersionCompatibility = __webpack_exports__.checkVersionCompatibilit
897
941
  exports.clearPreloadCache = __webpack_exports__.clearPreloadCache;
898
942
  exports.compareVersions = __webpack_exports__.compareVersions;
899
943
  exports.createEventBus = __webpack_exports__.createEventBus;
944
+ exports.createRemoteSourcePlugin = __webpack_exports__.createRemoteSourcePlugin;
900
945
  exports.eventBus = __webpack_exports__.eventBus;
901
946
  exports.extractMajorVersion = __webpack_exports__.extractMajorVersion;
902
947
  exports.fallbackPlugin = __webpack_exports__.fallbackPlugin;
@@ -938,6 +983,7 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
938
983
  "clearPreloadCache",
939
984
  "compareVersions",
940
985
  "createEventBus",
986
+ "createRemoteSourcePlugin",
941
987
  "eventBus",
942
988
  "extractMajorVersion",
943
989
  "fallbackPlugin",
package/dist/main.js CHANGED
@@ -256,8 +256,20 @@ function buildCdnUrls(pkg, version) {
256
256
  }
257
257
  const mfInstanceCache = new Map();
258
258
  const mfInstanceLoadingCache = new Map();
259
- async function tryLoadRemote(scopeName, url, retries, delay, sharedConfig, plugins) {
260
- const cacheKey = `${scopeName}::${url}`;
259
+ function buildRemotesIdentity(remotes) {
260
+ if (0 === remotes.length) return '';
261
+ return remotes.map((remote)=>JSON.stringify({
262
+ name: remote.name,
263
+ entry: 'entry' in remote ? remote.entry : '',
264
+ version: 'version' in remote ? remote.version : '',
265
+ alias: remote.alias || '',
266
+ type: remote.type || '',
267
+ entryGlobalName: remote.entryGlobalName || ''
268
+ })).sort().join('|');
269
+ }
270
+ async function tryLoadRemote(scopeName, url, _retries, _delay, sharedConfig, plugins, extraRemotes = [], registerOptions = {}) {
271
+ const remotesIdentity = buildRemotesIdentity(extraRemotes);
272
+ const cacheKey = `${scopeName}::${url}::${remotesIdentity}::${registerOptions.force ? 'force' : 'normal'}`;
261
273
  const cachedMfs = mfInstanceCache.get(cacheKey);
262
274
  if (cachedMfs) return {
263
275
  scopeName,
@@ -265,41 +277,32 @@ async function tryLoadRemote(scopeName, url, retries, delay, sharedConfig, plugi
265
277
  };
266
278
  const loadingMfs = mfInstanceLoadingCache.get(cacheKey);
267
279
  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
280
+ const loadPromise = Promise.resolve().then(()=>{
281
+ const mf = createInstance({
282
+ name: 'host',
283
+ remotes: [
284
+ {
285
+ name: scopeName,
286
+ entry: url
287
+ }
288
+ ],
289
+ shared: sharedConfig,
290
+ plugins: [
291
+ ...plugins,
292
+ fallbackPlugin()
293
+ ]
298
294
  });
299
- })();
300
- mfInstanceLoadingCache.set(cacheKey, createProcess);
295
+ if (extraRemotes.length > 0) mf.registerRemotes(extraRemotes, registerOptions);
296
+ const result = {
297
+ scopeName,
298
+ mf
299
+ };
300
+ mfInstanceCache.set(cacheKey, mf);
301
+ return result;
302
+ });
303
+ mfInstanceLoadingCache.set(cacheKey, loadPromise);
301
304
  try {
302
- return await createProcess;
305
+ return await loadPromise;
303
306
  } finally{
304
307
  mfInstanceLoadingCache.delete(cacheKey);
305
308
  }
@@ -421,15 +424,55 @@ function buildFinalUrls(pkg, version, localFallback) {
421
424
  if (localFallback) urls.push(localFallback);
422
425
  return urls;
423
426
  }
424
- async function loadRemoteMultiVersion(options, plugins) {
427
+ function dedupeRemotes(remotes) {
428
+ const map = new Map();
429
+ for (const remote of remotes){
430
+ if (!remote?.name) continue;
431
+ const key = [
432
+ remote.name,
433
+ 'entry' in remote ? remote.entry || '' : '',
434
+ 'version' in remote ? remote.version || '' : '',
435
+ remote.alias || ''
436
+ ].join('::');
437
+ if (!map.has(key)) map.set(key, remote);
438
+ }
439
+ return Array.from(map.values());
440
+ }
441
+ async function resolveRegisteredRemotes(context, baseRemotes, remoteSourcePlugins) {
442
+ const remoteList = [
443
+ ...baseRemotes
444
+ ];
445
+ for (const plugin of remoteSourcePlugins)if (plugin.registerRemotes) try {
446
+ const pluginRemotes = await plugin.registerRemotes(context);
447
+ if (pluginRemotes?.length) remoteList.push(...pluginRemotes);
448
+ } catch (error) {
449
+ throw new Error(`[MF] remote 来源插件 ${plugin.name} 执行失败: ${error.message}`);
450
+ }
451
+ return dedupeRemotes(remoteList).filter((remote)=>!(remote.name === context.scopeName && 'entry' in remote && remote.entry === context.currentEntry));
452
+ }
453
+ function createRemoteSourcePlugin(name, remotes) {
454
+ return {
455
+ name,
456
+ registerRemotes: ()=>remotes
457
+ };
458
+ }
459
+ async function loadRemoteMultiVersion(options, plugins = [], extraOptions = {}) {
425
460
  const { name, pkg, version = 'latest', retries = 3, delay = 1000, localFallback, cacheTTL = 86400000, revalidate = true, shared: customShared } = options;
461
+ const { remoteSourcePlugins = [], baseRemotes = [], registerOptions = {} } = extraOptions;
426
462
  const finalVersion = await resolveFinalVersion(pkg, version, cacheTTL, revalidate);
427
463
  const scopeName = `${name}`;
428
464
  const urls = buildFinalUrls(pkg, finalVersion, localFallback);
429
465
  const finalSharedConfig = getFinalSharedConfig(customShared);
430
- console.log(finalSharedConfig, 'finalSharedConfig');
431
466
  for (const url of urls)try {
432
- return await tryLoadRemote(scopeName, url, retries, delay, finalSharedConfig, plugins);
467
+ const registeredRemotes = await resolveRegisteredRemotes({
468
+ options,
469
+ scopeName,
470
+ pkg,
471
+ finalVersion,
472
+ currentEntry: url,
473
+ allEntries: urls
474
+ }, baseRemotes, remoteSourcePlugins);
475
+ return await tryLoadRemote(scopeName, url, retries, delay, finalSharedConfig, plugins, registeredRemotes, registerOptions);
433
476
  } catch (e) {
434
477
  console.warn(`[MF] 切换 CDN 路径:${url} 失败,尝试下一个...`, e);
435
478
  }
@@ -821,4 +864,4 @@ const eventBus = EventBusClass.create();
821
864
  function createEventBus() {
822
865
  return EventBusClass.create();
823
866
  }
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 };
867
+ export { buildCdnUrls, buildFinalUrls, cancelPreload, checkModuleLoadable, checkRemoteHealth, checkVersionCompatibility, clearPreloadCache, compareVersions, createEventBus, createRemoteSourcePlugin, 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 };
@@ -9,7 +9,7 @@ export interface LoadRemoteOptions {
9
9
  localFallback?: string;
10
10
  cacheTTL?: number;
11
11
  revalidate?: boolean;
12
- shared?: Record<string, ModuleFederationRuntimePlugin>;
12
+ shared?: Record<string, any>;
13
13
  }
14
14
  export interface VersionCache {
15
15
  [pkg: string]: {
package/loadRemote.md CHANGED
@@ -168,7 +168,8 @@ async function loadMultipleComponents() {
168
168
  ```typescript
169
169
  function loadRemoteMultiVersion(
170
170
  options: LoadRemoteOptions,
171
- plugins: ModuleFederationRuntimePlugin[]
171
+ plugins?: ModuleFederationRuntimePlugin[],
172
+ extraOptions?: LoadRemoteExtraOptions,
172
173
  ): Promise<LoadResult>
173
174
  ```
174
175
 
@@ -192,6 +193,14 @@ function loadRemoteMultiVersion(
192
193
 
193
194
  Module Federation 运行时插件数组,默认会添加 `fallbackPlugin()`。
194
195
 
196
+ **extraOptions**: `LoadRemoteExtraOptions`
197
+
198
+ | 属性 | 类型 | 必填 | 默认值 | 描述 |
199
+ |------|------|------|--------|------|
200
+ | `baseRemotes` | `RuntimeRemote[]` | ❌ | `[]` | 直接注册的附加 remote 列表 |
201
+ | `remoteSourcePlugins` | `RemoteSourcePlugin[]` | ❌ | `[]` | 通过插件动态返回并注册 remote 列表 |
202
+ | `registerOptions` | `{ force?: boolean }` | ❌ | `{}` | 透传给 `registerRemotes` 的配置 |
203
+
195
204
  #### 返回值
196
205
 
197
206
  ```typescript
@@ -869,6 +878,38 @@ const { mf } = await loadRemoteMultiVersion(options, [
869
878
  ]);
870
879
  ```
871
880
 
881
+ #### 4. 通过 `registerRemotes` 动态注册多个来源
882
+
883
+ ```typescript
884
+ import { loadRemoteMultiVersion, createRemoteSourcePlugin } from 'remote-reload-utils';
885
+
886
+ const remoteSourcePlugin = createRemoteSourcePlugin('multi-remote-source', [
887
+ {
888
+ name: 'remote_ui_v2',
889
+ entry: 'https://cdn.example.com/remote-ui-v2/dist/remoteEntry.js',
890
+ },
891
+ {
892
+ name: 'remote_widget',
893
+ entry: 'https://cdn.example.com/remote-widget/dist/remoteEntry.js',
894
+ },
895
+ ]);
896
+
897
+ const { scopeName, mf } = await loadRemoteMultiVersion(
898
+ {
899
+ name: 'react_mf_lib',
900
+ pkg: 'test-mf-unpkg',
901
+ version: 'latest',
902
+ },
903
+ [],
904
+ {
905
+ remoteSourcePlugins: [remoteSourcePlugin],
906
+ },
907
+ );
908
+
909
+ const Button = await mf.loadRemote(`${scopeName}/Button`);
910
+ const Widget = await mf.loadRemote('remote_widget/Widget');
911
+ ```
912
+
872
913
  #### 2. 监控加载状态
873
914
 
874
915
  ```typescript
@@ -1238,7 +1279,31 @@ interface LoadRemoteOptions {
1238
1279
  localFallback?: string; // 本地兜底
1239
1280
  cacheTTL?: number; // 缓存时间
1240
1281
  revalidate?: boolean; // 灰度更新
1241
- shared?: Record<string, ModuleFederationRuntimePlugin>; // 自定义 shared 配置
1282
+ shared?: Record<string, any>; // 自定义 shared 配置
1283
+ }
1284
+
1285
+ interface LoadRemoteExtraOptions {
1286
+ remoteSourcePlugins?: RemoteSourcePlugin[];
1287
+ baseRemotes?: RuntimeRemote[];
1288
+ registerOptions?: {
1289
+ force?: boolean;
1290
+ };
1291
+ }
1292
+
1293
+ interface RemoteSourcePluginContext {
1294
+ options: LoadRemoteOptions;
1295
+ scopeName: string;
1296
+ pkg: string;
1297
+ finalVersion: string;
1298
+ currentEntry: string;
1299
+ allEntries: string[];
1300
+ }
1301
+
1302
+ interface RemoteSourcePlugin {
1303
+ name: string;
1304
+ registerRemotes?: (
1305
+ context: RemoteSourcePluginContext
1306
+ ) => RuntimeRemote[] | void | Promise<RuntimeRemote[] | void>;
1242
1307
  }
1243
1308
 
1244
1309
  interface VersionCache {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remote-reload-utils",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "type": "module",
5
5
  "description": "Utilities for remote reload in Module Federation & React Component",
6
6
  "exports": {