@module-federation/runtime-core 0.23.0 → 0.24.1

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.esm.js CHANGED
@@ -200,7 +200,7 @@ function getGlobalFederationConstructor() {
200
200
  function setGlobalFederationConstructor(FederationConstructor, isDebug = isDebugMode()) {
201
201
  if (isDebug) {
202
202
  CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR__ = FederationConstructor;
203
- CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.23.0";
203
+ CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.24.1";
204
204
  }
205
205
  }
206
206
  // eslint-disable-next-line @typescript-eslint/ban-types
@@ -807,6 +807,9 @@ function formatShare(shareArgs, from, name, shareStrategy) {
807
807
  throw new Error(`Can not get shared '${name}'!`);
808
808
  });
809
809
  }
810
+ if (shareArgs.shareConfig?.eager && shareArgs.treeShaking) {
811
+ throw new Error('Can not set "eager:true" and "treeShaking" at the same time!');
812
+ }
810
813
  return {
811
814
  deps: [],
812
815
  useIn: [],
@@ -827,37 +830,67 @@ function formatShare(shareArgs, from, name, shareStrategy) {
827
830
  ? shareArgs.scope
828
831
  : [shareArgs.scope ?? 'default'],
829
832
  strategy: (shareArgs.strategy ?? shareStrategy) || 'version-first',
833
+ treeShaking: shareArgs.treeShaking
834
+ ? {
835
+ ...shareArgs.treeShaking,
836
+ mode: shareArgs.treeShaking.mode ?? 'server-calc',
837
+ status: shareArgs.treeShaking.status ?? 1 /* TreeShakingStatus.UNKNOWN */,
838
+ useIn: [],
839
+ }
840
+ : undefined,
830
841
  };
831
842
  }
832
- function formatShareConfigs(globalOptions, userOptions) {
833
- const shareArgs = userOptions.shared || {};
834
- const from = userOptions.name;
835
- const shareInfos = Object.keys(shareArgs).reduce((res, pkgName) => {
843
+ function formatShareConfigs(prevOptions, newOptions) {
844
+ const shareArgs = newOptions.shared || {};
845
+ const from = newOptions.name;
846
+ const newShareInfos = Object.keys(shareArgs).reduce((res, pkgName) => {
836
847
  const arrayShareArgs = arrayOptions(shareArgs[pkgName]);
837
848
  res[pkgName] = res[pkgName] || [];
838
849
  arrayShareArgs.forEach((shareConfig) => {
839
- res[pkgName].push(formatShare(shareConfig, from, pkgName, userOptions.shareStrategy));
850
+ res[pkgName].push(formatShare(shareConfig, from, pkgName, newOptions.shareStrategy));
840
851
  });
841
852
  return res;
842
853
  }, {});
843
- const shared = {
844
- ...globalOptions.shared,
854
+ const allShareInfos = {
855
+ ...prevOptions.shared,
845
856
  };
846
- Object.keys(shareInfos).forEach((shareKey) => {
847
- if (!shared[shareKey]) {
848
- shared[shareKey] = shareInfos[shareKey];
857
+ Object.keys(newShareInfos).forEach((shareKey) => {
858
+ if (!allShareInfos[shareKey]) {
859
+ allShareInfos[shareKey] = newShareInfos[shareKey];
849
860
  }
850
861
  else {
851
- shareInfos[shareKey].forEach((newUserSharedOptions) => {
852
- const isSameVersion = shared[shareKey].find((sharedVal) => sharedVal.version === newUserSharedOptions.version);
862
+ newShareInfos[shareKey].forEach((newUserSharedOptions) => {
863
+ const isSameVersion = allShareInfos[shareKey].find((sharedVal) => sharedVal.version === newUserSharedOptions.version);
853
864
  if (!isSameVersion) {
854
- shared[shareKey].push(newUserSharedOptions);
865
+ allShareInfos[shareKey].push(newUserSharedOptions);
855
866
  }
856
867
  });
857
868
  }
858
869
  });
859
- return { shared, shareInfos };
870
+ return { allShareInfos, newShareInfos };
860
871
  }
872
+ function shouldUseTreeShaking(treeShaking, usedExports) {
873
+ if (!treeShaking) {
874
+ return false;
875
+ }
876
+ const { status, mode } = treeShaking;
877
+ if (status === 0 /* TreeShakingStatus.NO_USE */) {
878
+ return false;
879
+ }
880
+ if (status === 2 /* TreeShakingStatus.CALCULATED */) {
881
+ return true;
882
+ }
883
+ if (mode === 'runtime-infer') {
884
+ if (!usedExports) {
885
+ return true;
886
+ }
887
+ return isMatchUsedExports(treeShaking, usedExports);
888
+ }
889
+ return false;
890
+ }
891
+ /**
892
+ * compare version a and b, return true if a is less than b
893
+ */
861
894
  function versionLt(a, b) {
862
895
  const transformInvalidVersion = (version) => {
863
896
  const isNumberVersion = !Number.isNaN(Number(version));
@@ -903,19 +936,79 @@ const isLoaded = (shared) => {
903
936
  const isLoading = (shared) => {
904
937
  return Boolean(shared.loading);
905
938
  };
906
- function findSingletonVersionOrderByVersion(shareScopeMap, scope, pkgName) {
939
+ const isMatchUsedExports = (treeShaking, usedExports) => {
940
+ if (!treeShaking || !usedExports) {
941
+ return false;
942
+ }
943
+ const { usedExports: treeShakingUsedExports } = treeShaking;
944
+ if (!treeShakingUsedExports) {
945
+ return false;
946
+ }
947
+ if (usedExports.every((e) => treeShakingUsedExports.includes(e))) {
948
+ return true;
949
+ }
950
+ return false;
951
+ };
952
+ function findSingletonVersionOrderByVersion(shareScopeMap, scope, pkgName, treeShaking) {
907
953
  const versions = shareScopeMap[scope][pkgName];
954
+ let version = '';
955
+ let useTreesShaking = shouldUseTreeShaking(treeShaking);
956
+ // return false means use prev version
908
957
  const callback = function (prev, cur) {
958
+ if (useTreesShaking) {
959
+ if (!versions[prev].treeShaking) {
960
+ return true;
961
+ }
962
+ if (!versions[cur].treeShaking) {
963
+ return false;
964
+ }
965
+ return !isLoaded(versions[prev].treeShaking) && versionLt(prev, cur);
966
+ }
909
967
  return !isLoaded(versions[prev]) && versionLt(prev, cur);
910
968
  };
911
- return findVersion(shareScopeMap[scope][pkgName], callback);
969
+ if (useTreesShaking) {
970
+ version = findVersion(shareScopeMap[scope][pkgName], callback);
971
+ if (version) {
972
+ return {
973
+ version,
974
+ useTreesShaking,
975
+ };
976
+ }
977
+ useTreesShaking = false;
978
+ }
979
+ return {
980
+ version: findVersion(shareScopeMap[scope][pkgName], callback),
981
+ useTreesShaking,
982
+ };
912
983
  }
913
- function findSingletonVersionOrderByLoaded(shareScopeMap, scope, pkgName) {
984
+ const isLoadingOrLoaded = (shared) => {
985
+ return isLoaded(shared) || isLoading(shared);
986
+ };
987
+ function findSingletonVersionOrderByLoaded(shareScopeMap, scope, pkgName, treeShaking) {
914
988
  const versions = shareScopeMap[scope][pkgName];
989
+ let version = '';
990
+ let useTreesShaking = shouldUseTreeShaking(treeShaking);
991
+ // return false means use prev version
915
992
  const callback = function (prev, cur) {
916
- const isLoadingOrLoaded = (shared) => {
917
- return isLoaded(shared) || isLoading(shared);
918
- };
993
+ if (useTreesShaking) {
994
+ if (!versions[prev].treeShaking) {
995
+ return true;
996
+ }
997
+ if (!versions[cur].treeShaking) {
998
+ return false;
999
+ }
1000
+ if (isLoadingOrLoaded(versions[cur].treeShaking)) {
1001
+ if (isLoadingOrLoaded(versions[prev].treeShaking)) {
1002
+ return Boolean(versionLt(prev, cur));
1003
+ }
1004
+ else {
1005
+ return true;
1006
+ }
1007
+ }
1008
+ if (isLoadingOrLoaded(versions[prev].treeShaking)) {
1009
+ return false;
1010
+ }
1011
+ }
919
1012
  if (isLoadingOrLoaded(versions[cur])) {
920
1013
  if (isLoadingOrLoaded(versions[prev])) {
921
1014
  return Boolean(versionLt(prev, cur));
@@ -929,7 +1022,20 @@ function findSingletonVersionOrderByLoaded(shareScopeMap, scope, pkgName) {
929
1022
  }
930
1023
  return versionLt(prev, cur);
931
1024
  };
932
- return findVersion(shareScopeMap[scope][pkgName], callback);
1025
+ if (useTreesShaking) {
1026
+ version = findVersion(shareScopeMap[scope][pkgName], callback);
1027
+ if (version) {
1028
+ return {
1029
+ version,
1030
+ useTreesShaking,
1031
+ };
1032
+ }
1033
+ useTreesShaking = false;
1034
+ }
1035
+ return {
1036
+ version: findVersion(shareScopeMap[scope][pkgName], callback),
1037
+ useTreesShaking,
1038
+ };
933
1039
  }
934
1040
  function getFindShareFunction(strategy) {
935
1041
  if (strategy === 'loaded-first') {
@@ -941,7 +1047,7 @@ function getRegisteredShare(localShareScopeMap, pkgName, shareInfo, resolveShare
941
1047
  if (!localShareScopeMap) {
942
1048
  return;
943
1049
  }
944
- const { shareConfig, scope = DEFAULT_SCOPE, strategy } = shareInfo;
1050
+ const { shareConfig, scope = DEFAULT_SCOPE, strategy, treeShaking, } = shareInfo;
945
1051
  const scopes = Array.isArray(scope) ? scope : [scope];
946
1052
  for (const sc of scopes) {
947
1053
  if (shareConfig &&
@@ -949,14 +1055,13 @@ function getRegisteredShare(localShareScopeMap, pkgName, shareInfo, resolveShare
949
1055
  localShareScopeMap[sc][pkgName]) {
950
1056
  const { requiredVersion } = shareConfig;
951
1057
  const findShareFunction = getFindShareFunction(strategy);
952
- const maxOrSingletonVersion = findShareFunction(localShareScopeMap, sc, pkgName);
953
- //@ts-ignore
1058
+ const { version: maxOrSingletonVersion, useTreesShaking } = findShareFunction(localShareScopeMap, sc, pkgName, treeShaking);
954
1059
  const defaultResolver = () => {
1060
+ const shared = localShareScopeMap[sc][pkgName][maxOrSingletonVersion];
955
1061
  if (shareConfig.singleton) {
956
1062
  if (typeof requiredVersion === 'string' &&
957
1063
  !satisfy(maxOrSingletonVersion, requiredVersion)) {
958
- const msg = `Version ${maxOrSingletonVersion} from ${maxOrSingletonVersion &&
959
- localShareScopeMap[sc][pkgName][maxOrSingletonVersion].from} of shared singleton module ${pkgName} does not satisfy the requirement of ${shareInfo.from} which needs ${requiredVersion})`;
1064
+ const msg = `Version ${maxOrSingletonVersion} from ${maxOrSingletonVersion && shared.from} of shared singleton module ${pkgName} does not satisfy the requirement of ${shareInfo.from} which needs ${requiredVersion})`;
960
1065
  if (shareConfig.strictVersion) {
961
1066
  error(msg);
962
1067
  }
@@ -964,21 +1069,48 @@ function getRegisteredShare(localShareScopeMap, pkgName, shareInfo, resolveShare
964
1069
  warn(msg);
965
1070
  }
966
1071
  }
967
- return localShareScopeMap[sc][pkgName][maxOrSingletonVersion];
1072
+ return {
1073
+ shared,
1074
+ useTreesShaking,
1075
+ };
968
1076
  }
969
1077
  else {
970
1078
  if (requiredVersion === false || requiredVersion === '*') {
971
- return localShareScopeMap[sc][pkgName][maxOrSingletonVersion];
1079
+ return {
1080
+ shared,
1081
+ useTreesShaking,
1082
+ };
972
1083
  }
973
1084
  if (satisfy(maxOrSingletonVersion, requiredVersion)) {
974
- return localShareScopeMap[sc][pkgName][maxOrSingletonVersion];
1085
+ return {
1086
+ shared,
1087
+ useTreesShaking,
1088
+ };
1089
+ }
1090
+ const _usedTreeShaking = shouldUseTreeShaking(treeShaking);
1091
+ if (_usedTreeShaking) {
1092
+ for (const [versionKey, versionValue] of Object.entries(localShareScopeMap[sc][pkgName])) {
1093
+ if (!shouldUseTreeShaking(versionValue.treeShaking, treeShaking?.usedExports)) {
1094
+ continue;
1095
+ }
1096
+ if (satisfy(versionKey, requiredVersion)) {
1097
+ return {
1098
+ shared: versionValue,
1099
+ useTreesShaking: _usedTreeShaking,
1100
+ };
1101
+ }
1102
+ }
975
1103
  }
976
1104
  for (const [versionKey, versionValue] of Object.entries(localShareScopeMap[sc][pkgName])) {
977
1105
  if (satisfy(versionKey, requiredVersion)) {
978
- return versionValue;
1106
+ return {
1107
+ shared: versionValue,
1108
+ useTreesShaking: false,
1109
+ };
979
1110
  }
980
1111
  }
981
1112
  }
1113
+ return;
982
1114
  };
983
1115
  const params = {
984
1116
  shareScopeMap: localShareScopeMap,
@@ -986,6 +1118,7 @@ function getRegisteredShare(localShareScopeMap, pkgName, shareInfo, resolveShare
986
1118
  pkgName,
987
1119
  version: maxOrSingletonVersion,
988
1120
  GlobalFederation: Global.__FEDERATION__,
1121
+ shareInfo,
989
1122
  resolver: defaultResolver,
990
1123
  };
991
1124
  const resolveShared = resolveShare.emit(params) || params;
@@ -1007,13 +1140,47 @@ function getTargetSharedOptions(options) {
1007
1140
  shareVersionMap[shared.version] = shared;
1008
1141
  });
1009
1142
  const callback = function (prev, cur) {
1010
- return !isLoaded(shareVersionMap[prev]) && versionLt(prev, cur);
1143
+ return (
1144
+ // TODO: consider multiple treeShaking shared scenes
1145
+ !isLoaded(shareVersionMap[prev]) && versionLt(prev, cur));
1011
1146
  };
1012
1147
  const maxVersion = findVersion(shareVersionMap, callback);
1013
1148
  return shareVersionMap[maxVersion];
1014
1149
  };
1015
1150
  const resolver = extraOptions?.resolver ?? defaultResolver;
1016
- return Object.assign({}, resolver(shareInfos[pkgName]), extraOptions?.customShareInfo);
1151
+ const isPlainObject = (val) => {
1152
+ return val !== null && typeof val === 'object' && !Array.isArray(val);
1153
+ };
1154
+ const merge = (...sources) => {
1155
+ const out = {};
1156
+ for (const src of sources) {
1157
+ if (!src)
1158
+ continue;
1159
+ for (const [key, value] of Object.entries(src)) {
1160
+ const prev = out[key];
1161
+ if (isPlainObject(prev) && isPlainObject(value)) {
1162
+ out[key] = merge(prev, value);
1163
+ }
1164
+ else if (value !== undefined) {
1165
+ out[key] = value;
1166
+ }
1167
+ }
1168
+ }
1169
+ return out;
1170
+ };
1171
+ return merge(resolver(shareInfos[pkgName]), extraOptions?.customShareInfo);
1172
+ }
1173
+ const addUseIn = (shared, from) => {
1174
+ if (!shared.useIn) {
1175
+ shared.useIn = [];
1176
+ }
1177
+ addUniqueItem(shared.useIn, from);
1178
+ };
1179
+ function directShare(shared, useTreesShaking) {
1180
+ if (useTreesShaking && shared.treeShaking) {
1181
+ return shared.treeShaking;
1182
+ }
1183
+ return shared;
1017
1184
  }
1018
1185
 
1019
1186
  function getBuilderId() {
@@ -1525,9 +1692,44 @@ var helpers = {
1525
1692
  },
1526
1693
  };
1527
1694
 
1695
+ function createRemoteEntryInitOptions(remoteInfo, hostShareScopeMap) {
1696
+ const localShareScopeMap = hostShareScopeMap;
1697
+ const shareScopeKeys = Array.isArray(remoteInfo.shareScope)
1698
+ ? remoteInfo.shareScope
1699
+ : [remoteInfo.shareScope];
1700
+ if (!shareScopeKeys.length) {
1701
+ shareScopeKeys.push('default');
1702
+ }
1703
+ shareScopeKeys.forEach((shareScopeKey) => {
1704
+ if (!localShareScopeMap[shareScopeKey]) {
1705
+ localShareScopeMap[shareScopeKey] = {};
1706
+ }
1707
+ });
1708
+ const remoteEntryInitOptions = {
1709
+ version: remoteInfo.version || '',
1710
+ shareScopeKeys: Array.isArray(remoteInfo.shareScope)
1711
+ ? shareScopeKeys
1712
+ : remoteInfo.shareScope || 'default',
1713
+ };
1714
+ // Help to find host instance
1715
+ Object.defineProperty(remoteEntryInitOptions, 'shareScopeMap', {
1716
+ value: localShareScopeMap,
1717
+ // remoteEntryInitOptions will be traversed and assigned during container init, ,so this attribute is not allowed to be traversed
1718
+ enumerable: false,
1719
+ });
1720
+ // TODO: compate legacy init params, should use shareScopeMap if exist
1721
+ const shareScope = localShareScopeMap[shareScopeKeys[0]];
1722
+ const initScope = [];
1723
+ return {
1724
+ remoteEntryInitOptions,
1725
+ shareScope,
1726
+ initScope,
1727
+ };
1728
+ }
1528
1729
  class Module {
1529
1730
  constructor({ remoteInfo, host, }) {
1530
1731
  this.inited = false;
1732
+ this.initing = false;
1531
1733
  this.lib = undefined;
1532
1734
  this.remoteInfo = remoteInfo;
1533
1735
  this.host = host;
@@ -1549,34 +1751,9 @@ class Module {
1549
1751
  async init(id, remoteSnapshot) {
1550
1752
  // Get remoteEntry.js
1551
1753
  const remoteEntryExports = await this.getEntry();
1552
- if (!this.inited) {
1553
- const localShareScopeMap = this.host.shareScopeMap;
1554
- const shareScopeKeys = Array.isArray(this.remoteInfo.shareScope)
1555
- ? this.remoteInfo.shareScope
1556
- : [this.remoteInfo.shareScope];
1557
- if (!shareScopeKeys.length) {
1558
- shareScopeKeys.push('default');
1559
- }
1560
- shareScopeKeys.forEach((shareScopeKey) => {
1561
- if (!localShareScopeMap[shareScopeKey]) {
1562
- localShareScopeMap[shareScopeKey] = {};
1563
- }
1564
- });
1565
- // TODO: compate legacy init params, should use shareScopeMap if exist
1566
- const shareScope = localShareScopeMap[shareScopeKeys[0]];
1567
- const initScope = [];
1568
- const remoteEntryInitOptions = {
1569
- version: this.remoteInfo.version || '',
1570
- shareScopeKeys: Array.isArray(this.remoteInfo.shareScope)
1571
- ? shareScopeKeys
1572
- : this.remoteInfo.shareScope || 'default',
1573
- };
1574
- // Help to find host instance
1575
- Object.defineProperty(remoteEntryInitOptions, 'shareScopeMap', {
1576
- value: localShareScopeMap,
1577
- // remoteEntryInitOptions will be traversed and assigned during container init, ,so this attribute is not allowed to be traversed
1578
- enumerable: false,
1579
- });
1754
+ if (!this.inited && !this.initing) {
1755
+ this.initing = true;
1756
+ const { remoteEntryInitOptions, shareScope, initScope } = createRemoteEntryInitOptions(this.remoteInfo, this.host.shareScopeMap);
1580
1757
  const initContainerOptions = await this.host.hooks.lifecycle.beforeInitContainer.emit({
1581
1758
  shareScope,
1582
1759
  // @ts-ignore shareScopeMap will be set by Object.defineProperty
@@ -1600,6 +1777,7 @@ class Module {
1600
1777
  remoteSnapshot,
1601
1778
  remoteEntryExports,
1602
1779
  });
1780
+ this.inited = true;
1603
1781
  }
1604
1782
  return remoteEntryExports;
1605
1783
  }
@@ -1608,7 +1786,6 @@ class Module {
1608
1786
  const { loadFactory = true } = options || { loadFactory: true };
1609
1787
  const remoteEntryExports = await this.init(id, remoteSnapshot);
1610
1788
  this.lib = remoteEntryExports;
1611
- this.inited = true;
1612
1789
  let moduleFactory;
1613
1790
  moduleFactory = await this.host.loaderHook.lifecycle.getModuleFactory.emit({
1614
1791
  remoteEntryExports,
@@ -2062,7 +2239,7 @@ function generatePreloadAssets(origin, preloadOptions, remote, globalSnapshot, r
2062
2239
  }, true, memo, remoteSnapshot);
2063
2240
  if (remoteSnapshot.shared && remoteSnapshot.shared.length > 0) {
2064
2241
  const collectSharedAssets = (shareInfo, snapshotShared) => {
2065
- const registeredShared = getRegisteredShare(origin.shareScopeMap, snapshotShared.sharedName, shareInfo, origin.sharedHandler.hooks.lifecycle.resolveShare);
2242
+ const { shared: registeredShared } = getRegisteredShare(origin.shareScopeMap, snapshotShared.sharedName, shareInfo, origin.sharedHandler.hooks.lifecycle.resolveShare) || {};
2066
2243
  // If the global share does not exist, or the lib function does not exist, it means that the shared has not been loaded yet and can be preloaded.
2067
2244
  if (registeredShared && typeof registeredShared.lib === 'function') {
2068
2245
  snapshotShared.assets.js.sync.forEach((asset) => {
@@ -2353,6 +2530,7 @@ class SnapshotHandler {
2353
2530
  class SharedHandler {
2354
2531
  constructor(host) {
2355
2532
  this.hooks = new PluginSystem({
2533
+ beforeRegisterShare: new SyncWaterfallHook('beforeRegisterShare'),
2356
2534
  afterResolve: new AsyncWaterfallHook('afterResolve'),
2357
2535
  beforeLoadShare: new AsyncWaterfallHook('beforeLoadShare'),
2358
2536
  // not used yet
@@ -2368,12 +2546,17 @@ class SharedHandler {
2368
2546
  }
2369
2547
  // register shared in shareScopeMap
2370
2548
  registerShared(globalOptions, userOptions) {
2371
- const { shareInfos, shared } = formatShareConfigs(globalOptions, userOptions);
2372
- const sharedKeys = Object.keys(shareInfos);
2549
+ const { newShareInfos, allShareInfos } = formatShareConfigs(globalOptions, userOptions);
2550
+ const sharedKeys = Object.keys(newShareInfos);
2373
2551
  sharedKeys.forEach((sharedKey) => {
2374
- const sharedVals = shareInfos[sharedKey];
2552
+ const sharedVals = newShareInfos[sharedKey];
2375
2553
  sharedVals.forEach((sharedVal) => {
2376
2554
  sharedVal.scope.forEach((sc) => {
2555
+ this.hooks.lifecycle.beforeRegisterShare.emit({
2556
+ origin: this.host,
2557
+ pkgName: sharedKey,
2558
+ shared: sharedVal,
2559
+ });
2377
2560
  const registeredShared = this.shareScopeMap[sc]?.[sharedKey];
2378
2561
  if (!registeredShared) {
2379
2562
  this.setShared({
@@ -2389,8 +2572,8 @@ class SharedHandler {
2389
2572
  });
2390
2573
  });
2391
2574
  return {
2392
- shareInfos,
2393
- shared,
2575
+ newShareInfos,
2576
+ allShareInfos,
2394
2577
  };
2395
2578
  }
2396
2579
  async loadShare(pkgName, extraOptions) {
@@ -2421,61 +2604,61 @@ class SharedHandler {
2421
2604
  const { shareInfo: shareOptionsRes } = loadShareRes;
2422
2605
  // Assert that shareInfoRes exists, if not, throw an error
2423
2606
  assert(shareOptionsRes, `Cannot find ${pkgName} Share in the ${host.options.name}. Please ensure that the ${pkgName} Share parameters have been injected`);
2424
- // Retrieve from cache
2425
- const registeredShared = getRegisteredShare(this.shareScopeMap, pkgName, shareOptionsRes, this.hooks.lifecycle.resolveShare);
2426
- const addUseIn = (shared) => {
2427
- if (!shared.useIn) {
2428
- shared.useIn = [];
2429
- }
2430
- addUniqueItem(shared.useIn, host.options.name);
2431
- };
2432
- if (registeredShared && registeredShared.lib) {
2433
- addUseIn(registeredShared);
2434
- return registeredShared.lib;
2435
- }
2436
- else if (registeredShared &&
2437
- registeredShared.loading &&
2438
- !registeredShared.loaded) {
2439
- const factory = await registeredShared.loading;
2440
- registeredShared.loaded = true;
2441
- if (!registeredShared.lib) {
2442
- registeredShared.lib = factory;
2443
- }
2444
- addUseIn(registeredShared);
2445
- return factory;
2446
- }
2447
- else if (registeredShared) {
2448
- const asyncLoadProcess = async () => {
2449
- const factory = await registeredShared.get();
2450
- addUseIn(registeredShared);
2451
- registeredShared.loaded = true;
2452
- registeredShared.lib = factory;
2607
+ const { shared: registeredShared, useTreesShaking } = getRegisteredShare(this.shareScopeMap, pkgName, shareOptionsRes, this.hooks.lifecycle.resolveShare) || {};
2608
+ if (registeredShared) {
2609
+ const targetShared = directShare(registeredShared, useTreesShaking);
2610
+ if (targetShared.lib) {
2611
+ addUseIn(targetShared, host.options.name);
2612
+ return targetShared.lib;
2613
+ }
2614
+ else if (targetShared.loading && !targetShared.loaded) {
2615
+ const factory = await targetShared.loading;
2616
+ targetShared.loaded = true;
2617
+ if (!targetShared.lib) {
2618
+ targetShared.lib = factory;
2619
+ }
2620
+ addUseIn(targetShared, host.options.name);
2453
2621
  return factory;
2454
- };
2455
- const loading = asyncLoadProcess();
2456
- this.setShared({
2457
- pkgName,
2458
- loaded: false,
2459
- shared: registeredShared,
2460
- from: host.options.name,
2461
- lib: null,
2462
- loading,
2463
- });
2464
- return loading;
2622
+ }
2623
+ else {
2624
+ const asyncLoadProcess = async () => {
2625
+ const factory = await targetShared.get();
2626
+ addUseIn(targetShared, host.options.name);
2627
+ targetShared.loaded = true;
2628
+ targetShared.lib = factory;
2629
+ return factory;
2630
+ };
2631
+ const loading = asyncLoadProcess();
2632
+ this.setShared({
2633
+ pkgName,
2634
+ loaded: false,
2635
+ shared: registeredShared,
2636
+ from: host.options.name,
2637
+ lib: null,
2638
+ loading,
2639
+ treeShaking: useTreesShaking
2640
+ ? targetShared
2641
+ : undefined,
2642
+ });
2643
+ return loading;
2644
+ }
2465
2645
  }
2466
2646
  else {
2467
2647
  if (extraOptions?.customShareInfo) {
2468
2648
  return false;
2469
2649
  }
2650
+ const _useTreeShaking = shouldUseTreeShaking(shareOptionsRes.treeShaking);
2651
+ const targetShared = directShare(shareOptionsRes, _useTreeShaking);
2470
2652
  const asyncLoadProcess = async () => {
2471
- const factory = await shareOptionsRes.get();
2472
- shareOptionsRes.lib = factory;
2473
- shareOptionsRes.loaded = true;
2474
- addUseIn(shareOptionsRes);
2475
- const gShared = getRegisteredShare(this.shareScopeMap, pkgName, shareOptionsRes, this.hooks.lifecycle.resolveShare);
2653
+ const factory = await targetShared.get();
2654
+ targetShared.lib = factory;
2655
+ targetShared.loaded = true;
2656
+ addUseIn(targetShared, host.options.name);
2657
+ const { shared: gShared, useTreesShaking: gUseTreeShaking } = getRegisteredShare(this.shareScopeMap, pkgName, shareOptionsRes, this.hooks.lifecycle.resolveShare) || {};
2476
2658
  if (gShared) {
2477
- gShared.lib = factory;
2478
- gShared.loaded = true;
2659
+ const targetGShared = directShare(gShared, gUseTreeShaking);
2660
+ targetGShared.lib = factory;
2661
+ targetGShared.loaded = true;
2479
2662
  gShared.from = shareOptionsRes.from;
2480
2663
  }
2481
2664
  return factory;
@@ -2488,6 +2671,9 @@ class SharedHandler {
2488
2671
  from: host.options.name,
2489
2672
  lib: null,
2490
2673
  loading,
2674
+ treeShaking: _useTreeShaking
2675
+ ? targetShared
2676
+ : undefined,
2491
2677
  });
2492
2678
  return loading;
2493
2679
  }
@@ -2527,15 +2713,17 @@ class SharedHandler {
2527
2713
  const { version, eager } = shared;
2528
2714
  scope[name] = scope[name] || {};
2529
2715
  const versions = scope[name];
2530
- const activeVersion = versions[version];
2716
+ const activeVersion = versions[version] && directShare(versions[version]);
2531
2717
  const activeVersionEager = Boolean(activeVersion &&
2532
- (activeVersion.eager || activeVersion.shareConfig?.eager));
2718
+ (('eager' in activeVersion && activeVersion.eager) ||
2719
+ ('shareConfig' in activeVersion &&
2720
+ activeVersion.shareConfig?.eager)));
2533
2721
  if (!activeVersion ||
2534
2722
  (activeVersion.strategy !== 'loaded-first' &&
2535
2723
  !activeVersion.loaded &&
2536
2724
  (Boolean(!eager) !== !activeVersionEager
2537
2725
  ? eager
2538
- : hostName > activeVersion.from))) {
2726
+ : hostName > versions[version].from))) {
2539
2727
  versions[version] = shared;
2540
2728
  }
2541
2729
  };
@@ -2543,7 +2731,26 @@ class SharedHandler {
2543
2731
  const { module } = await host.remoteHandler.getRemoteModuleAndOptions({
2544
2732
  id: key,
2545
2733
  });
2546
- await module.init();
2734
+ let remoteEntryExports = undefined;
2735
+ try {
2736
+ remoteEntryExports = await module.getEntry();
2737
+ }
2738
+ catch (error) {
2739
+ remoteEntryExports =
2740
+ (await host.remoteHandler.hooks.lifecycle.errorLoadRemote.emit({
2741
+ id: key,
2742
+ error,
2743
+ from: 'runtime',
2744
+ lifecycle: 'beforeLoadShare',
2745
+ origin: host,
2746
+ }));
2747
+ }
2748
+ finally {
2749
+ if (remoteEntryExports?.init) {
2750
+ module.remoteEntryExports = remoteEntryExports;
2751
+ await module.init();
2752
+ }
2753
+ }
2547
2754
  };
2548
2755
  Object.keys(host.options.shared).forEach((shareName) => {
2549
2756
  const sharedArr = host.options.shared[shareName];
@@ -2580,16 +2787,10 @@ class SharedHandler {
2580
2787
  this.initializeSharing(shareScope, { strategy: shareOptions.strategy });
2581
2788
  });
2582
2789
  }
2583
- const registeredShared = getRegisteredShare(this.shareScopeMap, pkgName, shareOptions, this.hooks.lifecycle.resolveShare);
2584
- const addUseIn = (shared) => {
2585
- if (!shared.useIn) {
2586
- shared.useIn = [];
2587
- }
2588
- addUniqueItem(shared.useIn, host.options.name);
2589
- };
2790
+ const { shared: registeredShared, useTreesShaking } = getRegisteredShare(this.shareScopeMap, pkgName, shareOptions, this.hooks.lifecycle.resolveShare) || {};
2590
2791
  if (registeredShared) {
2591
2792
  if (typeof registeredShared.lib === 'function') {
2592
- addUseIn(registeredShared);
2793
+ addUseIn(registeredShared, host.options.name);
2593
2794
  if (!registeredShared.loaded) {
2594
2795
  registeredShared.loaded = true;
2595
2796
  if (registeredShared.from === host.options.name) {
@@ -2601,7 +2802,7 @@ class SharedHandler {
2601
2802
  if (typeof registeredShared.get === 'function') {
2602
2803
  const module = registeredShared.get();
2603
2804
  if (!(module instanceof Promise)) {
2604
- addUseIn(registeredShared);
2805
+ addUseIn(registeredShared, host.options.name);
2605
2806
  this.setShared({
2606
2807
  pkgName,
2607
2808
  loaded: true,
@@ -2654,9 +2855,20 @@ class SharedHandler {
2654
2855
  hostShareScopeMap: extraOptions.hostShareScopeMap,
2655
2856
  });
2656
2857
  }
2657
- setShared({ pkgName, shared, from, lib, loading, loaded, get, }) {
2858
+ setShared({ pkgName, shared, from, lib, loading, loaded, get, treeShaking, }) {
2658
2859
  const { version, scope = 'default', ...shareInfo } = shared;
2659
2860
  const scopes = Array.isArray(scope) ? scope : [scope];
2861
+ const mergeAttrs = (shared) => {
2862
+ const merge = (s, key, val) => {
2863
+ if (val && !s[key]) {
2864
+ s[key] = val;
2865
+ }
2866
+ };
2867
+ const targetShared = (treeShaking ? shared.treeShaking : shared);
2868
+ merge(targetShared, 'loaded', loaded);
2869
+ merge(targetShared, 'loading', loading);
2870
+ merge(targetShared, 'get', get);
2871
+ };
2660
2872
  scopes.forEach((sc) => {
2661
2873
  if (!this.shareScopeMap[sc]) {
2662
2874
  this.shareScopeMap[sc] = {};
@@ -2670,21 +2882,10 @@ class SharedHandler {
2670
2882
  scope: [sc],
2671
2883
  ...shareInfo,
2672
2884
  lib,
2673
- loaded,
2674
- loading,
2675
2885
  };
2676
- if (get) {
2677
- this.shareScopeMap[sc][pkgName][version].get = get;
2678
- }
2679
- return;
2680
2886
  }
2681
2887
  const registeredShared = this.shareScopeMap[sc][pkgName][version];
2682
- if (loading && !registeredShared.loading) {
2683
- registeredShared.loading = loading;
2684
- }
2685
- if (loaded && !registeredShared.loaded) {
2686
- registeredShared.loaded = loaded;
2687
- }
2888
+ mergeAttrs(registeredShared);
2688
2889
  if (from && registeredShared.from !== from) {
2689
2890
  registeredShared.from = from;
2690
2891
  }
@@ -2712,6 +2913,7 @@ class RemoteHandler {
2712
2913
  generatePreloadAssets: new AsyncHook('generatePreloadAssets'),
2713
2914
  // not used yet
2714
2915
  afterPreloadRemote: new AsyncHook(),
2916
+ // TODO: Move to loaderHook
2715
2917
  loadEntry: new AsyncHook(),
2716
2918
  });
2717
2919
  this.host = host;
@@ -3060,7 +3262,7 @@ class ModuleFederation {
3060
3262
  // maybe will change, temporarily for internal use only
3061
3263
  initContainer: new AsyncWaterfallHook('initContainer'),
3062
3264
  });
3063
- this.version = "0.23.0";
3265
+ this.version = "0.24.1";
3064
3266
  this.moduleCache = new Map();
3065
3267
  this.loaderHook = new PluginSystem({
3066
3268
  // FIXME: may not be suitable , not open to the public yet
@@ -3141,7 +3343,7 @@ class ModuleFederation {
3141
3343
  this.sharedHandler.initShareScopeMap(scopeName, shareScope, extraOptions);
3142
3344
  }
3143
3345
  formatOptions(globalOptions, userOptions) {
3144
- const { shared } = formatShareConfigs(globalOptions, userOptions);
3346
+ const { allShareInfos: shared} = formatShareConfigs(globalOptions, userOptions);
3145
3347
  const { userOptions: userOptionsRes, options: globalOptionsRes } = this.hooks.lifecycle.beforeInit.emit({
3146
3348
  origin: this,
3147
3349
  userOptions,
@@ -3149,7 +3351,7 @@ class ModuleFederation {
3149
3351
  shareInfo: shared,
3150
3352
  });
3151
3353
  const remotes = this.remoteHandler.formatAndRegisterRemote(globalOptionsRes, userOptionsRes);
3152
- const { shared: handledShared } = this.sharedHandler.registerShared(globalOptionsRes, userOptionsRes);
3354
+ const { allShareInfos } = this.sharedHandler.registerShared(globalOptionsRes, userOptionsRes);
3153
3355
  const plugins = [...globalOptionsRes.plugins];
3154
3356
  if (userOptionsRes.plugins) {
3155
3357
  userOptionsRes.plugins.forEach((plugin) => {
@@ -3163,7 +3365,7 @@ class ModuleFederation {
3163
3365
  ...userOptions,
3164
3366
  plugins,
3165
3367
  remotes,
3166
- shared: handledShared,
3368
+ shared: allShareInfos,
3167
3369
  };
3168
3370
  this.hooks.lifecycle.init.emit({
3169
3371
  origin: this,