@module-federation/runtime-core 2.4.0 → 2.5.0

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.
Files changed (69) hide show
  1. package/dist/core.cjs +8 -1
  2. package/dist/core.cjs.map +1 -1
  3. package/dist/core.d.ts +62 -6
  4. package/dist/core.js +8 -1
  5. package/dist/core.js.map +1 -1
  6. package/dist/global.cjs +1 -1
  7. package/dist/global.js +1 -1
  8. package/dist/module/index.cjs +158 -21
  9. package/dist/module/index.cjs.map +1 -1
  10. package/dist/module/index.d.ts +5 -4
  11. package/dist/module/index.js +160 -23
  12. package/dist/module/index.js.map +1 -1
  13. package/dist/plugins/snapshot/SnapshotHandler.cjs +40 -16
  14. package/dist/plugins/snapshot/SnapshotHandler.cjs.map +1 -1
  15. package/dist/plugins/snapshot/SnapshotHandler.d.ts +5 -2
  16. package/dist/plugins/snapshot/SnapshotHandler.js +42 -18
  17. package/dist/plugins/snapshot/SnapshotHandler.js.map +1 -1
  18. package/dist/plugins/snapshot/index.cjs +6 -2
  19. package/dist/plugins/snapshot/index.cjs.map +1 -1
  20. package/dist/plugins/snapshot/index.js +6 -2
  21. package/dist/plugins/snapshot/index.js.map +1 -1
  22. package/dist/remote/index.cjs +163 -25
  23. package/dist/remote/index.cjs.map +1 -1
  24. package/dist/remote/index.d.ts +30 -4
  25. package/dist/remote/index.js +164 -26
  26. package/dist/remote/index.js.map +1 -1
  27. package/dist/shared/index.cjs +210 -95
  28. package/dist/shared/index.cjs.map +1 -1
  29. package/dist/shared/index.d.ts +22 -0
  30. package/dist/shared/index.js +211 -96
  31. package/dist/shared/index.js.map +1 -1
  32. package/dist/type/index.d.ts +2 -2
  33. package/dist/type/preload.d.ts +25 -1
  34. package/dist/types.d.ts +2 -2
  35. package/dist/utils/hooks/asyncHook.cjs +4 -1
  36. package/dist/utils/hooks/asyncHook.cjs.map +1 -1
  37. package/dist/utils/hooks/asyncHook.js +4 -1
  38. package/dist/utils/hooks/asyncHook.js.map +1 -1
  39. package/dist/utils/hooks/asyncWaterfallHooks.cjs +10 -8
  40. package/dist/utils/hooks/asyncWaterfallHooks.cjs.map +1 -1
  41. package/dist/utils/hooks/asyncWaterfallHooks.d.ts +2 -2
  42. package/dist/utils/hooks/asyncWaterfallHooks.js +10 -8
  43. package/dist/utils/hooks/asyncWaterfallHooks.js.map +1 -1
  44. package/dist/utils/hooks/pluginSystem.d.ts +1 -1
  45. package/dist/utils/hooks/syncHook.cjs +2 -1
  46. package/dist/utils/hooks/syncHook.cjs.map +1 -1
  47. package/dist/utils/hooks/syncHook.js +2 -1
  48. package/dist/utils/hooks/syncHook.js.map +1 -1
  49. package/dist/utils/hooks/syncWaterfallHook.cjs +1 -0
  50. package/dist/utils/hooks/syncWaterfallHook.cjs.map +1 -1
  51. package/dist/utils/hooks/syncWaterfallHook.d.ts +1 -1
  52. package/dist/utils/hooks/syncWaterfallHook.js +1 -0
  53. package/dist/utils/hooks/syncWaterfallHook.js.map +1 -1
  54. package/dist/utils/index.js +1 -1
  55. package/dist/utils/load.cjs +42 -10
  56. package/dist/utils/load.cjs.map +1 -1
  57. package/dist/utils/load.d.ts +2 -0
  58. package/dist/utils/load.js +42 -10
  59. package/dist/utils/load.js.map +1 -1
  60. package/dist/utils/manifest.cjs +5 -0
  61. package/dist/utils/manifest.cjs.map +1 -1
  62. package/dist/utils/manifest.js +5 -1
  63. package/dist/utils/manifest.js.map +1 -1
  64. package/dist/utils/preload.cjs +126 -63
  65. package/dist/utils/preload.cjs.map +1 -1
  66. package/dist/utils/preload.d.ts +2 -2
  67. package/dist/utils/preload.js +126 -63
  68. package/dist/utils/preload.js.map +1 -1
  69. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.cjs","names":[],"sources":["../../src/utils/manifest.ts"],"sourcesContent":["import { Remote } from '../type';\n\n// Function to match a remote with its name and expose\n// id: pkgName(@federation/app1) + expose(button) = @federation/app1/button\n// id: alias(app1) + expose(button) = app1/button\n// id: alias(app1/utils) + expose(loadash/sort) = app1/utils/loadash/sort\nexport function matchRemoteWithNameAndExpose(\n remotes: Array<Remote>,\n id: string,\n):\n | {\n pkgNameOrAlias: string;\n expose: string;\n remote: Remote;\n }\n | undefined {\n for (const remote of remotes) {\n // match pkgName\n const isNameMatched = id.startsWith(remote.name);\n let expose = id.replace(remote.name, '');\n if (isNameMatched) {\n if (expose.startsWith('/')) {\n const pkgNameOrAlias = remote.name;\n expose = `.${expose}`;\n return {\n pkgNameOrAlias,\n expose,\n remote,\n };\n } else if (expose === '') {\n return {\n pkgNameOrAlias: remote.name,\n expose: '.',\n remote,\n };\n }\n }\n\n // match alias\n const isAliasMatched = remote.alias && id.startsWith(remote.alias);\n let exposeWithAlias = remote.alias && id.replace(remote.alias, '');\n if (remote.alias && isAliasMatched) {\n if (exposeWithAlias && exposeWithAlias.startsWith('/')) {\n const pkgNameOrAlias = remote.alias;\n exposeWithAlias = `.${exposeWithAlias}`;\n return {\n pkgNameOrAlias,\n expose: exposeWithAlias,\n remote,\n };\n } else if (exposeWithAlias === '') {\n return {\n pkgNameOrAlias: remote.alias,\n expose: '.',\n remote,\n };\n }\n }\n }\n\n return;\n}\n\n// Function to match a remote with its name or alias\nexport function matchRemote(\n remotes: Array<Remote>,\n nameOrAlias: string,\n): Remote | undefined {\n for (const remote of remotes) {\n const isNameMatched = nameOrAlias === remote.name;\n if (isNameMatched) {\n return remote;\n }\n\n const isAliasMatched = remote.alias && nameOrAlias === remote.alias;\n if (isAliasMatched) {\n return remote;\n }\n }\n return;\n}\n"],"mappings":";;AAMA,SAAgB,6BACd,SACA,IAOY;AACZ,MAAK,MAAM,UAAU,SAAS;EAE5B,MAAM,gBAAgB,GAAG,WAAW,OAAO,KAAK;EAChD,IAAI,SAAS,GAAG,QAAQ,OAAO,MAAM,GAAG;AACxC,MAAI,eACF;OAAI,OAAO,WAAW,IAAI,EAAE;IAC1B,MAAM,iBAAiB,OAAO;AAC9B,aAAS,IAAI;AACb,WAAO;KACL;KACA;KACA;KACD;cACQ,WAAW,GACpB,QAAO;IACL,gBAAgB,OAAO;IACvB,QAAQ;IACR;IACD;;EAKL,MAAM,iBAAiB,OAAO,SAAS,GAAG,WAAW,OAAO,MAAM;EAClE,IAAI,kBAAkB,OAAO,SAAS,GAAG,QAAQ,OAAO,OAAO,GAAG;AAClE,MAAI,OAAO,SAAS,gBAClB;OAAI,mBAAmB,gBAAgB,WAAW,IAAI,EAAE;IACtD,MAAM,iBAAiB,OAAO;AAC9B,sBAAkB,IAAI;AACtB,WAAO;KACL;KACA,QAAQ;KACR;KACD;cACQ,oBAAoB,GAC7B,QAAO;IACL,gBAAgB,OAAO;IACvB,QAAQ;IACR;IACD;;;;AAST,SAAgB,YACd,SACA,aACoB;AACpB,MAAK,MAAM,UAAU,SAAS;AAE5B,MADsB,gBAAgB,OAAO,KAE3C,QAAO;AAIT,MADuB,OAAO,SAAS,gBAAgB,OAAO,MAE5D,QAAO"}
1
+ {"version":3,"file":"manifest.cjs","names":[],"sources":["../../src/utils/manifest.ts"],"sourcesContent":["import { Remote } from '../type';\n\nexport function composeRemoteRequestId(\n remoteName: string,\n expose?: string,\n): string {\n if (!expose || expose === '.') {\n return remoteName;\n }\n\n return `${remoteName}/${expose.replace(/^\\.\\//, '')}`;\n}\n\n// Function to match a remote with its name and expose\n// id: pkgName(@federation/app1) + expose(button) = @federation/app1/button\n// id: alias(app1) + expose(button) = app1/button\n// id: alias(app1/utils) + expose(loadash/sort) = app1/utils/loadash/sort\nexport function matchRemoteWithNameAndExpose(\n remotes: Array<Remote>,\n id: string,\n):\n | {\n pkgNameOrAlias: string;\n expose: string;\n remote: Remote;\n }\n | undefined {\n for (const remote of remotes) {\n // match pkgName\n const isNameMatched = id.startsWith(remote.name);\n let expose = id.replace(remote.name, '');\n if (isNameMatched) {\n if (expose.startsWith('/')) {\n const pkgNameOrAlias = remote.name;\n expose = `.${expose}`;\n return {\n pkgNameOrAlias,\n expose,\n remote,\n };\n } else if (expose === '') {\n return {\n pkgNameOrAlias: remote.name,\n expose: '.',\n remote,\n };\n }\n }\n\n // match alias\n const isAliasMatched = remote.alias && id.startsWith(remote.alias);\n let exposeWithAlias = remote.alias && id.replace(remote.alias, '');\n if (remote.alias && isAliasMatched) {\n if (exposeWithAlias && exposeWithAlias.startsWith('/')) {\n const pkgNameOrAlias = remote.alias;\n exposeWithAlias = `.${exposeWithAlias}`;\n return {\n pkgNameOrAlias,\n expose: exposeWithAlias,\n remote,\n };\n } else if (exposeWithAlias === '') {\n return {\n pkgNameOrAlias: remote.alias,\n expose: '.',\n remote,\n };\n }\n }\n }\n\n return;\n}\n\n// Function to match a remote with its name or alias\nexport function matchRemote(\n remotes: Array<Remote>,\n nameOrAlias: string,\n): Remote | undefined {\n for (const remote of remotes) {\n const isNameMatched = nameOrAlias === remote.name;\n if (isNameMatched) {\n return remote;\n }\n\n const isAliasMatched = remote.alias && nameOrAlias === remote.alias;\n if (isAliasMatched) {\n return remote;\n }\n }\n return;\n}\n"],"mappings":";;AAEA,SAAgB,uBACd,YACA,QACQ;AACR,KAAI,CAAC,UAAU,WAAW,IACxB,QAAO;AAGT,QAAO,GAAG,WAAW,GAAG,OAAO,QAAQ,SAAS,GAAG;;AAOrD,SAAgB,6BACd,SACA,IAOY;AACZ,MAAK,MAAM,UAAU,SAAS;EAE5B,MAAM,gBAAgB,GAAG,WAAW,OAAO,KAAK;EAChD,IAAI,SAAS,GAAG,QAAQ,OAAO,MAAM,GAAG;AACxC,MAAI,eACF;OAAI,OAAO,WAAW,IAAI,EAAE;IAC1B,MAAM,iBAAiB,OAAO;AAC9B,aAAS,IAAI;AACb,WAAO;KACL;KACA;KACA;KACD;cACQ,WAAW,GACpB,QAAO;IACL,gBAAgB,OAAO;IACvB,QAAQ;IACR;IACD;;EAKL,MAAM,iBAAiB,OAAO,SAAS,GAAG,WAAW,OAAO,MAAM;EAClE,IAAI,kBAAkB,OAAO,SAAS,GAAG,QAAQ,OAAO,OAAO,GAAG;AAClE,MAAI,OAAO,SAAS,gBAClB;OAAI,mBAAmB,gBAAgB,WAAW,IAAI,EAAE;IACtD,MAAM,iBAAiB,OAAO;AAC9B,sBAAkB,IAAI;AACtB,WAAO;KACL;KACA,QAAQ;KACR;KACD;cACQ,oBAAoB,GAC7B,QAAO;IACL,gBAAgB,OAAO;IACvB,QAAQ;IACR;IACD;;;;AAST,SAAgB,YACd,SACA,aACoB;AACpB,MAAK,MAAM,UAAU,SAAS;AAE5B,MADsB,gBAAgB,OAAO,KAE3C,QAAO;AAIT,MADuB,OAAO,SAAS,gBAAgB,OAAO,MAE5D,QAAO"}
@@ -1,4 +1,8 @@
1
1
  //#region src/utils/manifest.ts
2
+ function composeRemoteRequestId(remoteName, expose) {
3
+ if (!expose || expose === ".") return remoteName;
4
+ return `${remoteName}/${expose.replace(/^\.\//, "")}`;
5
+ }
2
6
  function matchRemoteWithNameAndExpose(remotes, id) {
3
7
  for (const remote of remotes) {
4
8
  const isNameMatched = id.startsWith(remote.name);
@@ -45,5 +49,5 @@ function matchRemote(remotes, nameOrAlias) {
45
49
  }
46
50
 
47
51
  //#endregion
48
- export { matchRemote, matchRemoteWithNameAndExpose };
52
+ export { composeRemoteRequestId, matchRemote, matchRemoteWithNameAndExpose };
49
53
  //# sourceMappingURL=manifest.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.js","names":[],"sources":["../../src/utils/manifest.ts"],"sourcesContent":["import { Remote } from '../type';\n\n// Function to match a remote with its name and expose\n// id: pkgName(@federation/app1) + expose(button) = @federation/app1/button\n// id: alias(app1) + expose(button) = app1/button\n// id: alias(app1/utils) + expose(loadash/sort) = app1/utils/loadash/sort\nexport function matchRemoteWithNameAndExpose(\n remotes: Array<Remote>,\n id: string,\n):\n | {\n pkgNameOrAlias: string;\n expose: string;\n remote: Remote;\n }\n | undefined {\n for (const remote of remotes) {\n // match pkgName\n const isNameMatched = id.startsWith(remote.name);\n let expose = id.replace(remote.name, '');\n if (isNameMatched) {\n if (expose.startsWith('/')) {\n const pkgNameOrAlias = remote.name;\n expose = `.${expose}`;\n return {\n pkgNameOrAlias,\n expose,\n remote,\n };\n } else if (expose === '') {\n return {\n pkgNameOrAlias: remote.name,\n expose: '.',\n remote,\n };\n }\n }\n\n // match alias\n const isAliasMatched = remote.alias && id.startsWith(remote.alias);\n let exposeWithAlias = remote.alias && id.replace(remote.alias, '');\n if (remote.alias && isAliasMatched) {\n if (exposeWithAlias && exposeWithAlias.startsWith('/')) {\n const pkgNameOrAlias = remote.alias;\n exposeWithAlias = `.${exposeWithAlias}`;\n return {\n pkgNameOrAlias,\n expose: exposeWithAlias,\n remote,\n };\n } else if (exposeWithAlias === '') {\n return {\n pkgNameOrAlias: remote.alias,\n expose: '.',\n remote,\n };\n }\n }\n }\n\n return;\n}\n\n// Function to match a remote with its name or alias\nexport function matchRemote(\n remotes: Array<Remote>,\n nameOrAlias: string,\n): Remote | undefined {\n for (const remote of remotes) {\n const isNameMatched = nameOrAlias === remote.name;\n if (isNameMatched) {\n return remote;\n }\n\n const isAliasMatched = remote.alias && nameOrAlias === remote.alias;\n if (isAliasMatched) {\n return remote;\n }\n }\n return;\n}\n"],"mappings":";AAMA,SAAgB,6BACd,SACA,IAOY;AACZ,MAAK,MAAM,UAAU,SAAS;EAE5B,MAAM,gBAAgB,GAAG,WAAW,OAAO,KAAK;EAChD,IAAI,SAAS,GAAG,QAAQ,OAAO,MAAM,GAAG;AACxC,MAAI,eACF;OAAI,OAAO,WAAW,IAAI,EAAE;IAC1B,MAAM,iBAAiB,OAAO;AAC9B,aAAS,IAAI;AACb,WAAO;KACL;KACA;KACA;KACD;cACQ,WAAW,GACpB,QAAO;IACL,gBAAgB,OAAO;IACvB,QAAQ;IACR;IACD;;EAKL,MAAM,iBAAiB,OAAO,SAAS,GAAG,WAAW,OAAO,MAAM;EAClE,IAAI,kBAAkB,OAAO,SAAS,GAAG,QAAQ,OAAO,OAAO,GAAG;AAClE,MAAI,OAAO,SAAS,gBAClB;OAAI,mBAAmB,gBAAgB,WAAW,IAAI,EAAE;IACtD,MAAM,iBAAiB,OAAO;AAC9B,sBAAkB,IAAI;AACtB,WAAO;KACL;KACA,QAAQ;KACR;KACD;cACQ,oBAAoB,GAC7B,QAAO;IACL,gBAAgB,OAAO;IACvB,QAAQ;IACR;IACD;;;;AAST,SAAgB,YACd,SACA,aACoB;AACpB,MAAK,MAAM,UAAU,SAAS;AAE5B,MADsB,gBAAgB,OAAO,KAE3C,QAAO;AAIT,MADuB,OAAO,SAAS,gBAAgB,OAAO,MAE5D,QAAO"}
1
+ {"version":3,"file":"manifest.js","names":[],"sources":["../../src/utils/manifest.ts"],"sourcesContent":["import { Remote } from '../type';\n\nexport function composeRemoteRequestId(\n remoteName: string,\n expose?: string,\n): string {\n if (!expose || expose === '.') {\n return remoteName;\n }\n\n return `${remoteName}/${expose.replace(/^\\.\\//, '')}`;\n}\n\n// Function to match a remote with its name and expose\n// id: pkgName(@federation/app1) + expose(button) = @federation/app1/button\n// id: alias(app1) + expose(button) = app1/button\n// id: alias(app1/utils) + expose(loadash/sort) = app1/utils/loadash/sort\nexport function matchRemoteWithNameAndExpose(\n remotes: Array<Remote>,\n id: string,\n):\n | {\n pkgNameOrAlias: string;\n expose: string;\n remote: Remote;\n }\n | undefined {\n for (const remote of remotes) {\n // match pkgName\n const isNameMatched = id.startsWith(remote.name);\n let expose = id.replace(remote.name, '');\n if (isNameMatched) {\n if (expose.startsWith('/')) {\n const pkgNameOrAlias = remote.name;\n expose = `.${expose}`;\n return {\n pkgNameOrAlias,\n expose,\n remote,\n };\n } else if (expose === '') {\n return {\n pkgNameOrAlias: remote.name,\n expose: '.',\n remote,\n };\n }\n }\n\n // match alias\n const isAliasMatched = remote.alias && id.startsWith(remote.alias);\n let exposeWithAlias = remote.alias && id.replace(remote.alias, '');\n if (remote.alias && isAliasMatched) {\n if (exposeWithAlias && exposeWithAlias.startsWith('/')) {\n const pkgNameOrAlias = remote.alias;\n exposeWithAlias = `.${exposeWithAlias}`;\n return {\n pkgNameOrAlias,\n expose: exposeWithAlias,\n remote,\n };\n } else if (exposeWithAlias === '') {\n return {\n pkgNameOrAlias: remote.alias,\n expose: '.',\n remote,\n };\n }\n }\n }\n\n return;\n}\n\n// Function to match a remote with its name or alias\nexport function matchRemote(\n remotes: Array<Remote>,\n nameOrAlias: string,\n): Remote | undefined {\n for (const remote of remotes) {\n const isNameMatched = nameOrAlias === remote.name;\n if (isNameMatched) {\n return remote;\n }\n\n const isAliasMatched = remote.alias && nameOrAlias === remote.alias;\n if (isAliasMatched) {\n return remote;\n }\n }\n return;\n}\n"],"mappings":";AAEA,SAAgB,uBACd,YACA,QACQ;AACR,KAAI,CAAC,UAAU,WAAW,IACxB,QAAO;AAGT,QAAO,GAAG,WAAW,GAAG,OAAO,QAAQ,SAAS,GAAG;;AAOrD,SAAgB,6BACd,SACA,IAOY;AACZ,MAAK,MAAM,UAAU,SAAS;EAE5B,MAAM,gBAAgB,GAAG,WAAW,OAAO,KAAK;EAChD,IAAI,SAAS,GAAG,QAAQ,OAAO,MAAM,GAAG;AACxC,MAAI,eACF;OAAI,OAAO,WAAW,IAAI,EAAE;IAC1B,MAAM,iBAAiB,OAAO;AAC9B,aAAS,IAAI;AACb,WAAO;KACL;KACA;KACA;KACD;cACQ,WAAW,GACpB,QAAO;IACL,gBAAgB,OAAO;IACvB,QAAQ;IACR;IACD;;EAKL,MAAM,iBAAiB,OAAO,SAAS,GAAG,WAAW,OAAO,MAAM;EAClE,IAAI,kBAAkB,OAAO,SAAS,GAAG,QAAQ,OAAO,OAAO,GAAG;AAClE,MAAI,OAAO,SAAS,gBAClB;OAAI,mBAAmB,gBAAgB,WAAW,IAAI,EAAE;IACtD,MAAM,iBAAiB,OAAO;AAC9B,sBAAkB,IAAI;AACtB,WAAO;KACL;KACA,QAAQ;KACR;KACD;cACQ,oBAAoB,GAC7B,QAAO;IACL,gBAAgB,OAAO;IACvB,QAAQ;IACR;IACD;;;;AAST,SAAgB,YACd,SACA,aACoB;AACpB,MAAK,MAAM,UAAU,SAAS;AAE5B,MADsB,gBAAgB,OAAO,KAE3C,QAAO;AAIT,MADuB,OAAO,SAAS,gBAAgB,OAAO,MAE5D,QAAO"}
@@ -33,22 +33,113 @@ function normalizePreloadExposes(exposes) {
33
33
  return expose;
34
34
  });
35
35
  }
36
- function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
36
+ function isTimeoutError(error) {
37
+ if (!(error instanceof Error)) return false;
38
+ return error.message.includes("timed out") || error.name.includes("Timeout");
39
+ }
40
+ function createAssetResult(context, url, status, error) {
41
+ return {
42
+ url,
43
+ status,
44
+ resourceType: context.resourceType,
45
+ initiator: context.initiator,
46
+ id: context.id,
47
+ error
48
+ };
49
+ }
50
+ async function waitForRemoteEntryPreload(host, remoteInfo, entryRemoteInfo, context) {
51
+ const cachedRemote = host.moduleCache.get(entryRemoteInfo.name);
52
+ const url = entryRemoteInfo.entry;
53
+ if (cachedRemote?.remoteEntryExports) return createAssetResult(context, url, "cached");
54
+ try {
55
+ if (!await require_load.getRemoteEntry({
56
+ origin: host,
57
+ remoteInfo: entryRemoteInfo,
58
+ remoteEntryExports: cachedRemote?.remoteEntryExports,
59
+ resourceContext: {
60
+ ...context,
61
+ url
62
+ }
63
+ })) throw new Error(`Failed to load remoteEntry "${url}".`);
64
+ return createAssetResult(context, url, "success");
65
+ } catch (error) {
66
+ return createAssetResult(context, url, isTimeoutError(error) ? "timeout" : "error", error);
67
+ }
68
+ }
69
+ function waitForLinkPreload({ host, remoteInfo, url, attrs, context, needDeleteLink }) {
70
+ return new Promise((resolve) => {
71
+ const { link, needAttach } = (0, _module_federation_sdk.createLink)({
72
+ url,
73
+ cb: () => {
74
+ resolve(createAssetResult(context, url, needAttach ? "success" : "cached"));
75
+ },
76
+ onErrorCallback: (error) => {
77
+ resolve(createAssetResult(context, url, isTimeoutError(error) ? "timeout" : "error", error));
78
+ },
79
+ attrs,
80
+ createLinkHook: (hookUrl, hookAttrs) => {
81
+ const res = host.loaderHook.lifecycle.createLink.emit({
82
+ url: hookUrl,
83
+ attrs: hookAttrs,
84
+ remoteInfo,
85
+ resourceContext: {
86
+ ...context,
87
+ url: hookUrl
88
+ }
89
+ });
90
+ if (res instanceof HTMLLinkElement) return res;
91
+ return res;
92
+ },
93
+ needDeleteLink
94
+ });
95
+ needAttach && document.head.appendChild(link);
96
+ });
97
+ }
98
+ function waitForScriptPreload({ host, remoteInfo, url, attrs, context }) {
99
+ return new Promise((resolve) => {
100
+ const { script, needAttach } = (0, _module_federation_sdk.createScript)({
101
+ url,
102
+ cb: () => {
103
+ resolve(createAssetResult(context, url, needAttach ? "success" : "cached"));
104
+ },
105
+ onErrorCallback: (error) => {
106
+ resolve(createAssetResult(context, url, isTimeoutError(error) ? "timeout" : "error", error));
107
+ },
108
+ attrs,
109
+ createScriptHook: (hookUrl, hookAttrs) => {
110
+ const res = host.loaderHook.lifecycle.createScript.emit({
111
+ url: hookUrl,
112
+ attrs: hookAttrs,
113
+ remoteInfo,
114
+ resourceContext: {
115
+ ...context,
116
+ url: hookUrl
117
+ }
118
+ });
119
+ if (res instanceof HTMLScriptElement) return res;
120
+ return res;
121
+ },
122
+ needDeleteScript: true
123
+ });
124
+ needAttach && document.head.appendChild(script);
125
+ });
126
+ }
127
+ function createResourceContext(baseContext, resourceType) {
128
+ return {
129
+ ...baseContext,
130
+ resourceType
131
+ };
132
+ }
133
+ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true, baseContext = {
134
+ initiator: "preloadRemote",
135
+ id: remoteInfo.name
136
+ }) {
37
137
  const { cssAssets, jsAssetsWithoutEntry, entryAssets } = assets;
138
+ const results = [];
38
139
  if (host.options.inBrowser) {
39
140
  entryAssets.forEach((asset) => {
40
- const { moduleInfo } = asset;
41
- const module = host.moduleCache.get(remoteInfo.name);
42
- if (module) require_load.getRemoteEntry({
43
- origin: host,
44
- remoteInfo: moduleInfo,
45
- remoteEntryExports: module.remoteEntryExports
46
- });
47
- else require_load.getRemoteEntry({
48
- origin: host,
49
- remoteInfo: moduleInfo,
50
- remoteEntryExports: void 0
51
- });
141
+ const { moduleInfo: entryRemoteInfo } = asset;
142
+ results.push(waitForRemoteEntryPreload(host, remoteInfo, entryRemoteInfo, createResourceContext(baseContext, "remoteEntry")));
52
143
  });
53
144
  if (useLinkPreload) {
54
145
  const defaultAttrs = {
@@ -56,20 +147,13 @@ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
56
147
  as: "style"
57
148
  };
58
149
  cssAssets.forEach((cssUrl) => {
59
- const { link: cssEl, needAttach } = (0, _module_federation_sdk.createLink)({
150
+ results.push(waitForLinkPreload({
151
+ host,
152
+ remoteInfo,
60
153
  url: cssUrl,
61
- cb: () => {},
62
154
  attrs: defaultAttrs,
63
- createLinkHook: (url, attrs) => {
64
- const res = host.loaderHook.lifecycle.createLink.emit({
65
- url,
66
- attrs,
67
- remoteInfo
68
- });
69
- if (res instanceof HTMLLinkElement) return res;
70
- }
71
- });
72
- needAttach && document.head.appendChild(cssEl);
155
+ context: createResourceContext(baseContext, "css")
156
+ }));
73
157
  });
74
158
  } else {
75
159
  const defaultAttrs = {
@@ -77,21 +161,14 @@ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
77
161
  type: "text/css"
78
162
  };
79
163
  cssAssets.forEach((cssUrl) => {
80
- const { link: cssEl, needAttach } = (0, _module_federation_sdk.createLink)({
164
+ results.push(waitForLinkPreload({
165
+ host,
166
+ remoteInfo,
81
167
  url: cssUrl,
82
- cb: () => {},
83
168
  attrs: defaultAttrs,
84
- createLinkHook: (url, attrs) => {
85
- const res = host.loaderHook.lifecycle.createLink.emit({
86
- url,
87
- attrs,
88
- remoteInfo
89
- });
90
- if (res instanceof HTMLLinkElement) return res;
91
- },
92
- needDeleteLink: false
93
- });
94
- needAttach && document.head.appendChild(cssEl);
169
+ needDeleteLink: false,
170
+ context: createResourceContext(baseContext, "css")
171
+ }));
95
172
  });
96
173
  }
97
174
  if (useLinkPreload) {
@@ -100,20 +177,13 @@ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
100
177
  as: "script"
101
178
  };
102
179
  jsAssetsWithoutEntry.forEach((jsUrl) => {
103
- const { link: linkEl, needAttach } = (0, _module_federation_sdk.createLink)({
180
+ results.push(waitForLinkPreload({
181
+ host,
182
+ remoteInfo,
104
183
  url: jsUrl,
105
- cb: () => {},
106
184
  attrs: defaultAttrs,
107
- createLinkHook: (url, attrs) => {
108
- const res = host.loaderHook.lifecycle.createLink.emit({
109
- url,
110
- attrs,
111
- remoteInfo
112
- });
113
- if (res instanceof HTMLLinkElement) return res;
114
- }
115
- });
116
- needAttach && document.head.appendChild(linkEl);
185
+ context: createResourceContext(baseContext, "js")
186
+ }));
117
187
  });
118
188
  } else {
119
189
  const defaultAttrs = {
@@ -121,24 +191,17 @@ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
121
191
  type: remoteInfo?.type === "module" ? "module" : "text/javascript"
122
192
  };
123
193
  jsAssetsWithoutEntry.forEach((jsUrl) => {
124
- const { script: scriptEl, needAttach } = (0, _module_federation_sdk.createScript)({
194
+ results.push(waitForScriptPreload({
195
+ host,
196
+ remoteInfo,
125
197
  url: jsUrl,
126
- cb: () => {},
127
198
  attrs: defaultAttrs,
128
- createScriptHook: (url, attrs) => {
129
- const res = host.loaderHook.lifecycle.createScript.emit({
130
- url,
131
- attrs,
132
- remoteInfo
133
- });
134
- if (res instanceof HTMLScriptElement) return res;
135
- },
136
- needDeleteScript: true
137
- });
138
- needAttach && document.head.appendChild(scriptEl);
199
+ context: createResourceContext(baseContext, "js")
200
+ }));
139
201
  });
140
202
  }
141
203
  }
204
+ return Promise.all(results);
142
205
  }
143
206
 
144
207
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"preload.cjs","names":["matchRemote"],"sources":["../../src/utils/preload.ts"],"sourcesContent":["import { createLink, createScript, safeToString } from '@module-federation/sdk';\nimport {\n PreloadAssets,\n PreloadConfig,\n PreloadOptions,\n PreloadRemoteArgs,\n Remote,\n RemoteInfo,\n depsPreloadArg,\n} from '../type';\nimport { matchRemote } from './manifest';\nimport { assert } from './logger';\nimport { ModuleFederation } from '../core';\nimport { getRemoteEntry } from './load';\n\nexport function defaultPreloadArgs(\n preloadConfig: PreloadRemoteArgs | depsPreloadArg,\n): PreloadConfig {\n return {\n resourceCategory: 'sync',\n share: true,\n depsRemote: true,\n ...preloadConfig,\n } as PreloadConfig;\n}\n\nexport function formatPreloadArgs(\n remotes: Array<Remote>,\n preloadArgs: Array<PreloadRemoteArgs>,\n): PreloadOptions {\n return preloadArgs.map((args) => {\n const remoteInfo = matchRemote(remotes, args.nameOrAlias);\n assert(\n remoteInfo,\n `Unable to preload ${args.nameOrAlias} as it is not included in ${\n !remoteInfo &&\n safeToString({\n remoteInfo,\n remotes,\n })\n }`,\n );\n return {\n remote: remoteInfo,\n preloadConfig: defaultPreloadArgs(args),\n };\n });\n}\n\nexport function normalizePreloadExposes(exposes?: string[]): string[] {\n if (!exposes) {\n return [];\n }\n\n return exposes.map((expose) => {\n if (expose === '.') {\n return expose;\n }\n if (expose.startsWith('./')) {\n return expose.replace('./', '');\n }\n return expose;\n });\n}\n\nexport function preloadAssets(\n remoteInfo: RemoteInfo,\n host: ModuleFederation,\n assets: PreloadAssets,\n // It is used to distinguish preload from load remote parallel loading\n useLinkPreload = true,\n): void {\n const { cssAssets, jsAssetsWithoutEntry, entryAssets } = assets;\n\n if (host.options.inBrowser) {\n entryAssets.forEach((asset) => {\n const { moduleInfo } = asset;\n const module = host.moduleCache.get(remoteInfo.name);\n if (module) {\n getRemoteEntry({\n origin: host,\n remoteInfo: moduleInfo,\n remoteEntryExports: module.remoteEntryExports,\n });\n } else {\n getRemoteEntry({\n origin: host,\n remoteInfo: moduleInfo,\n remoteEntryExports: undefined,\n });\n }\n });\n\n if (useLinkPreload) {\n const defaultAttrs = {\n rel: 'preload',\n as: 'style',\n };\n cssAssets.forEach((cssUrl) => {\n const { link: cssEl, needAttach } = createLink({\n url: cssUrl,\n cb: () => {\n // noop\n },\n attrs: defaultAttrs,\n createLinkHook: (url, attrs) => {\n const res = host.loaderHook.lifecycle.createLink.emit({\n url,\n attrs,\n remoteInfo,\n });\n if (res instanceof HTMLLinkElement) {\n return res;\n }\n return;\n },\n });\n\n needAttach && document.head.appendChild(cssEl);\n });\n } else {\n const defaultAttrs = {\n rel: 'stylesheet',\n type: 'text/css',\n };\n cssAssets.forEach((cssUrl) => {\n const { link: cssEl, needAttach } = createLink({\n url: cssUrl,\n cb: () => {\n // noop\n },\n attrs: defaultAttrs,\n createLinkHook: (url, attrs) => {\n const res = host.loaderHook.lifecycle.createLink.emit({\n url,\n attrs,\n remoteInfo,\n });\n if (res instanceof HTMLLinkElement) {\n return res;\n }\n return;\n },\n needDeleteLink: false,\n });\n\n needAttach && document.head.appendChild(cssEl);\n });\n }\n\n if (useLinkPreload) {\n const defaultAttrs = {\n rel: 'preload',\n as: 'script',\n };\n jsAssetsWithoutEntry.forEach((jsUrl) => {\n const { link: linkEl, needAttach } = createLink({\n url: jsUrl,\n cb: () => {\n // noop\n },\n attrs: defaultAttrs,\n createLinkHook: (url: string, attrs) => {\n const res = host.loaderHook.lifecycle.createLink.emit({\n url,\n attrs,\n remoteInfo,\n });\n if (res instanceof HTMLLinkElement) {\n return res;\n }\n return;\n },\n });\n needAttach && document.head.appendChild(linkEl);\n });\n } else {\n const defaultAttrs = {\n fetchpriority: 'high',\n type: remoteInfo?.type === 'module' ? 'module' : 'text/javascript',\n };\n jsAssetsWithoutEntry.forEach((jsUrl) => {\n const { script: scriptEl, needAttach } = createScript({\n url: jsUrl,\n cb: () => {\n // noop\n },\n attrs: defaultAttrs,\n createScriptHook: (url: string, attrs: any) => {\n const res = host.loaderHook.lifecycle.createScript.emit({\n url,\n attrs,\n remoteInfo,\n });\n if (res instanceof HTMLScriptElement) {\n return res;\n }\n return;\n },\n needDeleteScript: true,\n });\n needAttach && document.head.appendChild(scriptEl);\n });\n }\n }\n}\n"],"mappings":";;;;;;AAeA,SAAgB,mBACd,eACe;AACf,QAAO;EACL,kBAAkB;EAClB,OAAO;EACP,YAAY;EACZ,GAAG;EACJ;;AAGH,SAAgB,kBACd,SACA,aACgB;AAChB,QAAO,YAAY,KAAK,SAAS;EAC/B,MAAM,aAAaA,6BAAY,SAAS,KAAK,YAAY;AACzD,wBACE,YACA,qBAAqB,KAAK,YAAY,4BACpC,CAAC,uDACY;GACX;GACA;GACD,CAAC,GAEL;AACD,SAAO;GACL,QAAQ;GACR,eAAe,mBAAmB,KAAK;GACxC;GACD;;AAGJ,SAAgB,wBAAwB,SAA8B;AACpE,KAAI,CAAC,QACH,QAAO,EAAE;AAGX,QAAO,QAAQ,KAAK,WAAW;AAC7B,MAAI,WAAW,IACb,QAAO;AAET,MAAI,OAAO,WAAW,KAAK,CACzB,QAAO,OAAO,QAAQ,MAAM,GAAG;AAEjC,SAAO;GACP;;AAGJ,SAAgB,cACd,YACA,MACA,QAEA,iBAAiB,MACX;CACN,MAAM,EAAE,WAAW,sBAAsB,gBAAgB;AAEzD,KAAI,KAAK,QAAQ,WAAW;AAC1B,cAAY,SAAS,UAAU;GAC7B,MAAM,EAAE,eAAe;GACvB,MAAM,SAAS,KAAK,YAAY,IAAI,WAAW,KAAK;AACpD,OAAI,OACF,6BAAe;IACb,QAAQ;IACR,YAAY;IACZ,oBAAoB,OAAO;IAC5B,CAAC;OAEF,6BAAe;IACb,QAAQ;IACR,YAAY;IACZ,oBAAoB;IACrB,CAAC;IAEJ;AAEF,MAAI,gBAAgB;GAClB,MAAM,eAAe;IACnB,KAAK;IACL,IAAI;IACL;AACD,aAAU,SAAS,WAAW;IAC5B,MAAM,EAAE,MAAM,OAAO,sDAA0B;KAC7C,KAAK;KACL,UAAU;KAGV,OAAO;KACP,iBAAiB,KAAK,UAAU;MAC9B,MAAM,MAAM,KAAK,WAAW,UAAU,WAAW,KAAK;OACpD;OACA;OACA;OACD,CAAC;AACF,UAAI,eAAe,gBACjB,QAAO;;KAIZ,CAAC;AAEF,kBAAc,SAAS,KAAK,YAAY,MAAM;KAC9C;SACG;GACL,MAAM,eAAe;IACnB,KAAK;IACL,MAAM;IACP;AACD,aAAU,SAAS,WAAW;IAC5B,MAAM,EAAE,MAAM,OAAO,sDAA0B;KAC7C,KAAK;KACL,UAAU;KAGV,OAAO;KACP,iBAAiB,KAAK,UAAU;MAC9B,MAAM,MAAM,KAAK,WAAW,UAAU,WAAW,KAAK;OACpD;OACA;OACA;OACD,CAAC;AACF,UAAI,eAAe,gBACjB,QAAO;;KAIX,gBAAgB;KACjB,CAAC;AAEF,kBAAc,SAAS,KAAK,YAAY,MAAM;KAC9C;;AAGJ,MAAI,gBAAgB;GAClB,MAAM,eAAe;IACnB,KAAK;IACL,IAAI;IACL;AACD,wBAAqB,SAAS,UAAU;IACtC,MAAM,EAAE,MAAM,QAAQ,sDAA0B;KAC9C,KAAK;KACL,UAAU;KAGV,OAAO;KACP,iBAAiB,KAAa,UAAU;MACtC,MAAM,MAAM,KAAK,WAAW,UAAU,WAAW,KAAK;OACpD;OACA;OACA;OACD,CAAC;AACF,UAAI,eAAe,gBACjB,QAAO;;KAIZ,CAAC;AACF,kBAAc,SAAS,KAAK,YAAY,OAAO;KAC/C;SACG;GACL,MAAM,eAAe;IACnB,eAAe;IACf,MAAM,YAAY,SAAS,WAAW,WAAW;IAClD;AACD,wBAAqB,SAAS,UAAU;IACtC,MAAM,EAAE,QAAQ,UAAU,wDAA4B;KACpD,KAAK;KACL,UAAU;KAGV,OAAO;KACP,mBAAmB,KAAa,UAAe;MAC7C,MAAM,MAAM,KAAK,WAAW,UAAU,aAAa,KAAK;OACtD;OACA;OACA;OACD,CAAC;AACF,UAAI,eAAe,kBACjB,QAAO;;KAIX,kBAAkB;KACnB,CAAC;AACF,kBAAc,SAAS,KAAK,YAAY,SAAS;KACjD"}
1
+ {"version":3,"file":"preload.cjs","names":["matchRemote","getRemoteEntry"],"sources":["../../src/utils/preload.ts"],"sourcesContent":["import { createLink, createScript, safeToString } from '@module-federation/sdk';\nimport {\n PreloadAssets,\n PreloadAssetResult,\n PreloadConfig,\n PreloadOptions,\n PreloadRemoteArgs,\n Remote,\n RemoteInfo,\n ResourceLoadContext,\n ResourceLoadType,\n depsPreloadArg,\n} from '../type';\nimport { matchRemote } from './manifest';\nimport { assert } from './logger';\nimport { ModuleFederation } from '../core';\nimport { getRemoteEntry } from './load';\n\nexport function defaultPreloadArgs(\n preloadConfig: PreloadRemoteArgs | depsPreloadArg,\n): PreloadConfig {\n return {\n resourceCategory: 'sync',\n share: true,\n depsRemote: true,\n ...preloadConfig,\n } as PreloadConfig;\n}\n\nexport function formatPreloadArgs(\n remotes: Array<Remote>,\n preloadArgs: Array<PreloadRemoteArgs>,\n): PreloadOptions {\n return preloadArgs.map((args) => {\n const remoteInfo = matchRemote(remotes, args.nameOrAlias);\n assert(\n remoteInfo,\n `Unable to preload ${args.nameOrAlias} as it is not included in ${\n !remoteInfo &&\n safeToString({\n remoteInfo,\n remotes,\n })\n }`,\n );\n return {\n remote: remoteInfo,\n preloadConfig: defaultPreloadArgs(args),\n };\n });\n}\n\nexport function normalizePreloadExposes(exposes?: string[]): string[] {\n if (!exposes) {\n return [];\n }\n\n return exposes.map((expose) => {\n if (expose === '.') {\n return expose;\n }\n if (expose.startsWith('./')) {\n return expose.replace('./', '');\n }\n return expose;\n });\n}\n\nfunction isTimeoutError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n return error.message.includes('timed out') || error.name.includes('Timeout');\n}\n\nfunction createAssetResult(\n context: ResourceLoadContext,\n url: string,\n status: PreloadAssetResult['status'],\n error?: unknown,\n): PreloadAssetResult {\n return {\n url,\n status,\n resourceType: context.resourceType,\n initiator: context.initiator,\n id: context.id,\n error,\n };\n}\n\nasync function waitForRemoteEntryPreload(\n host: ModuleFederation,\n remoteInfo: RemoteInfo,\n entryRemoteInfo: RemoteInfo,\n context: ResourceLoadContext,\n): Promise<PreloadAssetResult> {\n const cachedRemote = host.moduleCache.get(entryRemoteInfo.name);\n const url = entryRemoteInfo.entry;\n if (cachedRemote?.remoteEntryExports) {\n return createAssetResult(context, url, 'cached');\n }\n\n try {\n const remoteEntryExports = await getRemoteEntry({\n origin: host,\n remoteInfo: entryRemoteInfo,\n remoteEntryExports: cachedRemote?.remoteEntryExports,\n resourceContext: {\n ...context,\n url,\n },\n });\n if (!remoteEntryExports) {\n throw new Error(`Failed to load remoteEntry \"${url}\".`);\n }\n return createAssetResult(context, url, 'success');\n } catch (error) {\n return createAssetResult(\n context,\n url,\n isTimeoutError(error) ? 'timeout' : 'error',\n error,\n );\n }\n}\n\nfunction waitForLinkPreload({\n host,\n remoteInfo,\n url,\n attrs,\n context,\n needDeleteLink,\n}: {\n host: ModuleFederation;\n remoteInfo: RemoteInfo;\n url: string;\n attrs: Record<string, string>;\n context: ResourceLoadContext;\n needDeleteLink?: boolean;\n}): Promise<PreloadAssetResult> {\n return new Promise((resolve) => {\n const { link, needAttach } = createLink({\n url,\n cb: () => {\n resolve(\n createAssetResult(context, url, needAttach ? 'success' : 'cached'),\n );\n },\n onErrorCallback: (error) => {\n resolve(\n createAssetResult(\n context,\n url,\n isTimeoutError(error) ? 'timeout' : 'error',\n error,\n ),\n );\n },\n attrs,\n createLinkHook: (hookUrl, hookAttrs) => {\n const res = host.loaderHook.lifecycle.createLink.emit({\n url: hookUrl,\n attrs: hookAttrs,\n remoteInfo,\n resourceContext: {\n ...context,\n url: hookUrl,\n },\n });\n if (res instanceof HTMLLinkElement) {\n return res;\n }\n return res;\n },\n needDeleteLink,\n });\n\n needAttach && document.head.appendChild(link);\n });\n}\n\nfunction waitForScriptPreload({\n host,\n remoteInfo,\n url,\n attrs,\n context,\n}: {\n host: ModuleFederation;\n remoteInfo: RemoteInfo;\n url: string;\n attrs: Record<string, string>;\n context: ResourceLoadContext;\n}): Promise<PreloadAssetResult> {\n return new Promise((resolve) => {\n const { script, needAttach } = createScript({\n url,\n cb: () => {\n resolve(\n createAssetResult(context, url, needAttach ? 'success' : 'cached'),\n );\n },\n onErrorCallback: (error) => {\n resolve(\n createAssetResult(\n context,\n url,\n isTimeoutError(error) ? 'timeout' : 'error',\n error,\n ),\n );\n },\n attrs,\n createScriptHook: (hookUrl: string, hookAttrs: any) => {\n const res = host.loaderHook.lifecycle.createScript.emit({\n url: hookUrl,\n attrs: hookAttrs,\n remoteInfo,\n resourceContext: {\n ...context,\n url: hookUrl,\n },\n });\n if (res instanceof HTMLScriptElement) {\n return res;\n }\n return res;\n },\n needDeleteScript: true,\n });\n\n needAttach && document.head.appendChild(script);\n });\n}\n\nfunction createResourceContext(\n baseContext: Omit<ResourceLoadContext, 'resourceType'>,\n resourceType: ResourceLoadType,\n): ResourceLoadContext {\n return {\n ...baseContext,\n resourceType,\n };\n}\n\nexport function preloadAssets(\n remoteInfo: RemoteInfo,\n host: ModuleFederation,\n assets: PreloadAssets,\n // It is used to distinguish preload from load remote parallel loading\n useLinkPreload = true,\n baseContext: Omit<ResourceLoadContext, 'resourceType'> = {\n initiator: 'preloadRemote',\n id: remoteInfo.name,\n },\n): Promise<PreloadAssetResult[]> {\n const { cssAssets, jsAssetsWithoutEntry, entryAssets } = assets;\n const results: Array<Promise<PreloadAssetResult>> = [];\n\n if (host.options.inBrowser) {\n entryAssets.forEach((asset) => {\n const { moduleInfo: entryRemoteInfo } = asset;\n results.push(\n waitForRemoteEntryPreload(\n host,\n remoteInfo,\n entryRemoteInfo,\n createResourceContext(baseContext, 'remoteEntry'),\n ),\n );\n });\n\n if (useLinkPreload) {\n const defaultAttrs = {\n rel: 'preload',\n as: 'style',\n };\n cssAssets.forEach((cssUrl) => {\n results.push(\n waitForLinkPreload({\n host,\n remoteInfo,\n url: cssUrl,\n attrs: defaultAttrs,\n context: createResourceContext(baseContext, 'css'),\n }),\n );\n });\n } else {\n const defaultAttrs = {\n rel: 'stylesheet',\n type: 'text/css',\n };\n cssAssets.forEach((cssUrl) => {\n results.push(\n waitForLinkPreload({\n host,\n remoteInfo,\n url: cssUrl,\n attrs: defaultAttrs,\n needDeleteLink: false,\n context: createResourceContext(baseContext, 'css'),\n }),\n );\n });\n }\n\n if (useLinkPreload) {\n const defaultAttrs = {\n rel: 'preload',\n as: 'script',\n };\n jsAssetsWithoutEntry.forEach((jsUrl) => {\n results.push(\n waitForLinkPreload({\n host,\n remoteInfo,\n url: jsUrl,\n attrs: defaultAttrs,\n context: createResourceContext(baseContext, 'js'),\n }),\n );\n });\n } else {\n const defaultAttrs = {\n fetchpriority: 'high',\n type: remoteInfo?.type === 'module' ? 'module' : 'text/javascript',\n };\n jsAssetsWithoutEntry.forEach((jsUrl) => {\n results.push(\n waitForScriptPreload({\n host,\n remoteInfo,\n url: jsUrl,\n attrs: defaultAttrs,\n context: createResourceContext(baseContext, 'js'),\n }),\n );\n });\n }\n }\n\n return Promise.all(results);\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { ModuleFederation } from "../core.js";
2
2
  import { RemoteInfo } from "../type/config.js";
3
- import { PreloadAssets } from "../type/preload.js";
3
+ import { PreloadAssetResult, PreloadAssets, ResourceLoadContext } from "../type/preload.js";
4
4
  //#region src/utils/preload.d.ts
5
- declare function preloadAssets(remoteInfo: RemoteInfo, host: ModuleFederation, assets: PreloadAssets, useLinkPreload?: boolean): void;
5
+ declare function preloadAssets(remoteInfo: RemoteInfo, host: ModuleFederation, assets: PreloadAssets, useLinkPreload?: boolean, baseContext?: Omit<ResourceLoadContext, 'resourceType'>): Promise<PreloadAssetResult[]>;
6
6
  //#endregion
7
7
  export { preloadAssets };
8
8
  //# sourceMappingURL=preload.d.ts.map
@@ -33,22 +33,113 @@ function normalizePreloadExposes(exposes) {
33
33
  return expose;
34
34
  });
35
35
  }
36
- function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
36
+ function isTimeoutError(error) {
37
+ if (!(error instanceof Error)) return false;
38
+ return error.message.includes("timed out") || error.name.includes("Timeout");
39
+ }
40
+ function createAssetResult(context, url, status, error) {
41
+ return {
42
+ url,
43
+ status,
44
+ resourceType: context.resourceType,
45
+ initiator: context.initiator,
46
+ id: context.id,
47
+ error
48
+ };
49
+ }
50
+ async function waitForRemoteEntryPreload(host, remoteInfo, entryRemoteInfo, context) {
51
+ const cachedRemote = host.moduleCache.get(entryRemoteInfo.name);
52
+ const url = entryRemoteInfo.entry;
53
+ if (cachedRemote?.remoteEntryExports) return createAssetResult(context, url, "cached");
54
+ try {
55
+ if (!await getRemoteEntry({
56
+ origin: host,
57
+ remoteInfo: entryRemoteInfo,
58
+ remoteEntryExports: cachedRemote?.remoteEntryExports,
59
+ resourceContext: {
60
+ ...context,
61
+ url
62
+ }
63
+ })) throw new Error(`Failed to load remoteEntry "${url}".`);
64
+ return createAssetResult(context, url, "success");
65
+ } catch (error) {
66
+ return createAssetResult(context, url, isTimeoutError(error) ? "timeout" : "error", error);
67
+ }
68
+ }
69
+ function waitForLinkPreload({ host, remoteInfo, url, attrs, context, needDeleteLink }) {
70
+ return new Promise((resolve) => {
71
+ const { link, needAttach } = createLink({
72
+ url,
73
+ cb: () => {
74
+ resolve(createAssetResult(context, url, needAttach ? "success" : "cached"));
75
+ },
76
+ onErrorCallback: (error) => {
77
+ resolve(createAssetResult(context, url, isTimeoutError(error) ? "timeout" : "error", error));
78
+ },
79
+ attrs,
80
+ createLinkHook: (hookUrl, hookAttrs) => {
81
+ const res = host.loaderHook.lifecycle.createLink.emit({
82
+ url: hookUrl,
83
+ attrs: hookAttrs,
84
+ remoteInfo,
85
+ resourceContext: {
86
+ ...context,
87
+ url: hookUrl
88
+ }
89
+ });
90
+ if (res instanceof HTMLLinkElement) return res;
91
+ return res;
92
+ },
93
+ needDeleteLink
94
+ });
95
+ needAttach && document.head.appendChild(link);
96
+ });
97
+ }
98
+ function waitForScriptPreload({ host, remoteInfo, url, attrs, context }) {
99
+ return new Promise((resolve) => {
100
+ const { script, needAttach } = createScript({
101
+ url,
102
+ cb: () => {
103
+ resolve(createAssetResult(context, url, needAttach ? "success" : "cached"));
104
+ },
105
+ onErrorCallback: (error) => {
106
+ resolve(createAssetResult(context, url, isTimeoutError(error) ? "timeout" : "error", error));
107
+ },
108
+ attrs,
109
+ createScriptHook: (hookUrl, hookAttrs) => {
110
+ const res = host.loaderHook.lifecycle.createScript.emit({
111
+ url: hookUrl,
112
+ attrs: hookAttrs,
113
+ remoteInfo,
114
+ resourceContext: {
115
+ ...context,
116
+ url: hookUrl
117
+ }
118
+ });
119
+ if (res instanceof HTMLScriptElement) return res;
120
+ return res;
121
+ },
122
+ needDeleteScript: true
123
+ });
124
+ needAttach && document.head.appendChild(script);
125
+ });
126
+ }
127
+ function createResourceContext(baseContext, resourceType) {
128
+ return {
129
+ ...baseContext,
130
+ resourceType
131
+ };
132
+ }
133
+ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true, baseContext = {
134
+ initiator: "preloadRemote",
135
+ id: remoteInfo.name
136
+ }) {
37
137
  const { cssAssets, jsAssetsWithoutEntry, entryAssets } = assets;
138
+ const results = [];
38
139
  if (host.options.inBrowser) {
39
140
  entryAssets.forEach((asset) => {
40
- const { moduleInfo } = asset;
41
- const module = host.moduleCache.get(remoteInfo.name);
42
- if (module) getRemoteEntry({
43
- origin: host,
44
- remoteInfo: moduleInfo,
45
- remoteEntryExports: module.remoteEntryExports
46
- });
47
- else getRemoteEntry({
48
- origin: host,
49
- remoteInfo: moduleInfo,
50
- remoteEntryExports: void 0
51
- });
141
+ const { moduleInfo: entryRemoteInfo } = asset;
142
+ results.push(waitForRemoteEntryPreload(host, remoteInfo, entryRemoteInfo, createResourceContext(baseContext, "remoteEntry")));
52
143
  });
53
144
  if (useLinkPreload) {
54
145
  const defaultAttrs = {
@@ -56,20 +147,13 @@ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
56
147
  as: "style"
57
148
  };
58
149
  cssAssets.forEach((cssUrl) => {
59
- const { link: cssEl, needAttach } = createLink({
150
+ results.push(waitForLinkPreload({
151
+ host,
152
+ remoteInfo,
60
153
  url: cssUrl,
61
- cb: () => {},
62
154
  attrs: defaultAttrs,
63
- createLinkHook: (url, attrs) => {
64
- const res = host.loaderHook.lifecycle.createLink.emit({
65
- url,
66
- attrs,
67
- remoteInfo
68
- });
69
- if (res instanceof HTMLLinkElement) return res;
70
- }
71
- });
72
- needAttach && document.head.appendChild(cssEl);
155
+ context: createResourceContext(baseContext, "css")
156
+ }));
73
157
  });
74
158
  } else {
75
159
  const defaultAttrs = {
@@ -77,21 +161,14 @@ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
77
161
  type: "text/css"
78
162
  };
79
163
  cssAssets.forEach((cssUrl) => {
80
- const { link: cssEl, needAttach } = createLink({
164
+ results.push(waitForLinkPreload({
165
+ host,
166
+ remoteInfo,
81
167
  url: cssUrl,
82
- cb: () => {},
83
168
  attrs: defaultAttrs,
84
- createLinkHook: (url, attrs) => {
85
- const res = host.loaderHook.lifecycle.createLink.emit({
86
- url,
87
- attrs,
88
- remoteInfo
89
- });
90
- if (res instanceof HTMLLinkElement) return res;
91
- },
92
- needDeleteLink: false
93
- });
94
- needAttach && document.head.appendChild(cssEl);
169
+ needDeleteLink: false,
170
+ context: createResourceContext(baseContext, "css")
171
+ }));
95
172
  });
96
173
  }
97
174
  if (useLinkPreload) {
@@ -100,20 +177,13 @@ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
100
177
  as: "script"
101
178
  };
102
179
  jsAssetsWithoutEntry.forEach((jsUrl) => {
103
- const { link: linkEl, needAttach } = createLink({
180
+ results.push(waitForLinkPreload({
181
+ host,
182
+ remoteInfo,
104
183
  url: jsUrl,
105
- cb: () => {},
106
184
  attrs: defaultAttrs,
107
- createLinkHook: (url, attrs) => {
108
- const res = host.loaderHook.lifecycle.createLink.emit({
109
- url,
110
- attrs,
111
- remoteInfo
112
- });
113
- if (res instanceof HTMLLinkElement) return res;
114
- }
115
- });
116
- needAttach && document.head.appendChild(linkEl);
185
+ context: createResourceContext(baseContext, "js")
186
+ }));
117
187
  });
118
188
  } else {
119
189
  const defaultAttrs = {
@@ -121,24 +191,17 @@ function preloadAssets(remoteInfo, host, assets, useLinkPreload = true) {
121
191
  type: remoteInfo?.type === "module" ? "module" : "text/javascript"
122
192
  };
123
193
  jsAssetsWithoutEntry.forEach((jsUrl) => {
124
- const { script: scriptEl, needAttach } = createScript({
194
+ results.push(waitForScriptPreload({
195
+ host,
196
+ remoteInfo,
125
197
  url: jsUrl,
126
- cb: () => {},
127
198
  attrs: defaultAttrs,
128
- createScriptHook: (url, attrs) => {
129
- const res = host.loaderHook.lifecycle.createScript.emit({
130
- url,
131
- attrs,
132
- remoteInfo
133
- });
134
- if (res instanceof HTMLScriptElement) return res;
135
- },
136
- needDeleteScript: true
137
- });
138
- needAttach && document.head.appendChild(scriptEl);
199
+ context: createResourceContext(baseContext, "js")
200
+ }));
139
201
  });
140
202
  }
141
203
  }
204
+ return Promise.all(results);
142
205
  }
143
206
 
144
207
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"preload.js","names":[],"sources":["../../src/utils/preload.ts"],"sourcesContent":["import { createLink, createScript, safeToString } from '@module-federation/sdk';\nimport {\n PreloadAssets,\n PreloadConfig,\n PreloadOptions,\n PreloadRemoteArgs,\n Remote,\n RemoteInfo,\n depsPreloadArg,\n} from '../type';\nimport { matchRemote } from './manifest';\nimport { assert } from './logger';\nimport { ModuleFederation } from '../core';\nimport { getRemoteEntry } from './load';\n\nexport function defaultPreloadArgs(\n preloadConfig: PreloadRemoteArgs | depsPreloadArg,\n): PreloadConfig {\n return {\n resourceCategory: 'sync',\n share: true,\n depsRemote: true,\n ...preloadConfig,\n } as PreloadConfig;\n}\n\nexport function formatPreloadArgs(\n remotes: Array<Remote>,\n preloadArgs: Array<PreloadRemoteArgs>,\n): PreloadOptions {\n return preloadArgs.map((args) => {\n const remoteInfo = matchRemote(remotes, args.nameOrAlias);\n assert(\n remoteInfo,\n `Unable to preload ${args.nameOrAlias} as it is not included in ${\n !remoteInfo &&\n safeToString({\n remoteInfo,\n remotes,\n })\n }`,\n );\n return {\n remote: remoteInfo,\n preloadConfig: defaultPreloadArgs(args),\n };\n });\n}\n\nexport function normalizePreloadExposes(exposes?: string[]): string[] {\n if (!exposes) {\n return [];\n }\n\n return exposes.map((expose) => {\n if (expose === '.') {\n return expose;\n }\n if (expose.startsWith('./')) {\n return expose.replace('./', '');\n }\n return expose;\n });\n}\n\nexport function preloadAssets(\n remoteInfo: RemoteInfo,\n host: ModuleFederation,\n assets: PreloadAssets,\n // It is used to distinguish preload from load remote parallel loading\n useLinkPreload = true,\n): void {\n const { cssAssets, jsAssetsWithoutEntry, entryAssets } = assets;\n\n if (host.options.inBrowser) {\n entryAssets.forEach((asset) => {\n const { moduleInfo } = asset;\n const module = host.moduleCache.get(remoteInfo.name);\n if (module) {\n getRemoteEntry({\n origin: host,\n remoteInfo: moduleInfo,\n remoteEntryExports: module.remoteEntryExports,\n });\n } else {\n getRemoteEntry({\n origin: host,\n remoteInfo: moduleInfo,\n remoteEntryExports: undefined,\n });\n }\n });\n\n if (useLinkPreload) {\n const defaultAttrs = {\n rel: 'preload',\n as: 'style',\n };\n cssAssets.forEach((cssUrl) => {\n const { link: cssEl, needAttach } = createLink({\n url: cssUrl,\n cb: () => {\n // noop\n },\n attrs: defaultAttrs,\n createLinkHook: (url, attrs) => {\n const res = host.loaderHook.lifecycle.createLink.emit({\n url,\n attrs,\n remoteInfo,\n });\n if (res instanceof HTMLLinkElement) {\n return res;\n }\n return;\n },\n });\n\n needAttach && document.head.appendChild(cssEl);\n });\n } else {\n const defaultAttrs = {\n rel: 'stylesheet',\n type: 'text/css',\n };\n cssAssets.forEach((cssUrl) => {\n const { link: cssEl, needAttach } = createLink({\n url: cssUrl,\n cb: () => {\n // noop\n },\n attrs: defaultAttrs,\n createLinkHook: (url, attrs) => {\n const res = host.loaderHook.lifecycle.createLink.emit({\n url,\n attrs,\n remoteInfo,\n });\n if (res instanceof HTMLLinkElement) {\n return res;\n }\n return;\n },\n needDeleteLink: false,\n });\n\n needAttach && document.head.appendChild(cssEl);\n });\n }\n\n if (useLinkPreload) {\n const defaultAttrs = {\n rel: 'preload',\n as: 'script',\n };\n jsAssetsWithoutEntry.forEach((jsUrl) => {\n const { link: linkEl, needAttach } = createLink({\n url: jsUrl,\n cb: () => {\n // noop\n },\n attrs: defaultAttrs,\n createLinkHook: (url: string, attrs) => {\n const res = host.loaderHook.lifecycle.createLink.emit({\n url,\n attrs,\n remoteInfo,\n });\n if (res instanceof HTMLLinkElement) {\n return res;\n }\n return;\n },\n });\n needAttach && document.head.appendChild(linkEl);\n });\n } else {\n const defaultAttrs = {\n fetchpriority: 'high',\n type: remoteInfo?.type === 'module' ? 'module' : 'text/javascript',\n };\n jsAssetsWithoutEntry.forEach((jsUrl) => {\n const { script: scriptEl, needAttach } = createScript({\n url: jsUrl,\n cb: () => {\n // noop\n },\n attrs: defaultAttrs,\n createScriptHook: (url: string, attrs: any) => {\n const res = host.loaderHook.lifecycle.createScript.emit({\n url,\n attrs,\n remoteInfo,\n });\n if (res instanceof HTMLScriptElement) {\n return res;\n }\n return;\n },\n needDeleteScript: true,\n });\n needAttach && document.head.appendChild(scriptEl);\n });\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"preload.js","names":[],"sources":["../../src/utils/preload.ts"],"sourcesContent":["import { createLink, createScript, safeToString } from '@module-federation/sdk';\nimport {\n PreloadAssets,\n PreloadAssetResult,\n PreloadConfig,\n PreloadOptions,\n PreloadRemoteArgs,\n Remote,\n RemoteInfo,\n ResourceLoadContext,\n ResourceLoadType,\n depsPreloadArg,\n} from '../type';\nimport { matchRemote } from './manifest';\nimport { assert } from './logger';\nimport { ModuleFederation } from '../core';\nimport { getRemoteEntry } from './load';\n\nexport function defaultPreloadArgs(\n preloadConfig: PreloadRemoteArgs | depsPreloadArg,\n): PreloadConfig {\n return {\n resourceCategory: 'sync',\n share: true,\n depsRemote: true,\n ...preloadConfig,\n } as PreloadConfig;\n}\n\nexport function formatPreloadArgs(\n remotes: Array<Remote>,\n preloadArgs: Array<PreloadRemoteArgs>,\n): PreloadOptions {\n return preloadArgs.map((args) => {\n const remoteInfo = matchRemote(remotes, args.nameOrAlias);\n assert(\n remoteInfo,\n `Unable to preload ${args.nameOrAlias} as it is not included in ${\n !remoteInfo &&\n safeToString({\n remoteInfo,\n remotes,\n })\n }`,\n );\n return {\n remote: remoteInfo,\n preloadConfig: defaultPreloadArgs(args),\n };\n });\n}\n\nexport function normalizePreloadExposes(exposes?: string[]): string[] {\n if (!exposes) {\n return [];\n }\n\n return exposes.map((expose) => {\n if (expose === '.') {\n return expose;\n }\n if (expose.startsWith('./')) {\n return expose.replace('./', '');\n }\n return expose;\n });\n}\n\nfunction isTimeoutError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n return error.message.includes('timed out') || error.name.includes('Timeout');\n}\n\nfunction createAssetResult(\n context: ResourceLoadContext,\n url: string,\n status: PreloadAssetResult['status'],\n error?: unknown,\n): PreloadAssetResult {\n return {\n url,\n status,\n resourceType: context.resourceType,\n initiator: context.initiator,\n id: context.id,\n error,\n };\n}\n\nasync function waitForRemoteEntryPreload(\n host: ModuleFederation,\n remoteInfo: RemoteInfo,\n entryRemoteInfo: RemoteInfo,\n context: ResourceLoadContext,\n): Promise<PreloadAssetResult> {\n const cachedRemote = host.moduleCache.get(entryRemoteInfo.name);\n const url = entryRemoteInfo.entry;\n if (cachedRemote?.remoteEntryExports) {\n return createAssetResult(context, url, 'cached');\n }\n\n try {\n const remoteEntryExports = await getRemoteEntry({\n origin: host,\n remoteInfo: entryRemoteInfo,\n remoteEntryExports: cachedRemote?.remoteEntryExports,\n resourceContext: {\n ...context,\n url,\n },\n });\n if (!remoteEntryExports) {\n throw new Error(`Failed to load remoteEntry \"${url}\".`);\n }\n return createAssetResult(context, url, 'success');\n } catch (error) {\n return createAssetResult(\n context,\n url,\n isTimeoutError(error) ? 'timeout' : 'error',\n error,\n );\n }\n}\n\nfunction waitForLinkPreload({\n host,\n remoteInfo,\n url,\n attrs,\n context,\n needDeleteLink,\n}: {\n host: ModuleFederation;\n remoteInfo: RemoteInfo;\n url: string;\n attrs: Record<string, string>;\n context: ResourceLoadContext;\n needDeleteLink?: boolean;\n}): Promise<PreloadAssetResult> {\n return new Promise((resolve) => {\n const { link, needAttach } = createLink({\n url,\n cb: () => {\n resolve(\n createAssetResult(context, url, needAttach ? 'success' : 'cached'),\n );\n },\n onErrorCallback: (error) => {\n resolve(\n createAssetResult(\n context,\n url,\n isTimeoutError(error) ? 'timeout' : 'error',\n error,\n ),\n );\n },\n attrs,\n createLinkHook: (hookUrl, hookAttrs) => {\n const res = host.loaderHook.lifecycle.createLink.emit({\n url: hookUrl,\n attrs: hookAttrs,\n remoteInfo,\n resourceContext: {\n ...context,\n url: hookUrl,\n },\n });\n if (res instanceof HTMLLinkElement) {\n return res;\n }\n return res;\n },\n needDeleteLink,\n });\n\n needAttach && document.head.appendChild(link);\n });\n}\n\nfunction waitForScriptPreload({\n host,\n remoteInfo,\n url,\n attrs,\n context,\n}: {\n host: ModuleFederation;\n remoteInfo: RemoteInfo;\n url: string;\n attrs: Record<string, string>;\n context: ResourceLoadContext;\n}): Promise<PreloadAssetResult> {\n return new Promise((resolve) => {\n const { script, needAttach } = createScript({\n url,\n cb: () => {\n resolve(\n createAssetResult(context, url, needAttach ? 'success' : 'cached'),\n );\n },\n onErrorCallback: (error) => {\n resolve(\n createAssetResult(\n context,\n url,\n isTimeoutError(error) ? 'timeout' : 'error',\n error,\n ),\n );\n },\n attrs,\n createScriptHook: (hookUrl: string, hookAttrs: any) => {\n const res = host.loaderHook.lifecycle.createScript.emit({\n url: hookUrl,\n attrs: hookAttrs,\n remoteInfo,\n resourceContext: {\n ...context,\n url: hookUrl,\n },\n });\n if (res instanceof HTMLScriptElement) {\n return res;\n }\n return res;\n },\n needDeleteScript: true,\n });\n\n needAttach && document.head.appendChild(script);\n });\n}\n\nfunction createResourceContext(\n baseContext: Omit<ResourceLoadContext, 'resourceType'>,\n resourceType: ResourceLoadType,\n): ResourceLoadContext {\n return {\n ...baseContext,\n resourceType,\n };\n}\n\nexport function preloadAssets(\n remoteInfo: RemoteInfo,\n host: ModuleFederation,\n assets: PreloadAssets,\n // It is used to distinguish preload from load remote parallel loading\n useLinkPreload = true,\n baseContext: Omit<ResourceLoadContext, 'resourceType'> = {\n initiator: 'preloadRemote',\n id: remoteInfo.name,\n },\n): Promise<PreloadAssetResult[]> {\n const { cssAssets, jsAssetsWithoutEntry, entryAssets } = assets;\n const results: Array<Promise<PreloadAssetResult>> = [];\n\n if (host.options.inBrowser) {\n entryAssets.forEach((asset) => {\n const { moduleInfo: entryRemoteInfo } = asset;\n results.push(\n waitForRemoteEntryPreload(\n host,\n remoteInfo,\n entryRemoteInfo,\n createResourceContext(baseContext, 'remoteEntry'),\n ),\n );\n });\n\n if (useLinkPreload) {\n const defaultAttrs = {\n rel: 'preload',\n as: 'style',\n };\n cssAssets.forEach((cssUrl) => {\n results.push(\n waitForLinkPreload({\n host,\n remoteInfo,\n url: cssUrl,\n attrs: defaultAttrs,\n context: createResourceContext(baseContext, 'css'),\n }),\n );\n });\n } else {\n const defaultAttrs = {\n rel: 'stylesheet',\n type: 'text/css',\n };\n cssAssets.forEach((cssUrl) => {\n results.push(\n waitForLinkPreload({\n host,\n remoteInfo,\n url: cssUrl,\n attrs: defaultAttrs,\n needDeleteLink: false,\n context: createResourceContext(baseContext, 'css'),\n }),\n );\n });\n }\n\n if (useLinkPreload) {\n const defaultAttrs = {\n rel: 'preload',\n as: 'script',\n };\n jsAssetsWithoutEntry.forEach((jsUrl) => {\n results.push(\n waitForLinkPreload({\n host,\n remoteInfo,\n url: jsUrl,\n attrs: defaultAttrs,\n context: createResourceContext(baseContext, 'js'),\n }),\n );\n });\n } else {\n const defaultAttrs = {\n fetchpriority: 'high',\n type: remoteInfo?.type === 'module' ? 'module' : 'text/javascript',\n };\n jsAssetsWithoutEntry.forEach((jsUrl) => {\n results.push(\n waitForScriptPreload({\n host,\n remoteInfo,\n url: jsUrl,\n attrs: defaultAttrs,\n context: createResourceContext(baseContext, 'js'),\n }),\n );\n });\n }\n }\n\n return Promise.all(results);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/runtime-core",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "type": "module",
5
5
  "author": "zhouxiao <codingzx@gmail.com>",
6
6
  "main": "./dist/index.cjs",
@@ -52,8 +52,8 @@
52
52
  }
53
53
  },
54
54
  "dependencies": {
55
- "@module-federation/sdk": "2.4.0",
56
- "@module-federation/error-codes": "2.4.0"
55
+ "@module-federation/sdk": "2.5.0",
56
+ "@module-federation/error-codes": "2.5.0"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "tsdown --config tsdown.config.ts",