@module-federation/runtime 0.0.0-next-20240814085621 → 0.0.0-next-20240815093707

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -142,29 +142,80 @@ async function loadEntryScript({ name, globalName, entry, createScriptHook }) {
142
142
  if (remoteEntryExports) {
143
143
  return remoteEntryExports;
144
144
  }
145
- if (typeof document === 'undefined') {
146
- return sdk.loadScriptNode(entry, {
147
- attrs: {
148
- name,
149
- globalName
150
- },
151
- createScriptHook
152
- }).then(()=>{
153
- const { remoteEntryKey, entryExports } = share.getRemoteEntryExports(name, globalName);
154
- share.assert(entryExports, `
155
- Unable to use the ${name}'s '${entry}' URL with ${remoteEntryKey}'s globalName to get remoteEntry exports.
156
- Possible reasons could be:\n
157
- 1. '${entry}' is not the correct URL, or the remoteEntry resource or name is incorrect.\n
158
- 2. ${remoteEntryKey} cannot be used to get remoteEntry exports in the window object.
159
- `);
160
- return entryExports;
161
- }).catch((e)=>{
162
- throw e;
163
- });
164
- }
165
145
  return sdk.loadScript(entry, {
166
146
  attrs: {},
167
- createScriptHook
147
+ createScriptHook: (url, attrs)=>{
148
+ const res = createScriptHook.emit({
149
+ url,
150
+ attrs
151
+ });
152
+ if (!res) return;
153
+ if (res instanceof HTMLScriptElement) {
154
+ return res;
155
+ }
156
+ if ('script' in res || 'timeout' in res) {
157
+ return res;
158
+ }
159
+ return;
160
+ }
161
+ }).then(()=>{
162
+ const { remoteEntryKey, entryExports } = share.getRemoteEntryExports(name, globalName);
163
+ share.assert(entryExports, `
164
+ Unable to use the ${name}'s '${entry}' URL with ${remoteEntryKey}'s globalName to get remoteEntry exports.
165
+ Possible reasons could be:\n
166
+ 1. '${entry}' is not the correct URL, or the remoteEntry resource or name is incorrect.\n
167
+ 2. ${remoteEntryKey} cannot be used to get remoteEntry exports in the window object.
168
+ `);
169
+ return entryExports;
170
+ }).catch((e)=>{
171
+ throw e;
172
+ });
173
+ }
174
+ async function loadEntryDom({ remoteInfo, remoteEntryExports, createScriptHook }) {
175
+ const { entry, entryGlobalName: globalName, name, type } = remoteInfo;
176
+ switch(type){
177
+ case 'esm':
178
+ case 'module':
179
+ return loadEsmEntry({
180
+ entry,
181
+ remoteEntryExports
182
+ });
183
+ case 'system':
184
+ return loadSystemJsEntry({
185
+ entry,
186
+ remoteEntryExports
187
+ });
188
+ default:
189
+ return loadEntryScript({
190
+ entry,
191
+ globalName,
192
+ name,
193
+ createScriptHook
194
+ });
195
+ }
196
+ }
197
+ async function loadEntryNode({ remoteInfo, createScriptHook }) {
198
+ const { entry, entryGlobalName: globalName, name } = remoteInfo;
199
+ const { entryExports: remoteEntryExports } = share.getRemoteEntryExports(name, globalName);
200
+ if (remoteEntryExports) {
201
+ return remoteEntryExports;
202
+ }
203
+ return sdk.loadScriptNode(entry, {
204
+ attrs: {
205
+ name,
206
+ globalName
207
+ },
208
+ createScriptHook: (url, attrs)=>{
209
+ const res = createScriptHook.emit({
210
+ url,
211
+ attrs
212
+ });
213
+ if (!res) return;
214
+ if ('url' in res) {
215
+ return res;
216
+ }
217
+ return;
218
+ }
168
219
  }).then(()=>{
169
220
  const { remoteEntryKey, entryExports } = share.getRemoteEntryExports(name, globalName);
170
221
  share.assert(entryExports, `
@@ -182,33 +233,33 @@ function getRemoteEntryUniqueKey(remoteInfo) {
182
233
  const { entry, name } = remoteInfo;
183
234
  return sdk.composeKeyWithSeparator(name, entry);
184
235
  }
185
- async function getRemoteEntry({ remoteEntryExports, remoteInfo, createScriptHook }) {
186
- const { entry, name, type, entryGlobalName } = remoteInfo;
236
+ async function getRemoteEntry({ origin, remoteEntryExports, remoteInfo }) {
187
237
  const uniqueKey = getRemoteEntryUniqueKey(remoteInfo);
188
238
  if (remoteEntryExports) {
189
239
  return remoteEntryExports;
190
240
  }
191
241
  if (!share.globalLoading[uniqueKey]) {
192
- if ([
193
- 'esm',
194
- 'module'
195
- ].includes(type)) {
196
- share.globalLoading[uniqueKey] = loadEsmEntry({
197
- entry,
198
- remoteEntryExports
199
- });
200
- } else if (type === 'system') {
201
- share.globalLoading[uniqueKey] = loadSystemJsEntry({
202
- entry,
242
+ const loadEntryHook = origin.remoteHandler.hooks.lifecycle.loadEntry;
243
+ if (loadEntryHook.listeners.size) {
244
+ share.globalLoading[uniqueKey] = loadEntryHook.emit({
245
+ createScriptHook: origin.loaderHook.lifecycle.createScript,
246
+ remoteInfo,
203
247
  remoteEntryExports
204
- });
248
+ }).then((res)=>res || undefined);
205
249
  } else {
206
- share.globalLoading[uniqueKey] = loadEntryScript({
207
- name,
208
- globalName: entryGlobalName,
209
- entry,
210
- createScriptHook
211
- });
250
+ const createScriptHook = origin.loaderHook.lifecycle.createScript;
251
+ if (!sdk.isBrowserEnv()) {
252
+ share.globalLoading[uniqueKey] = loadEntryNode({
253
+ remoteInfo,
254
+ createScriptHook
255
+ });
256
+ } else {
257
+ share.globalLoading[uniqueKey] = loadEntryDom({
258
+ remoteInfo,
259
+ remoteEntryExports,
260
+ createScriptHook
261
+ });
262
+ }
212
263
  }
213
264
  }
214
265
  return share.globalLoading[uniqueKey];
@@ -243,26 +294,9 @@ let Module = class Module {
243
294
  }
244
295
  // Get remoteEntry.js
245
296
  const remoteEntryExports = await getRemoteEntry({
297
+ origin: this.host,
246
298
  remoteInfo: this.remoteInfo,
247
- remoteEntryExports: this.remoteEntryExports,
248
- createScriptHook: (url, attrs)=>{
249
- const res = this.host.loaderHook.lifecycle.createScript.emit({
250
- url,
251
- attrs
252
- });
253
- if (!res) return;
254
- if (typeof document === 'undefined') {
255
- //todo: needs real fix
256
- return res;
257
- }
258
- if (res instanceof HTMLScriptElement) {
259
- return res;
260
- }
261
- if ('script' in res || 'timeout' in res) {
262
- return res;
263
- }
264
- return;
265
- }
299
+ remoteEntryExports: this.remoteEntryExports
266
300
  });
267
301
  share.assert(remoteEntryExports, `remoteEntryExports is undefined \n ${share.safeToString(this.remoteInfo)}`);
268
302
  this.remoteEntryExports = remoteEntryExports;
@@ -300,6 +334,9 @@ let Module = class Module {
300
334
  remoteInfo: this.remoteInfo,
301
335
  origin: this.host
302
336
  });
337
+ if (typeof (remoteEntryExports == null ? void 0 : remoteEntryExports.init) === 'undefined') {
338
+ console.error('The remote entry interface does not contain "init"', '\n', 'Ensure the name of this remote is not reserved or in use. Check if anything already exists on window[nameOfRemote]', '\n', 'Ensure that window[nameOfRemote] is returning a {get,init} object.');
339
+ }
303
340
  await remoteEntryExports.init(initContainerOptions.shareScope, initContainerOptions.initScope, initContainerOptions.remoteEntryInitOptions);
304
341
  await this.host.hooks.lifecycle.initContainer.emit(_extends$6({}, initContainerOptions, {
305
342
  remoteEntryExports
@@ -595,65 +632,33 @@ useLinkPreload = true) {
595
632
  const module = host.moduleCache.get(remoteInfo.name);
596
633
  if (module) {
597
634
  getRemoteEntry({
635
+ origin: host,
598
636
  remoteInfo: moduleInfo,
599
- remoteEntryExports: module.remoteEntryExports,
600
- createScriptHook: (url, attrs)=>{
601
- const res = host.loaderHook.lifecycle.createScript.emit({
602
- url,
603
- attrs
604
- });
605
- if (!res) return;
606
- if (typeof document === 'undefined') {
607
- //todo: needs real fix
608
- return res;
609
- }
610
- if (res instanceof HTMLScriptElement) {
611
- return res;
612
- }
613
- if ('script' in res || 'timeout' in res) {
614
- return res;
615
- }
616
- return;
617
- }
637
+ remoteEntryExports: module.remoteEntryExports
618
638
  });
619
639
  } else {
620
640
  getRemoteEntry({
641
+ origin: host,
621
642
  remoteInfo: moduleInfo,
622
- remoteEntryExports: undefined,
623
- createScriptHook: (url, attrs)=>{
624
- const res = host.loaderHook.lifecycle.createScript.emit({
625
- url,
626
- attrs
627
- });
628
- if (!res) return;
629
- if (typeof document === 'undefined') {
630
- //todo: needs real fix
631
- return res;
632
- }
633
- if (res instanceof HTMLScriptElement) {
634
- return res;
635
- }
636
- if ('script' in res || 'timeout' in res) {
637
- return res;
638
- }
639
- return;
640
- }
643
+ remoteEntryExports: undefined
641
644
  });
642
645
  }
643
646
  });
644
647
  if (useLinkPreload) {
648
+ const defaultAttrs = {
649
+ rel: 'preload',
650
+ as: 'style',
651
+ crossorigin: 'anonymous'
652
+ };
645
653
  cssAssets.forEach((cssUrl)=>{
646
654
  const { link: cssEl, needAttach } = sdk.createLink({
647
655
  url: cssUrl,
648
656
  cb: ()=>{},
649
- attrs: {
650
- rel: 'preload',
651
- as: 'style',
652
- crossorigin: 'anonymous'
653
- },
654
- createLinkHook: (url)=>{
657
+ attrs: defaultAttrs,
658
+ createLinkHook: (url, attrs)=>{
655
659
  const res = host.loaderHook.lifecycle.createLink.emit({
656
- url
660
+ url,
661
+ attrs
657
662
  });
658
663
  if (res instanceof HTMLLinkElement) {
659
664
  return res;
@@ -664,17 +669,19 @@ useLinkPreload = true) {
664
669
  needAttach && document.head.appendChild(cssEl);
665
670
  });
666
671
  } else {
672
+ const defaultAttrs = {
673
+ rel: 'stylesheet',
674
+ type: 'text/css'
675
+ };
667
676
  cssAssets.forEach((cssUrl)=>{
668
677
  const { link: cssEl, needAttach } = sdk.createLink({
669
678
  url: cssUrl,
670
679
  cb: ()=>{},
671
- attrs: {
672
- rel: 'stylesheet',
673
- type: 'text/css'
674
- },
675
- createLinkHook: (url)=>{
680
+ attrs: defaultAttrs,
681
+ createLinkHook: (url, attrs)=>{
676
682
  const res = host.loaderHook.lifecycle.createLink.emit({
677
- url
683
+ url,
684
+ attrs
678
685
  });
679
686
  if (res instanceof HTMLLinkElement) {
680
687
  return res;
@@ -687,18 +694,20 @@ useLinkPreload = true) {
687
694
  });
688
695
  }
689
696
  if (useLinkPreload) {
697
+ const defaultAttrs = {
698
+ rel: 'preload',
699
+ as: 'script',
700
+ crossorigin: 'anonymous'
701
+ };
690
702
  jsAssetsWithoutEntry.forEach((jsUrl)=>{
691
703
  const { link: linkEl, needAttach } = sdk.createLink({
692
704
  url: jsUrl,
693
705
  cb: ()=>{},
694
- attrs: {
695
- rel: 'preload',
696
- as: 'script',
697
- crossorigin: 'anonymous'
698
- },
699
- createLinkHook: (url)=>{
706
+ attrs: defaultAttrs,
707
+ createLinkHook: (url, attrs)=>{
700
708
  const res = host.loaderHook.lifecycle.createLink.emit({
701
- url
709
+ url,
710
+ attrs
702
711
  });
703
712
  if (res instanceof HTMLLinkElement) {
704
713
  return res;
@@ -709,14 +718,15 @@ useLinkPreload = true) {
709
718
  needAttach && document.head.appendChild(linkEl);
710
719
  });
711
720
  } else {
721
+ const defaultAttrs = {
722
+ fetchpriority: 'high',
723
+ type: (remoteInfo == null ? void 0 : remoteInfo.type) === 'module' ? 'module' : 'text/javascript'
724
+ };
712
725
  jsAssetsWithoutEntry.forEach((jsUrl)=>{
713
726
  const { script: scriptEl, needAttach } = sdk.createScript({
714
727
  url: jsUrl,
715
728
  cb: ()=>{},
716
- attrs: {
717
- fetchpriority: 'high',
718
- type: (remoteInfo == null ? void 0 : remoteInfo.type) === 'module' ? 'module' : 'text/javascript'
719
- },
729
+ attrs: defaultAttrs,
720
730
  createScriptHook: (url, attrs)=>{
721
731
  const res = host.loaderHook.lifecycle.createScript.emit({
722
732
  url,
@@ -1113,6 +1123,8 @@ class SnapshotHandler {
1113
1123
  remoteSnapshot,
1114
1124
  globalSnapshot
1115
1125
  });
1126
+ let mSnapshot;
1127
+ let gSnapshot;
1116
1128
  // global snapshot includes manifest or module info includes manifest
1117
1129
  if (globalRemoteSnapshot) {
1118
1130
  if (sdk.isManifestProvider(globalRemoteSnapshot)) {
@@ -1124,10 +1136,8 @@ class SnapshotHandler {
1124
1136
  // Therefore, set the snapshot key to the global address of the actual request
1125
1137
  entry: remoteEntry
1126
1138
  }), moduleSnapshot);
1127
- return {
1128
- remoteSnapshot: moduleSnapshot,
1129
- globalSnapshot: globalSnapshotRes
1130
- };
1139
+ mSnapshot = moduleSnapshot;
1140
+ gSnapshot = globalSnapshotRes;
1131
1141
  } else {
1132
1142
  const { remoteSnapshot: remoteSnapshotRes } = await this.hooks.lifecycle.loadRemoteSnapshot.emit({
1133
1143
  options: this.HostInstance.options,
@@ -1135,10 +1145,8 @@ class SnapshotHandler {
1135
1145
  remoteSnapshot: globalRemoteSnapshot,
1136
1146
  from: 'global'
1137
1147
  });
1138
- return {
1139
- remoteSnapshot: remoteSnapshotRes,
1140
- globalSnapshot: globalSnapshotRes
1141
- };
1148
+ mSnapshot = remoteSnapshotRes;
1149
+ gSnapshot = globalSnapshotRes;
1142
1150
  }
1143
1151
  } else {
1144
1152
  if (share.isRemoteInfoWithEntry(moduleInfo)) {
@@ -1152,10 +1160,8 @@ class SnapshotHandler {
1152
1160
  remoteSnapshot: moduleSnapshot,
1153
1161
  from: 'global'
1154
1162
  });
1155
- return {
1156
- remoteSnapshot: remoteSnapshotRes,
1157
- globalSnapshot: globalSnapshotRes
1158
- };
1163
+ mSnapshot = remoteSnapshotRes;
1164
+ gSnapshot = globalSnapshotRes;
1159
1165
  } else {
1160
1166
  share.error(`
1161
1167
  Cannot get remoteSnapshot with the name: '${moduleInfo.name}', version: '${moduleInfo.version}' from __FEDERATION__.moduleInfo. The following reasons may be causing the problem:\n
@@ -1165,6 +1171,10 @@ class SnapshotHandler {
1165
1171
  `);
1166
1172
  }
1167
1173
  }
1174
+ return {
1175
+ remoteSnapshot: mSnapshot,
1176
+ globalSnapshot: gSnapshot
1177
+ };
1168
1178
  }
1169
1179
  getGlobalRemoteInfo(moduleInfo) {
1170
1180
  return getGlobalRemoteInfo(moduleInfo, this.HostInstance);
@@ -1217,7 +1227,8 @@ class SnapshotHandler {
1217
1227
  this.hooks = new PluginSystem({
1218
1228
  beforeLoadRemoteSnapshot: new AsyncHook('beforeLoadRemoteSnapshot'),
1219
1229
  loadSnapshot: new AsyncWaterfallHook('loadGlobalSnapshot'),
1220
- loadRemoteSnapshot: new AsyncWaterfallHook('loadRemoteSnapshot')
1230
+ loadRemoteSnapshot: new AsyncWaterfallHook('loadRemoteSnapshot'),
1231
+ afterLoadSnapshot: new AsyncWaterfallHook('loadRemoteSnapshot')
1221
1232
  });
1222
1233
  this.manifestLoading = share.Global.__FEDERATION__.__MANIFEST_LOADING__;
1223
1234
  this.HostInstance = HostInstance;
@@ -1940,7 +1951,8 @@ class RemoteHandler {
1940
1951
  beforePreloadRemote: new AsyncHook('beforePreloadRemote'),
1941
1952
  generatePreloadAssets: new AsyncHook('generatePreloadAssets'),
1942
1953
  // not used yet
1943
- afterPreloadRemote: new AsyncHook()
1954
+ afterPreloadRemote: new AsyncHook(),
1955
+ loadEntry: new AsyncHook()
1944
1956
  });
1945
1957
  this.host = host;
1946
1958
  this.idToRemoteMap = {};
@@ -2066,7 +2078,7 @@ class FederationHost {
2066
2078
  // maybe will change, temporarily for internal use only
2067
2079
  initContainer: new AsyncWaterfallHook('initContainer')
2068
2080
  });
2069
- this.version = "0.3.5";
2081
+ this.version = "0.4.0";
2070
2082
  this.moduleCache = new Map();
2071
2083
  this.loaderHook = new PluginSystem({
2072
2084
  // FIXME: may not be suitable , not open to the public yet
package/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
- import { g as getGlobalHostPlugins, a as globalLoading, D as DEFAULT_REMOTE_TYPE, b as DEFAULT_SCOPE, c as getRemoteEntryExports, d as assert, s as safeToString, e as getFMId, i as isObject, f as error, w as warn, h as isPlainObject, j as isRemoteInfoWithEntry, k as isPureRemoteEntry, l as getRemoteEntryInfoFromSnapshot, m as isBrowserEnv, n as getInfoWithoutType, o as getPreloaded, p as setPreloaded, q as getRegisteredShare, r as arrayOptions, t as getGlobalSnapshotInfoByModuleInfo, u as addGlobalSnapshot, v as setGlobalSnapshotInfoByModuleInfo, G as Global, x as getGlobalSnapshot, y as formatShareConfigs, z as getTargetSharedOptions, A as getGlobalShareScope, B as addUniqueItem, C as getBuilderId, E as setGlobalFederationConstructor, F as getGlobalFederationInstance, H as getGlobalFederationConstructor, I as setGlobalFederationInstance } from './share.esm.js';
1
+ import { g as getGlobalHostPlugins, a as globalLoading, D as DEFAULT_REMOTE_TYPE, b as DEFAULT_SCOPE, c as getRemoteEntryExports, d as assert, s as safeToString, e as getFMId, i as isObject, f as error, w as warn, h as isPlainObject, j as isRemoteInfoWithEntry, k as isPureRemoteEntry, l as getRemoteEntryInfoFromSnapshot, m as isBrowserEnv$1, n as getInfoWithoutType, o as getPreloaded, p as setPreloaded, q as getRegisteredShare, r as arrayOptions, t as getGlobalSnapshotInfoByModuleInfo, u as addGlobalSnapshot, v as setGlobalSnapshotInfoByModuleInfo, G as Global, x as getGlobalSnapshot, y as formatShareConfigs, z as getTargetSharedOptions, A as getGlobalShareScope, B as addUniqueItem, C as getBuilderId, E as setGlobalFederationConstructor, F as getGlobalFederationInstance, H as getGlobalFederationConstructor, I as setGlobalFederationInstance } from './share.esm.js';
2
2
  export { J as registerGlobalPlugins } from './share.esm.js';
3
- import { loadScriptNode, loadScript, composeKeyWithSeparator, createLink, createScript, getResourceUrl, isManifestProvider, generateSnapshotFromManifest, warn as warn$1, isBrowserEnv as isBrowserEnv$1 } from '@module-federation/sdk';
3
+ import { isBrowserEnv, loadScriptNode, composeKeyWithSeparator, loadScript, createLink, createScript, getResourceUrl, isManifestProvider, generateSnapshotFromManifest, warn as warn$1 } from '@module-federation/sdk';
4
4
  export { loadScript, loadScriptNode } from '@module-federation/sdk';
5
5
 
6
6
  // Function to match a remote with its name and expose
@@ -140,29 +140,80 @@ async function loadEntryScript({ name, globalName, entry, createScriptHook }) {
140
140
  if (remoteEntryExports) {
141
141
  return remoteEntryExports;
142
142
  }
143
- if (typeof document === 'undefined') {
144
- return loadScriptNode(entry, {
145
- attrs: {
146
- name,
147
- globalName
148
- },
149
- createScriptHook
150
- }).then(()=>{
151
- const { remoteEntryKey, entryExports } = getRemoteEntryExports(name, globalName);
152
- assert(entryExports, `
153
- Unable to use the ${name}'s '${entry}' URL with ${remoteEntryKey}'s globalName to get remoteEntry exports.
154
- Possible reasons could be:\n
155
- 1. '${entry}' is not the correct URL, or the remoteEntry resource or name is incorrect.\n
156
- 2. ${remoteEntryKey} cannot be used to get remoteEntry exports in the window object.
157
- `);
158
- return entryExports;
159
- }).catch((e)=>{
160
- throw e;
161
- });
162
- }
163
143
  return loadScript(entry, {
164
144
  attrs: {},
165
- createScriptHook
145
+ createScriptHook: (url, attrs)=>{
146
+ const res = createScriptHook.emit({
147
+ url,
148
+ attrs
149
+ });
150
+ if (!res) return;
151
+ if (res instanceof HTMLScriptElement) {
152
+ return res;
153
+ }
154
+ if ('script' in res || 'timeout' in res) {
155
+ return res;
156
+ }
157
+ return;
158
+ }
159
+ }).then(()=>{
160
+ const { remoteEntryKey, entryExports } = getRemoteEntryExports(name, globalName);
161
+ assert(entryExports, `
162
+ Unable to use the ${name}'s '${entry}' URL with ${remoteEntryKey}'s globalName to get remoteEntry exports.
163
+ Possible reasons could be:\n
164
+ 1. '${entry}' is not the correct URL, or the remoteEntry resource or name is incorrect.\n
165
+ 2. ${remoteEntryKey} cannot be used to get remoteEntry exports in the window object.
166
+ `);
167
+ return entryExports;
168
+ }).catch((e)=>{
169
+ throw e;
170
+ });
171
+ }
172
+ async function loadEntryDom({ remoteInfo, remoteEntryExports, createScriptHook }) {
173
+ const { entry, entryGlobalName: globalName, name, type } = remoteInfo;
174
+ switch(type){
175
+ case 'esm':
176
+ case 'module':
177
+ return loadEsmEntry({
178
+ entry,
179
+ remoteEntryExports
180
+ });
181
+ case 'system':
182
+ return loadSystemJsEntry({
183
+ entry,
184
+ remoteEntryExports
185
+ });
186
+ default:
187
+ return loadEntryScript({
188
+ entry,
189
+ globalName,
190
+ name,
191
+ createScriptHook
192
+ });
193
+ }
194
+ }
195
+ async function loadEntryNode({ remoteInfo, createScriptHook }) {
196
+ const { entry, entryGlobalName: globalName, name } = remoteInfo;
197
+ const { entryExports: remoteEntryExports } = getRemoteEntryExports(name, globalName);
198
+ if (remoteEntryExports) {
199
+ return remoteEntryExports;
200
+ }
201
+ return loadScriptNode(entry, {
202
+ attrs: {
203
+ name,
204
+ globalName
205
+ },
206
+ createScriptHook: (url, attrs)=>{
207
+ const res = createScriptHook.emit({
208
+ url,
209
+ attrs
210
+ });
211
+ if (!res) return;
212
+ if ('url' in res) {
213
+ return res;
214
+ }
215
+ return;
216
+ }
166
217
  }).then(()=>{
167
218
  const { remoteEntryKey, entryExports } = getRemoteEntryExports(name, globalName);
168
219
  assert(entryExports, `
@@ -180,33 +231,33 @@ function getRemoteEntryUniqueKey(remoteInfo) {
180
231
  const { entry, name } = remoteInfo;
181
232
  return composeKeyWithSeparator(name, entry);
182
233
  }
183
- async function getRemoteEntry({ remoteEntryExports, remoteInfo, createScriptHook }) {
184
- const { entry, name, type, entryGlobalName } = remoteInfo;
234
+ async function getRemoteEntry({ origin, remoteEntryExports, remoteInfo }) {
185
235
  const uniqueKey = getRemoteEntryUniqueKey(remoteInfo);
186
236
  if (remoteEntryExports) {
187
237
  return remoteEntryExports;
188
238
  }
189
239
  if (!globalLoading[uniqueKey]) {
190
- if ([
191
- 'esm',
192
- 'module'
193
- ].includes(type)) {
194
- globalLoading[uniqueKey] = loadEsmEntry({
195
- entry,
196
- remoteEntryExports
197
- });
198
- } else if (type === 'system') {
199
- globalLoading[uniqueKey] = loadSystemJsEntry({
200
- entry,
240
+ const loadEntryHook = origin.remoteHandler.hooks.lifecycle.loadEntry;
241
+ if (loadEntryHook.listeners.size) {
242
+ globalLoading[uniqueKey] = loadEntryHook.emit({
243
+ createScriptHook: origin.loaderHook.lifecycle.createScript,
244
+ remoteInfo,
201
245
  remoteEntryExports
202
- });
246
+ }).then((res)=>res || undefined);
203
247
  } else {
204
- globalLoading[uniqueKey] = loadEntryScript({
205
- name,
206
- globalName: entryGlobalName,
207
- entry,
208
- createScriptHook
209
- });
248
+ const createScriptHook = origin.loaderHook.lifecycle.createScript;
249
+ if (!isBrowserEnv()) {
250
+ globalLoading[uniqueKey] = loadEntryNode({
251
+ remoteInfo,
252
+ createScriptHook
253
+ });
254
+ } else {
255
+ globalLoading[uniqueKey] = loadEntryDom({
256
+ remoteInfo,
257
+ remoteEntryExports,
258
+ createScriptHook
259
+ });
260
+ }
210
261
  }
211
262
  }
212
263
  return globalLoading[uniqueKey];
@@ -241,26 +292,9 @@ let Module = class Module {
241
292
  }
242
293
  // Get remoteEntry.js
243
294
  const remoteEntryExports = await getRemoteEntry({
295
+ origin: this.host,
244
296
  remoteInfo: this.remoteInfo,
245
- remoteEntryExports: this.remoteEntryExports,
246
- createScriptHook: (url, attrs)=>{
247
- const res = this.host.loaderHook.lifecycle.createScript.emit({
248
- url,
249
- attrs
250
- });
251
- if (!res) return;
252
- if (typeof document === 'undefined') {
253
- //todo: needs real fix
254
- return res;
255
- }
256
- if (res instanceof HTMLScriptElement) {
257
- return res;
258
- }
259
- if ('script' in res || 'timeout' in res) {
260
- return res;
261
- }
262
- return;
263
- }
297
+ remoteEntryExports: this.remoteEntryExports
264
298
  });
265
299
  assert(remoteEntryExports, `remoteEntryExports is undefined \n ${safeToString(this.remoteInfo)}`);
266
300
  this.remoteEntryExports = remoteEntryExports;
@@ -298,6 +332,9 @@ let Module = class Module {
298
332
  remoteInfo: this.remoteInfo,
299
333
  origin: this.host
300
334
  });
335
+ if (typeof (remoteEntryExports == null ? void 0 : remoteEntryExports.init) === 'undefined') {
336
+ console.error('The remote entry interface does not contain "init"', '\n', 'Ensure the name of this remote is not reserved or in use. Check if anything already exists on window[nameOfRemote]', '\n', 'Ensure that window[nameOfRemote] is returning a {get,init} object.');
337
+ }
301
338
  await remoteEntryExports.init(initContainerOptions.shareScope, initContainerOptions.initScope, initContainerOptions.remoteEntryInitOptions);
302
339
  await this.host.hooks.lifecycle.initContainer.emit(_extends$6({}, initContainerOptions, {
303
340
  remoteEntryExports
@@ -593,65 +630,33 @@ useLinkPreload = true) {
593
630
  const module = host.moduleCache.get(remoteInfo.name);
594
631
  if (module) {
595
632
  getRemoteEntry({
633
+ origin: host,
596
634
  remoteInfo: moduleInfo,
597
- remoteEntryExports: module.remoteEntryExports,
598
- createScriptHook: (url, attrs)=>{
599
- const res = host.loaderHook.lifecycle.createScript.emit({
600
- url,
601
- attrs
602
- });
603
- if (!res) return;
604
- if (typeof document === 'undefined') {
605
- //todo: needs real fix
606
- return res;
607
- }
608
- if (res instanceof HTMLScriptElement) {
609
- return res;
610
- }
611
- if ('script' in res || 'timeout' in res) {
612
- return res;
613
- }
614
- return;
615
- }
635
+ remoteEntryExports: module.remoteEntryExports
616
636
  });
617
637
  } else {
618
638
  getRemoteEntry({
639
+ origin: host,
619
640
  remoteInfo: moduleInfo,
620
- remoteEntryExports: undefined,
621
- createScriptHook: (url, attrs)=>{
622
- const res = host.loaderHook.lifecycle.createScript.emit({
623
- url,
624
- attrs
625
- });
626
- if (!res) return;
627
- if (typeof document === 'undefined') {
628
- //todo: needs real fix
629
- return res;
630
- }
631
- if (res instanceof HTMLScriptElement) {
632
- return res;
633
- }
634
- if ('script' in res || 'timeout' in res) {
635
- return res;
636
- }
637
- return;
638
- }
641
+ remoteEntryExports: undefined
639
642
  });
640
643
  }
641
644
  });
642
645
  if (useLinkPreload) {
646
+ const defaultAttrs = {
647
+ rel: 'preload',
648
+ as: 'style',
649
+ crossorigin: 'anonymous'
650
+ };
643
651
  cssAssets.forEach((cssUrl)=>{
644
652
  const { link: cssEl, needAttach } = createLink({
645
653
  url: cssUrl,
646
654
  cb: ()=>{},
647
- attrs: {
648
- rel: 'preload',
649
- as: 'style',
650
- crossorigin: 'anonymous'
651
- },
652
- createLinkHook: (url)=>{
655
+ attrs: defaultAttrs,
656
+ createLinkHook: (url, attrs)=>{
653
657
  const res = host.loaderHook.lifecycle.createLink.emit({
654
- url
658
+ url,
659
+ attrs
655
660
  });
656
661
  if (res instanceof HTMLLinkElement) {
657
662
  return res;
@@ -662,17 +667,19 @@ useLinkPreload = true) {
662
667
  needAttach && document.head.appendChild(cssEl);
663
668
  });
664
669
  } else {
670
+ const defaultAttrs = {
671
+ rel: 'stylesheet',
672
+ type: 'text/css'
673
+ };
665
674
  cssAssets.forEach((cssUrl)=>{
666
675
  const { link: cssEl, needAttach } = createLink({
667
676
  url: cssUrl,
668
677
  cb: ()=>{},
669
- attrs: {
670
- rel: 'stylesheet',
671
- type: 'text/css'
672
- },
673
- createLinkHook: (url)=>{
678
+ attrs: defaultAttrs,
679
+ createLinkHook: (url, attrs)=>{
674
680
  const res = host.loaderHook.lifecycle.createLink.emit({
675
- url
681
+ url,
682
+ attrs
676
683
  });
677
684
  if (res instanceof HTMLLinkElement) {
678
685
  return res;
@@ -685,18 +692,20 @@ useLinkPreload = true) {
685
692
  });
686
693
  }
687
694
  if (useLinkPreload) {
695
+ const defaultAttrs = {
696
+ rel: 'preload',
697
+ as: 'script',
698
+ crossorigin: 'anonymous'
699
+ };
688
700
  jsAssetsWithoutEntry.forEach((jsUrl)=>{
689
701
  const { link: linkEl, needAttach } = createLink({
690
702
  url: jsUrl,
691
703
  cb: ()=>{},
692
- attrs: {
693
- rel: 'preload',
694
- as: 'script',
695
- crossorigin: 'anonymous'
696
- },
697
- createLinkHook: (url)=>{
704
+ attrs: defaultAttrs,
705
+ createLinkHook: (url, attrs)=>{
698
706
  const res = host.loaderHook.lifecycle.createLink.emit({
699
- url
707
+ url,
708
+ attrs
700
709
  });
701
710
  if (res instanceof HTMLLinkElement) {
702
711
  return res;
@@ -707,14 +716,15 @@ useLinkPreload = true) {
707
716
  needAttach && document.head.appendChild(linkEl);
708
717
  });
709
718
  } else {
719
+ const defaultAttrs = {
720
+ fetchpriority: 'high',
721
+ type: (remoteInfo == null ? void 0 : remoteInfo.type) === 'module' ? 'module' : 'text/javascript'
722
+ };
710
723
  jsAssetsWithoutEntry.forEach((jsUrl)=>{
711
724
  const { script: scriptEl, needAttach } = createScript({
712
725
  url: jsUrl,
713
726
  cb: ()=>{},
714
- attrs: {
715
- fetchpriority: 'high',
716
- type: (remoteInfo == null ? void 0 : remoteInfo.type) === 'module' ? 'module' : 'text/javascript'
717
- },
727
+ attrs: defaultAttrs,
718
728
  createScriptHook: (url, attrs)=>{
719
729
  const res = host.loaderHook.lifecycle.createScript.emit({
720
730
  url,
@@ -753,7 +763,7 @@ function assignRemoteInfo(remoteInfo, remoteSnapshot) {
753
763
  error(`The attribute remoteEntry of ${remoteInfo.name} must not be undefined.`);
754
764
  }
755
765
  let entryUrl = getResourceUrl(remoteSnapshot, remoteEntryInfo.url);
756
- if (!isBrowserEnv() && !entryUrl.startsWith('http')) {
766
+ if (!isBrowserEnv$1() && !entryUrl.startsWith('http')) {
757
767
  entryUrl = `https:${entryUrl}`;
758
768
  }
759
769
  remoteInfo.type = remoteEntryInfo.type;
@@ -1111,10 +1121,12 @@ class SnapshotHandler {
1111
1121
  remoteSnapshot,
1112
1122
  globalSnapshot
1113
1123
  });
1124
+ let mSnapshot;
1125
+ let gSnapshot;
1114
1126
  // global snapshot includes manifest or module info includes manifest
1115
1127
  if (globalRemoteSnapshot) {
1116
1128
  if (isManifestProvider(globalRemoteSnapshot)) {
1117
- const remoteEntry = isBrowserEnv() ? globalRemoteSnapshot.remoteEntry : globalRemoteSnapshot.ssrRemoteEntry || globalRemoteSnapshot.remoteEntry || '';
1129
+ const remoteEntry = isBrowserEnv$1() ? globalRemoteSnapshot.remoteEntry : globalRemoteSnapshot.ssrRemoteEntry || globalRemoteSnapshot.remoteEntry || '';
1118
1130
  const moduleSnapshot = await this.getManifestJson(remoteEntry, moduleInfo, {});
1119
1131
  // eslint-disable-next-line @typescript-eslint/no-shadow
1120
1132
  const globalSnapshotRes = setGlobalSnapshotInfoByModuleInfo(_extends$3({}, moduleInfo, {
@@ -1122,10 +1134,8 @@ class SnapshotHandler {
1122
1134
  // Therefore, set the snapshot key to the global address of the actual request
1123
1135
  entry: remoteEntry
1124
1136
  }), moduleSnapshot);
1125
- return {
1126
- remoteSnapshot: moduleSnapshot,
1127
- globalSnapshot: globalSnapshotRes
1128
- };
1137
+ mSnapshot = moduleSnapshot;
1138
+ gSnapshot = globalSnapshotRes;
1129
1139
  } else {
1130
1140
  const { remoteSnapshot: remoteSnapshotRes } = await this.hooks.lifecycle.loadRemoteSnapshot.emit({
1131
1141
  options: this.HostInstance.options,
@@ -1133,10 +1143,8 @@ class SnapshotHandler {
1133
1143
  remoteSnapshot: globalRemoteSnapshot,
1134
1144
  from: 'global'
1135
1145
  });
1136
- return {
1137
- remoteSnapshot: remoteSnapshotRes,
1138
- globalSnapshot: globalSnapshotRes
1139
- };
1146
+ mSnapshot = remoteSnapshotRes;
1147
+ gSnapshot = globalSnapshotRes;
1140
1148
  }
1141
1149
  } else {
1142
1150
  if (isRemoteInfoWithEntry(moduleInfo)) {
@@ -1150,10 +1158,8 @@ class SnapshotHandler {
1150
1158
  remoteSnapshot: moduleSnapshot,
1151
1159
  from: 'global'
1152
1160
  });
1153
- return {
1154
- remoteSnapshot: remoteSnapshotRes,
1155
- globalSnapshot: globalSnapshotRes
1156
- };
1161
+ mSnapshot = remoteSnapshotRes;
1162
+ gSnapshot = globalSnapshotRes;
1157
1163
  } else {
1158
1164
  error(`
1159
1165
  Cannot get remoteSnapshot with the name: '${moduleInfo.name}', version: '${moduleInfo.version}' from __FEDERATION__.moduleInfo. The following reasons may be causing the problem:\n
@@ -1163,6 +1169,10 @@ class SnapshotHandler {
1163
1169
  `);
1164
1170
  }
1165
1171
  }
1172
+ return {
1173
+ remoteSnapshot: mSnapshot,
1174
+ globalSnapshot: gSnapshot
1175
+ };
1166
1176
  }
1167
1177
  getGlobalRemoteInfo(moduleInfo) {
1168
1178
  return getGlobalRemoteInfo(moduleInfo, this.HostInstance);
@@ -1215,7 +1225,8 @@ class SnapshotHandler {
1215
1225
  this.hooks = new PluginSystem({
1216
1226
  beforeLoadRemoteSnapshot: new AsyncHook('beforeLoadRemoteSnapshot'),
1217
1227
  loadSnapshot: new AsyncWaterfallHook('loadGlobalSnapshot'),
1218
- loadRemoteSnapshot: new AsyncWaterfallHook('loadRemoteSnapshot')
1228
+ loadRemoteSnapshot: new AsyncWaterfallHook('loadRemoteSnapshot'),
1229
+ afterLoadSnapshot: new AsyncWaterfallHook('loadRemoteSnapshot')
1219
1230
  });
1220
1231
  this.manifestLoading = Global.__FEDERATION__.__MANIFEST_LOADING__;
1221
1232
  this.HostInstance = HostInstance;
@@ -1785,7 +1796,7 @@ class RemoteHandler {
1785
1796
  }
1786
1797
  // Set the remote entry to a complete path
1787
1798
  if ('entry' in remote) {
1788
- if (isBrowserEnv$1() && !remote.entry.startsWith('http')) {
1799
+ if (isBrowserEnv() && !remote.entry.startsWith('http')) {
1789
1800
  remote.entry = new URL(remote.entry, window.location.origin).href;
1790
1801
  }
1791
1802
  }
@@ -1938,7 +1949,8 @@ class RemoteHandler {
1938
1949
  beforePreloadRemote: new AsyncHook('beforePreloadRemote'),
1939
1950
  generatePreloadAssets: new AsyncHook('generatePreloadAssets'),
1940
1951
  // not used yet
1941
- afterPreloadRemote: new AsyncHook()
1952
+ afterPreloadRemote: new AsyncHook(),
1953
+ loadEntry: new AsyncHook()
1942
1954
  });
1943
1955
  this.host = host;
1944
1956
  this.idToRemoteMap = {};
@@ -2064,7 +2076,7 @@ class FederationHost {
2064
2076
  // maybe will change, temporarily for internal use only
2065
2077
  initContainer: new AsyncWaterfallHook('initContainer')
2066
2078
  });
2067
- this.version = "0.3.5";
2079
+ this.version = "0.4.0";
2068
2080
  this.moduleCache = new Map();
2069
2081
  this.loaderHook = new PluginSystem({
2070
2082
  // FIXME: may not be suitable , not open to the public yet
@@ -2085,7 +2097,7 @@ class FederationHost {
2085
2097
  ],
2086
2098
  remotes: [],
2087
2099
  shared: {},
2088
- inBrowser: isBrowserEnv()
2100
+ inBrowser: isBrowserEnv$1()
2089
2101
  };
2090
2102
  this.name = userOptions.name;
2091
2103
  this.options = defaultOptions;
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/runtime",
3
- "version": "0.3.5",
3
+ "version": "0.4.0",
4
4
  "author": "zhouxiao <codingzx@gmail.com>",
5
5
  "main": "./index.cjs.js",
6
6
  "module": "./index.esm.js",
package/dist/share.cjs.js CHANGED
@@ -212,7 +212,7 @@ function getGlobalFederationConstructor() {
212
212
  function setGlobalFederationConstructor(FederationConstructor, isDebug = isDebugMode()) {
213
213
  if (isDebug) {
214
214
  globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR__ = FederationConstructor;
215
- globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.3.5";
215
+ globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.4.0";
216
216
  }
217
217
  }
218
218
  // eslint-disable-next-line @typescript-eslint/ban-types
package/dist/share.esm.js CHANGED
@@ -210,7 +210,7 @@ function getGlobalFederationConstructor() {
210
210
  function setGlobalFederationConstructor(FederationConstructor, isDebug = isDebugMode()) {
211
211
  if (isDebug) {
212
212
  globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR__ = FederationConstructor;
213
- globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.3.5";
213
+ globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.4.0";
214
214
  }
215
215
  }
216
216
  // eslint-disable-next-line @typescript-eslint/ban-types
@@ -55,6 +55,7 @@ export declare class FederationHost {
55
55
  }], CreateScriptHookReturn>;
56
56
  createLink: SyncHook<[{
57
57
  url: string;
58
+ attrs?: Record<string, any>;
58
59
  }], void | HTMLLinkElement>;
59
60
  fetch: AsyncHook<[string, RequestInit], false | void | Promise<Response>>;
60
61
  }>;
@@ -32,6 +32,11 @@ export declare class SnapshotHandler {
32
32
  remoteSnapshot: ModuleInfo;
33
33
  from: "global" | "manifest";
34
34
  }>;
35
+ afterLoadSnapshot: AsyncWaterfallHook<{
36
+ options: Options;
37
+ moduleInfo: Remote;
38
+ remoteSnapshot: ModuleInfo;
39
+ }>;
35
40
  }>;
36
41
  loaderHook: FederationHost['loaderHook'];
37
42
  manifestLoading: Record<string, Promise<ModuleInfo>>;
@@ -1,5 +1,5 @@
1
1
  import type { ModuleInfo, GlobalModuleInfo } from '@module-federation/sdk';
2
- import { Options, UserOptions, PreloadAssets, PreloadOptions, PreloadRemoteArgs, Remote, RemoteInfo } from '../type';
2
+ import { Options, UserOptions, PreloadAssets, PreloadOptions, PreloadRemoteArgs, Remote, RemoteInfo, RemoteEntryExports } from '../type';
3
3
  import { FederationHost } from '../core';
4
4
  import { PluginSystem, AsyncHook, AsyncWaterfallHook, SyncHook, SyncWaterfallHook } from '../utils/hooks';
5
5
  import { Module, ModuleOptions } from '../module';
@@ -78,6 +78,11 @@ export declare class RemoteHandler {
78
78
  options: Options;
79
79
  origin: FederationHost;
80
80
  }, false | void | Promise<false | void>>;
81
+ loadEntry: AsyncHook<[{
82
+ createScriptHook: FederationHost["loaderHook"]["lifecycle"]["createScript"];
83
+ remoteInfo: RemoteInfo;
84
+ remoteEntryExports?: RemoteEntryExports;
85
+ }], Promise<RemoteEntryExports>>;
81
86
  }>;
82
87
  constructor(host: FederationHost);
83
88
  formatAndRegisterRemote(globalOptions: Options, userOptions: UserOptions): Remote[];
@@ -1,23 +1,9 @@
1
- import { CreateScriptHookReturn } from '@module-federation/sdk';
1
+ import { FederationHost } from '../core';
2
2
  import { Remote, RemoteEntryExports, RemoteInfo } from '../type';
3
- export declare function loadEsmEntry({ entry, remoteEntryExports, }: {
4
- entry: string;
5
- remoteEntryExports: RemoteEntryExports | undefined;
6
- }): Promise<RemoteEntryExports>;
7
- export declare function loadSystemJsEntry({ entry, remoteEntryExports, }: {
8
- entry: string;
9
- remoteEntryExports: RemoteEntryExports | undefined;
10
- }): Promise<RemoteEntryExports>;
11
- export declare function loadEntryScript({ name, globalName, entry, createScriptHook, }: {
12
- name: string;
13
- globalName: string;
14
- entry: string;
15
- createScriptHook?: (url: string, attrs?: Record<string, any> | undefined) => CreateScriptHookReturn;
16
- }): Promise<RemoteEntryExports>;
17
3
  export declare function getRemoteEntryUniqueKey(remoteInfo: RemoteInfo): string;
18
- export declare function getRemoteEntry({ remoteEntryExports, remoteInfo, createScriptHook, }: {
4
+ export declare function getRemoteEntry({ origin, remoteEntryExports, remoteInfo, }: {
5
+ origin: FederationHost;
19
6
  remoteInfo: RemoteInfo;
20
7
  remoteEntryExports?: RemoteEntryExports | undefined;
21
- createScriptHook?: (url: string, attrs?: Record<string, any> | undefined) => CreateScriptHookReturn;
22
- }): Promise<RemoteEntryExports | void>;
8
+ }): Promise<RemoteEntryExports | false | void>;
23
9
  export declare function getRemoteInfo(remote: Remote): RemoteInfo;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/runtime",
3
- "version": "0.0.0-next-20240814085621",
3
+ "version": "0.0.0-next-20240815093707",
4
4
  "author": "zhouxiao <codingzx@gmail.com>",
5
5
  "main": "./dist/index.cjs.js",
6
6
  "module": "./dist/index.esm.js",
@@ -45,6 +45,6 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@module-federation/sdk": "0.0.0-next-20240814085621"
48
+ "@module-federation/sdk": "0.0.0-next-20240815093707"
49
49
  }
50
50
  }