@module-federation/runtime-core 0.0.0-feat-rspack-async-startup-20251223091151 → 0.0.0-feat-shared-treeshake-poc-20251224120020

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.
@@ -201,7 +201,7 @@ function getGlobalFederationConstructor() {
201
201
  function setGlobalFederationConstructor(FederationConstructor, isDebug = sdk.isDebugMode()) {
202
202
  if (isDebug) {
203
203
  CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR__ = FederationConstructor;
204
- CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.0.0-feat-rspack-async-startup-20251223091151";
204
+ CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.0.0-feat-shared-treeshake-poc-20251224120020";
205
205
  }
206
206
  }
207
207
  // eslint-disable-next-line @typescript-eslint/ban-types
@@ -808,6 +808,9 @@ function formatShare(shareArgs, from, name, shareStrategy) {
808
808
  throw new Error(`Can not get shared '${name}'!`);
809
809
  });
810
810
  }
811
+ if (shareArgs.shareConfig?.eager && shareArgs.treeshake) {
812
+ throw new Error('Can not set "eager:true" and "treeshake" at the same time!');
813
+ }
811
814
  return {
812
815
  deps: [],
813
816
  useIn: [],
@@ -828,37 +831,67 @@ function formatShare(shareArgs, from, name, shareStrategy) {
828
831
  ? shareArgs.scope
829
832
  : [shareArgs.scope ?? 'default'],
830
833
  strategy: (shareArgs.strategy ?? shareStrategy) || 'version-first',
834
+ treeshake: shareArgs.treeshake
835
+ ? {
836
+ ...shareArgs.treeshake,
837
+ strategy: shareArgs.treeshake.strategy ?? 'server',
838
+ status: shareArgs.treeshake.status ?? 1 /* TreeshakeStatus.UNKNOWN */,
839
+ useIn: [],
840
+ }
841
+ : undefined,
831
842
  };
832
843
  }
833
- function formatShareConfigs(globalOptions, userOptions) {
834
- const shareArgs = userOptions.shared || {};
835
- const from = userOptions.name;
836
- const shareInfos = Object.keys(shareArgs).reduce((res, pkgName) => {
844
+ function formatShareConfigs(prevOptions, newOptions) {
845
+ const shareArgs = newOptions.shared || {};
846
+ const from = newOptions.name;
847
+ const newShareInfos = Object.keys(shareArgs).reduce((res, pkgName) => {
837
848
  const arrayShareArgs = arrayOptions(shareArgs[pkgName]);
838
849
  res[pkgName] = res[pkgName] || [];
839
850
  arrayShareArgs.forEach((shareConfig) => {
840
- res[pkgName].push(formatShare(shareConfig, from, pkgName, userOptions.shareStrategy));
851
+ res[pkgName].push(formatShare(shareConfig, from, pkgName, newOptions.shareStrategy));
841
852
  });
842
853
  return res;
843
854
  }, {});
844
- const shared = {
845
- ...globalOptions.shared,
855
+ const allShareInfos = {
856
+ ...prevOptions.shared,
846
857
  };
847
- Object.keys(shareInfos).forEach((shareKey) => {
848
- if (!shared[shareKey]) {
849
- shared[shareKey] = shareInfos[shareKey];
858
+ Object.keys(newShareInfos).forEach((shareKey) => {
859
+ if (!allShareInfos[shareKey]) {
860
+ allShareInfos[shareKey] = newShareInfos[shareKey];
850
861
  }
851
862
  else {
852
- shareInfos[shareKey].forEach((newUserSharedOptions) => {
853
- const isSameVersion = shared[shareKey].find((sharedVal) => sharedVal.version === newUserSharedOptions.version);
863
+ newShareInfos[shareKey].forEach((newUserSharedOptions) => {
864
+ const isSameVersion = allShareInfos[shareKey].find((sharedVal) => sharedVal.version === newUserSharedOptions.version);
854
865
  if (!isSameVersion) {
855
- shared[shareKey].push(newUserSharedOptions);
866
+ allShareInfos[shareKey].push(newUserSharedOptions);
856
867
  }
857
868
  });
858
869
  }
859
870
  });
860
- return { shared, shareInfos };
871
+ return { allShareInfos, newShareInfos };
861
872
  }
873
+ function shouldUseTreeshake(treeshake, usedExports) {
874
+ if (!treeshake) {
875
+ return false;
876
+ }
877
+ const { status, strategy } = treeshake;
878
+ if (status === 0 /* TreeshakeStatus.NO_USE */) {
879
+ return false;
880
+ }
881
+ if (status === 2 /* TreeshakeStatus.CALCULATED */) {
882
+ return true;
883
+ }
884
+ if (strategy === 'infer') {
885
+ if (!usedExports) {
886
+ return true;
887
+ }
888
+ return isMatchUsedExports(treeshake, usedExports);
889
+ }
890
+ return false;
891
+ }
892
+ /**
893
+ * compare version a and b, return true if a is less than b
894
+ */
862
895
  function versionLt(a, b) {
863
896
  const transformInvalidVersion = (version) => {
864
897
  const isNumberVersion = !Number.isNaN(Number(version));
@@ -904,19 +937,79 @@ const isLoaded = (shared) => {
904
937
  const isLoading = (shared) => {
905
938
  return Boolean(shared.loading);
906
939
  };
907
- function findSingletonVersionOrderByVersion(shareScopeMap, scope, pkgName) {
940
+ const isMatchUsedExports = (treeshake, usedExports) => {
941
+ if (!treeshake || !usedExports) {
942
+ return false;
943
+ }
944
+ const { usedExports: treeshakeUsedExports } = treeshake;
945
+ if (!treeshakeUsedExports) {
946
+ return false;
947
+ }
948
+ if (usedExports.every((e) => treeshakeUsedExports.includes(e))) {
949
+ return true;
950
+ }
951
+ return false;
952
+ };
953
+ function findSingletonVersionOrderByVersion(shareScopeMap, scope, pkgName, treeshake) {
908
954
  const versions = shareScopeMap[scope][pkgName];
955
+ let version = '';
956
+ let useTreeshake = shouldUseTreeshake(treeshake);
957
+ // return false means use prev version
909
958
  const callback = function (prev, cur) {
959
+ if (useTreeshake) {
960
+ if (!versions[prev].treeshake) {
961
+ return true;
962
+ }
963
+ if (!versions[cur].treeshake) {
964
+ return false;
965
+ }
966
+ return !isLoaded(versions[prev].treeshake) && versionLt(prev, cur);
967
+ }
910
968
  return !isLoaded(versions[prev]) && versionLt(prev, cur);
911
969
  };
912
- return findVersion(shareScopeMap[scope][pkgName], callback);
970
+ if (useTreeshake) {
971
+ version = findVersion(shareScopeMap[scope][pkgName], callback);
972
+ if (version) {
973
+ return {
974
+ version,
975
+ useTreeshake,
976
+ };
977
+ }
978
+ useTreeshake = false;
979
+ }
980
+ return {
981
+ version: findVersion(shareScopeMap[scope][pkgName], callback),
982
+ useTreeshake,
983
+ };
913
984
  }
914
- function findSingletonVersionOrderByLoaded(shareScopeMap, scope, pkgName) {
985
+ const isLoadingOrLoaded = (shared) => {
986
+ return isLoaded(shared) || isLoading(shared);
987
+ };
988
+ function findSingletonVersionOrderByLoaded(shareScopeMap, scope, pkgName, treeshake) {
915
989
  const versions = shareScopeMap[scope][pkgName];
990
+ let version = '';
991
+ let useTreeshake = shouldUseTreeshake(treeshake);
992
+ // return false means use prev version
916
993
  const callback = function (prev, cur) {
917
- const isLoadingOrLoaded = (shared) => {
918
- return isLoaded(shared) || isLoading(shared);
919
- };
994
+ if (useTreeshake) {
995
+ if (!versions[prev].treeshake) {
996
+ return true;
997
+ }
998
+ if (!versions[cur].treeshake) {
999
+ return false;
1000
+ }
1001
+ if (isLoadingOrLoaded(versions[cur].treeshake)) {
1002
+ if (isLoadingOrLoaded(versions[prev].treeshake)) {
1003
+ return Boolean(versionLt(prev, cur));
1004
+ }
1005
+ else {
1006
+ return true;
1007
+ }
1008
+ }
1009
+ if (isLoadingOrLoaded(versions[prev].treeshake)) {
1010
+ return false;
1011
+ }
1012
+ }
920
1013
  if (isLoadingOrLoaded(versions[cur])) {
921
1014
  if (isLoadingOrLoaded(versions[prev])) {
922
1015
  return Boolean(versionLt(prev, cur));
@@ -930,7 +1023,20 @@ function findSingletonVersionOrderByLoaded(shareScopeMap, scope, pkgName) {
930
1023
  }
931
1024
  return versionLt(prev, cur);
932
1025
  };
933
- return findVersion(shareScopeMap[scope][pkgName], callback);
1026
+ if (useTreeshake) {
1027
+ version = findVersion(shareScopeMap[scope][pkgName], callback);
1028
+ if (version) {
1029
+ return {
1030
+ version,
1031
+ useTreeshake,
1032
+ };
1033
+ }
1034
+ useTreeshake = false;
1035
+ }
1036
+ return {
1037
+ version: findVersion(shareScopeMap[scope][pkgName], callback),
1038
+ useTreeshake,
1039
+ };
934
1040
  }
935
1041
  function getFindShareFunction(strategy) {
936
1042
  if (strategy === 'loaded-first') {
@@ -942,7 +1048,7 @@ function getRegisteredShare(localShareScopeMap, pkgName, shareInfo, resolveShare
942
1048
  if (!localShareScopeMap) {
943
1049
  return;
944
1050
  }
945
- const { shareConfig, scope = DEFAULT_SCOPE, strategy } = shareInfo;
1051
+ const { shareConfig, scope = DEFAULT_SCOPE, strategy, treeshake } = shareInfo;
946
1052
  const scopes = Array.isArray(scope) ? scope : [scope];
947
1053
  for (const sc of scopes) {
948
1054
  if (shareConfig &&
@@ -950,14 +1056,13 @@ function getRegisteredShare(localShareScopeMap, pkgName, shareInfo, resolveShare
950
1056
  localShareScopeMap[sc][pkgName]) {
951
1057
  const { requiredVersion } = shareConfig;
952
1058
  const findShareFunction = getFindShareFunction(strategy);
953
- const maxOrSingletonVersion = findShareFunction(localShareScopeMap, sc, pkgName);
954
- //@ts-ignore
1059
+ const { version: maxOrSingletonVersion, useTreeshake } = findShareFunction(localShareScopeMap, sc, pkgName, treeshake);
955
1060
  const defaultResolver = () => {
1061
+ const shared = localShareScopeMap[sc][pkgName][maxOrSingletonVersion];
956
1062
  if (shareConfig.singleton) {
957
1063
  if (typeof requiredVersion === 'string' &&
958
1064
  !satisfy(maxOrSingletonVersion, requiredVersion)) {
959
- const msg = `Version ${maxOrSingletonVersion} from ${maxOrSingletonVersion &&
960
- localShareScopeMap[sc][pkgName][maxOrSingletonVersion].from} of shared singleton module ${pkgName} does not satisfy the requirement of ${shareInfo.from} which needs ${requiredVersion})`;
1065
+ const msg = `Version ${maxOrSingletonVersion} from ${maxOrSingletonVersion && shared.from} of shared singleton module ${pkgName} does not satisfy the requirement of ${shareInfo.from} which needs ${requiredVersion})`;
961
1066
  if (shareConfig.strictVersion) {
962
1067
  error(msg);
963
1068
  }
@@ -965,21 +1070,48 @@ function getRegisteredShare(localShareScopeMap, pkgName, shareInfo, resolveShare
965
1070
  warn(msg);
966
1071
  }
967
1072
  }
968
- return localShareScopeMap[sc][pkgName][maxOrSingletonVersion];
1073
+ return {
1074
+ shared,
1075
+ useTreeshake,
1076
+ };
969
1077
  }
970
1078
  else {
971
1079
  if (requiredVersion === false || requiredVersion === '*') {
972
- return localShareScopeMap[sc][pkgName][maxOrSingletonVersion];
1080
+ return {
1081
+ shared,
1082
+ useTreeshake,
1083
+ };
973
1084
  }
974
1085
  if (satisfy(maxOrSingletonVersion, requiredVersion)) {
975
- return localShareScopeMap[sc][pkgName][maxOrSingletonVersion];
1086
+ return {
1087
+ shared,
1088
+ useTreeshake,
1089
+ };
1090
+ }
1091
+ const _usedTreeshake = shouldUseTreeshake(treeshake);
1092
+ if (_usedTreeshake) {
1093
+ for (const [versionKey, versionValue] of Object.entries(localShareScopeMap[sc][pkgName])) {
1094
+ if (!shouldUseTreeshake(versionValue.treeshake, treeshake?.usedExports)) {
1095
+ continue;
1096
+ }
1097
+ if (satisfy(versionKey, requiredVersion)) {
1098
+ return {
1099
+ shared: versionValue,
1100
+ useTreeshake: _usedTreeshake,
1101
+ };
1102
+ }
1103
+ }
976
1104
  }
977
1105
  for (const [versionKey, versionValue] of Object.entries(localShareScopeMap[sc][pkgName])) {
978
1106
  if (satisfy(versionKey, requiredVersion)) {
979
- return versionValue;
1107
+ return {
1108
+ shared: versionValue,
1109
+ useTreeshake: false,
1110
+ };
980
1111
  }
981
1112
  }
982
1113
  }
1114
+ return;
983
1115
  };
984
1116
  const params = {
985
1117
  shareScopeMap: localShareScopeMap,
@@ -987,6 +1119,7 @@ function getRegisteredShare(localShareScopeMap, pkgName, shareInfo, resolveShare
987
1119
  pkgName,
988
1120
  version: maxOrSingletonVersion,
989
1121
  GlobalFederation: Global.__FEDERATION__,
1122
+ shareInfo,
990
1123
  resolver: defaultResolver,
991
1124
  };
992
1125
  const resolveShared = resolveShare.emit(params) || params;
@@ -1008,13 +1141,47 @@ function getTargetSharedOptions(options) {
1008
1141
  shareVersionMap[shared.version] = shared;
1009
1142
  });
1010
1143
  const callback = function (prev, cur) {
1011
- return !isLoaded(shareVersionMap[prev]) && versionLt(prev, cur);
1144
+ return (
1145
+ // TODO: consider multiple treeshake shared scenes
1146
+ !isLoaded(shareVersionMap[prev]) && versionLt(prev, cur));
1012
1147
  };
1013
1148
  const maxVersion = findVersion(shareVersionMap, callback);
1014
1149
  return shareVersionMap[maxVersion];
1015
1150
  };
1016
1151
  const resolver = extraOptions?.resolver ?? defaultResolver;
1017
- return Object.assign({}, resolver(shareInfos[pkgName]), extraOptions?.customShareInfo);
1152
+ const isPlainObject = (val) => {
1153
+ return val !== null && typeof val === 'object' && !Array.isArray(val);
1154
+ };
1155
+ const merge = (...sources) => {
1156
+ const out = {};
1157
+ for (const src of sources) {
1158
+ if (!src)
1159
+ continue;
1160
+ for (const [key, value] of Object.entries(src)) {
1161
+ const prev = out[key];
1162
+ if (isPlainObject(prev) && isPlainObject(value)) {
1163
+ out[key] = merge(prev, value);
1164
+ }
1165
+ else if (value !== undefined) {
1166
+ out[key] = value;
1167
+ }
1168
+ }
1169
+ }
1170
+ return out;
1171
+ };
1172
+ return merge(resolver(shareInfos[pkgName]), extraOptions?.customShareInfo);
1173
+ }
1174
+ const addUseIn = (shared, from) => {
1175
+ if (!shared.useIn) {
1176
+ shared.useIn = [];
1177
+ }
1178
+ addUniqueItem(shared.useIn, from);
1179
+ };
1180
+ function directShare(shared, useTreeshake) {
1181
+ if (useTreeshake && shared.treeshake) {
1182
+ return shared.treeshake;
1183
+ }
1184
+ return shared;
1018
1185
  }
1019
1186
 
1020
1187
  function getBuilderId() {
@@ -1526,6 +1693,40 @@ var helpers = {
1526
1693
  },
1527
1694
  };
1528
1695
 
1696
+ function createRemoteEntryInitOptions(remoteInfo, hostShareScopeMap) {
1697
+ const localShareScopeMap = hostShareScopeMap;
1698
+ const shareScopeKeys = Array.isArray(remoteInfo.shareScope)
1699
+ ? remoteInfo.shareScope
1700
+ : [remoteInfo.shareScope];
1701
+ if (!shareScopeKeys.length) {
1702
+ shareScopeKeys.push('default');
1703
+ }
1704
+ shareScopeKeys.forEach((shareScopeKey) => {
1705
+ if (!localShareScopeMap[shareScopeKey]) {
1706
+ localShareScopeMap[shareScopeKey] = {};
1707
+ }
1708
+ });
1709
+ const remoteEntryInitOptions = {
1710
+ version: remoteInfo.version || '',
1711
+ shareScopeKeys: Array.isArray(remoteInfo.shareScope)
1712
+ ? shareScopeKeys
1713
+ : remoteInfo.shareScope || 'default',
1714
+ };
1715
+ // Help to find host instance
1716
+ Object.defineProperty(remoteEntryInitOptions, 'shareScopeMap', {
1717
+ value: localShareScopeMap,
1718
+ // remoteEntryInitOptions will be traversed and assigned during container init, ,so this attribute is not allowed to be traversed
1719
+ enumerable: false,
1720
+ });
1721
+ // TODO: compate legacy init params, should use shareScopeMap if exist
1722
+ const shareScope = localShareScopeMap[shareScopeKeys[0]];
1723
+ const initScope = [];
1724
+ return {
1725
+ remoteEntryInitOptions,
1726
+ shareScope,
1727
+ initScope,
1728
+ };
1729
+ }
1529
1730
  class Module {
1530
1731
  constructor({ remoteInfo, host, }) {
1531
1732
  this.inited = false;
@@ -1537,8 +1738,7 @@ class Module {
1537
1738
  if (this.remoteEntryExports) {
1538
1739
  return this.remoteEntryExports;
1539
1740
  }
1540
- let remoteEntryExports;
1541
- remoteEntryExports = await getRemoteEntry({
1741
+ const remoteEntryExports = await getRemoteEntry({
1542
1742
  origin: this.host,
1543
1743
  remoteInfo: this.remoteInfo,
1544
1744
  remoteEntryExports: this.remoteEntryExports,
@@ -1553,33 +1753,7 @@ class Module {
1553
1753
  // Get remoteEntry.js
1554
1754
  const remoteEntryExports = await this.getEntry();
1555
1755
  if (!this.inited) {
1556
- const localShareScopeMap = this.host.shareScopeMap;
1557
- const shareScopeKeys = Array.isArray(this.remoteInfo.shareScope)
1558
- ? this.remoteInfo.shareScope
1559
- : [this.remoteInfo.shareScope];
1560
- if (!shareScopeKeys.length) {
1561
- shareScopeKeys.push('default');
1562
- }
1563
- shareScopeKeys.forEach((shareScopeKey) => {
1564
- if (!localShareScopeMap[shareScopeKey]) {
1565
- localShareScopeMap[shareScopeKey] = {};
1566
- }
1567
- });
1568
- // TODO: compate legacy init params, should use shareScopeMap if exist
1569
- const shareScope = localShareScopeMap[shareScopeKeys[0]];
1570
- const initScope = [];
1571
- const remoteEntryInitOptions = {
1572
- version: this.remoteInfo.version || '',
1573
- shareScopeKeys: Array.isArray(this.remoteInfo.shareScope)
1574
- ? shareScopeKeys
1575
- : this.remoteInfo.shareScope || 'default',
1576
- };
1577
- // Help to find host instance
1578
- Object.defineProperty(remoteEntryInitOptions, 'shareScopeMap', {
1579
- value: localShareScopeMap,
1580
- // remoteEntryInitOptions will be traversed and assigned during container init, ,so this attribute is not allowed to be traversed
1581
- enumerable: false,
1582
- });
1756
+ const { remoteEntryInitOptions, shareScope, initScope } = createRemoteEntryInitOptions(this.remoteInfo, this.host.shareScopeMap);
1583
1757
  const initContainerOptions = await this.host.hooks.lifecycle.beforeInitContainer.emit({
1584
1758
  shareScope,
1585
1759
  // @ts-ignore shareScopeMap will be set by Object.defineProperty
@@ -2059,7 +2233,7 @@ function generatePreloadAssets(origin, preloadOptions, remote, globalSnapshot, r
2059
2233
  }, true, memo, remoteSnapshot);
2060
2234
  if (remoteSnapshot.shared && remoteSnapshot.shared.length > 0) {
2061
2235
  const collectSharedAssets = (shareInfo, snapshotShared) => {
2062
- const registeredShared = getRegisteredShare(origin.shareScopeMap, snapshotShared.sharedName, shareInfo, origin.sharedHandler.hooks.lifecycle.resolveShare);
2236
+ const { shared: registeredShared } = getRegisteredShare(origin.shareScopeMap, snapshotShared.sharedName, shareInfo, origin.sharedHandler.hooks.lifecycle.resolveShare) || {};
2063
2237
  // 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.
2064
2238
  if (registeredShared && typeof registeredShared.lib === 'function') {
2065
2239
  snapshotShared.assets.js.sync.forEach((asset) => {
@@ -2350,6 +2524,7 @@ class SnapshotHandler {
2350
2524
  class SharedHandler {
2351
2525
  constructor(host) {
2352
2526
  this.hooks = new PluginSystem({
2527
+ beforeRegisterShare: new SyncWaterfallHook('beforeRegisterShare'),
2353
2528
  afterResolve: new AsyncWaterfallHook('afterResolve'),
2354
2529
  beforeLoadShare: new AsyncWaterfallHook('beforeLoadShare'),
2355
2530
  // not used yet
@@ -2365,12 +2540,17 @@ class SharedHandler {
2365
2540
  }
2366
2541
  // register shared in shareScopeMap
2367
2542
  registerShared(globalOptions, userOptions) {
2368
- const { shareInfos, shared } = formatShareConfigs(globalOptions, userOptions);
2369
- const sharedKeys = Object.keys(shareInfos);
2543
+ const { newShareInfos, allShareInfos } = formatShareConfigs(globalOptions, userOptions);
2544
+ const sharedKeys = Object.keys(newShareInfos);
2370
2545
  sharedKeys.forEach((sharedKey) => {
2371
- const sharedVals = shareInfos[sharedKey];
2546
+ const sharedVals = newShareInfos[sharedKey];
2372
2547
  sharedVals.forEach((sharedVal) => {
2373
2548
  sharedVal.scope.forEach((sc) => {
2549
+ this.hooks.lifecycle.beforeRegisterShare.emit({
2550
+ origin: this.host,
2551
+ pkgName: sharedKey,
2552
+ shared: sharedVal,
2553
+ });
2374
2554
  const registeredShared = this.shareScopeMap[sc]?.[sharedKey];
2375
2555
  if (!registeredShared) {
2376
2556
  this.setShared({
@@ -2386,8 +2566,8 @@ class SharedHandler {
2386
2566
  });
2387
2567
  });
2388
2568
  return {
2389
- shareInfos,
2390
- shared,
2569
+ newShareInfos,
2570
+ allShareInfos,
2391
2571
  };
2392
2572
  }
2393
2573
  async loadShare(pkgName, extraOptions) {
@@ -2418,61 +2598,59 @@ class SharedHandler {
2418
2598
  const { shareInfo: shareOptionsRes } = loadShareRes;
2419
2599
  // Assert that shareInfoRes exists, if not, throw an error
2420
2600
  assert(shareOptionsRes, `Cannot find ${pkgName} Share in the ${host.options.name}. Please ensure that the ${pkgName} Share parameters have been injected`);
2421
- // Retrieve from cache
2422
- const registeredShared = getRegisteredShare(this.shareScopeMap, pkgName, shareOptionsRes, this.hooks.lifecycle.resolveShare);
2423
- const addUseIn = (shared) => {
2424
- if (!shared.useIn) {
2425
- shared.useIn = [];
2426
- }
2427
- addUniqueItem(shared.useIn, host.options.name);
2428
- };
2429
- if (registeredShared && registeredShared.lib) {
2430
- addUseIn(registeredShared);
2431
- return registeredShared.lib;
2432
- }
2433
- else if (registeredShared &&
2434
- registeredShared.loading &&
2435
- !registeredShared.loaded) {
2436
- const factory = await registeredShared.loading;
2437
- registeredShared.loaded = true;
2438
- if (!registeredShared.lib) {
2439
- registeredShared.lib = factory;
2440
- }
2441
- addUseIn(registeredShared);
2442
- return factory;
2443
- }
2444
- else if (registeredShared) {
2445
- const asyncLoadProcess = async () => {
2446
- const factory = await registeredShared.get();
2447
- addUseIn(registeredShared);
2448
- registeredShared.loaded = true;
2449
- registeredShared.lib = factory;
2601
+ const { shared: registeredShared, useTreeshake } = getRegisteredShare(this.shareScopeMap, pkgName, shareOptionsRes, this.hooks.lifecycle.resolveShare) || {};
2602
+ if (registeredShared) {
2603
+ const targetShared = directShare(registeredShared, useTreeshake);
2604
+ if (targetShared.lib) {
2605
+ addUseIn(targetShared, host.options.name);
2606
+ return targetShared.lib;
2607
+ }
2608
+ else if (targetShared.loading && !targetShared.loaded) {
2609
+ const factory = await targetShared.loading;
2610
+ targetShared.loaded = true;
2611
+ if (!targetShared.lib) {
2612
+ targetShared.lib = factory;
2613
+ }
2614
+ addUseIn(targetShared, host.options.name);
2450
2615
  return factory;
2451
- };
2452
- const loading = asyncLoadProcess();
2453
- this.setShared({
2454
- pkgName,
2455
- loaded: false,
2456
- shared: registeredShared,
2457
- from: host.options.name,
2458
- lib: null,
2459
- loading,
2460
- });
2461
- return loading;
2616
+ }
2617
+ else {
2618
+ const asyncLoadProcess = async () => {
2619
+ const factory = await targetShared.get();
2620
+ addUseIn(targetShared, host.options.name);
2621
+ targetShared.loaded = true;
2622
+ targetShared.lib = factory;
2623
+ return factory;
2624
+ };
2625
+ const loading = asyncLoadProcess();
2626
+ this.setShared({
2627
+ pkgName,
2628
+ loaded: false,
2629
+ shared: registeredShared,
2630
+ from: host.options.name,
2631
+ lib: null,
2632
+ loading,
2633
+ treeshake: useTreeshake ? targetShared : undefined,
2634
+ });
2635
+ return loading;
2636
+ }
2462
2637
  }
2463
2638
  else {
2464
2639
  if (extraOptions?.customShareInfo) {
2465
2640
  return false;
2466
2641
  }
2642
+ const _useTreeshake = shouldUseTreeshake(shareOptionsRes.treeshake);
2643
+ const targetShared = directShare(shareOptionsRes, _useTreeshake);
2467
2644
  const asyncLoadProcess = async () => {
2468
- const factory = await shareOptionsRes.get();
2469
- shareOptionsRes.lib = factory;
2470
- shareOptionsRes.loaded = true;
2471
- addUseIn(shareOptionsRes);
2472
- const gShared = getRegisteredShare(this.shareScopeMap, pkgName, shareOptionsRes, this.hooks.lifecycle.resolveShare);
2645
+ const factory = await targetShared.get();
2646
+ targetShared.lib = factory;
2647
+ targetShared.loaded = true;
2648
+ addUseIn(targetShared, host.options.name);
2649
+ const { shared: gShared, useTreeshake: gUseTreeshake } = getRegisteredShare(this.shareScopeMap, pkgName, shareOptionsRes, this.hooks.lifecycle.resolveShare) || {};
2473
2650
  if (gShared) {
2474
- gShared.lib = factory;
2475
- gShared.loaded = true;
2651
+ const targetGShared = directShare(gShared, gUseTreeshake);
2652
+ targetGShared.lib = factory;
2653
+ targetGShared.loaded = true;
2476
2654
  gShared.from = shareOptionsRes.from;
2477
2655
  }
2478
2656
  return factory;
@@ -2485,6 +2663,7 @@ class SharedHandler {
2485
2663
  from: host.options.name,
2486
2664
  lib: null,
2487
2665
  loading,
2666
+ treeshake: _useTreeshake ? targetShared : undefined,
2488
2667
  });
2489
2668
  return loading;
2490
2669
  }
@@ -2524,19 +2703,20 @@ class SharedHandler {
2524
2703
  const { version, eager } = shared;
2525
2704
  scope[name] = scope[name] || {};
2526
2705
  const versions = scope[name];
2527
- const activeVersion = versions[version];
2706
+ const activeVersion = versions[version] && directShare(versions[version]);
2528
2707
  const activeVersionEager = Boolean(activeVersion &&
2529
- (activeVersion.eager || activeVersion.shareConfig?.eager));
2708
+ (('eager' in activeVersion && activeVersion.eager) ||
2709
+ ('shareConfig' in activeVersion &&
2710
+ activeVersion.shareConfig?.eager)));
2530
2711
  if (!activeVersion ||
2531
2712
  (activeVersion.strategy !== 'loaded-first' &&
2532
2713
  !activeVersion.loaded &&
2533
2714
  (Boolean(!eager) !== !activeVersionEager
2534
2715
  ? eager
2535
- : hostName > activeVersion.from))) {
2716
+ : hostName > versions[version].from))) {
2536
2717
  versions[version] = shared;
2537
2718
  }
2538
2719
  };
2539
- const initFn = (mod) => mod && mod.init && mod.init(shareScope[shareScopeName], initScope);
2540
2720
  const initRemoteModule = async (key) => {
2541
2721
  const { module } = await host.remoteHandler.getRemoteModuleAndOptions({
2542
2722
  id: key,
@@ -2557,6 +2737,12 @@ class SharedHandler {
2557
2737
  }));
2558
2738
  }
2559
2739
  if (!module.inited) {
2740
+ const initFn = (mod) => {
2741
+ const { remoteEntryInitOptions } = createRemoteEntryInitOptions(module.remoteInfo, host.shareScopeMap);
2742
+ return (mod &&
2743
+ mod.init &&
2744
+ mod.init(shareScope[shareScopeName], initScope, remoteEntryInitOptions));
2745
+ };
2560
2746
  await initFn(remoteEntryExports);
2561
2747
  module.inited = true;
2562
2748
  }
@@ -2597,16 +2783,10 @@ class SharedHandler {
2597
2783
  this.initializeSharing(shareScope, { strategy: shareOptions.strategy });
2598
2784
  });
2599
2785
  }
2600
- const registeredShared = getRegisteredShare(this.shareScopeMap, pkgName, shareOptions, this.hooks.lifecycle.resolveShare);
2601
- const addUseIn = (shared) => {
2602
- if (!shared.useIn) {
2603
- shared.useIn = [];
2604
- }
2605
- addUniqueItem(shared.useIn, host.options.name);
2606
- };
2786
+ const { shared: registeredShared, useTreeshake } = getRegisteredShare(this.shareScopeMap, pkgName, shareOptions, this.hooks.lifecycle.resolveShare) || {};
2607
2787
  if (registeredShared) {
2608
2788
  if (typeof registeredShared.lib === 'function') {
2609
- addUseIn(registeredShared);
2789
+ addUseIn(registeredShared, host.options.name);
2610
2790
  if (!registeredShared.loaded) {
2611
2791
  registeredShared.loaded = true;
2612
2792
  if (registeredShared.from === host.options.name) {
@@ -2618,7 +2798,7 @@ class SharedHandler {
2618
2798
  if (typeof registeredShared.get === 'function') {
2619
2799
  const module = registeredShared.get();
2620
2800
  if (!(module instanceof Promise)) {
2621
- addUseIn(registeredShared);
2801
+ addUseIn(registeredShared, host.options.name);
2622
2802
  this.setShared({
2623
2803
  pkgName,
2624
2804
  loaded: true,
@@ -2662,6 +2842,39 @@ class SharedHandler {
2662
2842
  }
2663
2843
  initShareScopeMap(scopeName, shareScope, extraOptions = {}) {
2664
2844
  const { host } = this;
2845
+ // const existedShareScope = this.shareScopeMap[scopeName];
2846
+ // if (existedShareScope) {
2847
+ // Object.entries(shareScope).forEach(([pkgName, newVersions]) => {
2848
+ // const existedShareMap = existedShareScope[pkgName];
2849
+ // if (!existedShareMap) {
2850
+ // return;
2851
+ // }
2852
+ // Object.entries(existedShareMap).forEach(([version, existedShared]) => {
2853
+ // if (!shareScope[pkgName][version]) {
2854
+ // shareScope[pkgName][version] = existedShared;
2855
+ // }
2856
+ // // const newShared = newVersions[version];
2857
+ // // if (
2858
+ // // newShared &&
2859
+ // // newShared.treeshakeStatus === TreeshakeStatus.UNKNOWN &&
2860
+ // // newShared.usedExports &&
2861
+ // // existedShared.usedExports &&
2862
+ // // existedShared.usedExports.some(
2863
+ // // (exportName) => !newShared.usedExports?.includes(exportName),
2864
+ // // )
2865
+ // // ) {
2866
+ // // newShared.treeshakeStatus = TreeshakeStatus.NO_USE;
2867
+ // // newShared._noMatchedUsedExports =
2868
+ // // existedShared._noMatchedUsedExports || [];
2869
+ // // const item: NoMatchedUsedExportsItem = [existedShared.from];
2870
+ // // if (isDebugMode() && existedShared.usedExports) {
2871
+ // // item.push(existedShared.usedExports);
2872
+ // // }
2873
+ // // newShared._noMatchedUsedExports.push(item);
2874
+ // // }
2875
+ // });
2876
+ // });
2877
+ // }
2665
2878
  this.shareScopeMap[scopeName] = shareScope;
2666
2879
  this.hooks.lifecycle.initContainerShareScopeMap.emit({
2667
2880
  shareScope,
@@ -2671,9 +2884,20 @@ class SharedHandler {
2671
2884
  hostShareScopeMap: extraOptions.hostShareScopeMap,
2672
2885
  });
2673
2886
  }
2674
- setShared({ pkgName, shared, from, lib, loading, loaded, get, }) {
2887
+ setShared({ pkgName, shared, from, lib, loading, loaded, get, treeshake, }) {
2675
2888
  const { version, scope = 'default', ...shareInfo } = shared;
2676
2889
  const scopes = Array.isArray(scope) ? scope : [scope];
2890
+ const mergeAttrs = (shared) => {
2891
+ const merge = (s, key, val) => {
2892
+ if (val && !s[key]) {
2893
+ s[key] = val;
2894
+ }
2895
+ };
2896
+ const targetShared = (treeshake ? shared.treeshake : shared);
2897
+ merge(targetShared, 'loaded', loaded);
2898
+ merge(targetShared, 'loading', loading);
2899
+ merge(targetShared, 'get', get);
2900
+ };
2677
2901
  scopes.forEach((sc) => {
2678
2902
  if (!this.shareScopeMap[sc]) {
2679
2903
  this.shareScopeMap[sc] = {};
@@ -2687,21 +2911,10 @@ class SharedHandler {
2687
2911
  scope: [sc],
2688
2912
  ...shareInfo,
2689
2913
  lib,
2690
- loaded,
2691
- loading,
2692
2914
  };
2693
- if (get) {
2694
- this.shareScopeMap[sc][pkgName][version].get = get;
2695
- }
2696
- return;
2697
2915
  }
2698
2916
  const registeredShared = this.shareScopeMap[sc][pkgName][version];
2699
- if (loading && !registeredShared.loading) {
2700
- registeredShared.loading = loading;
2701
- }
2702
- if (loaded && !registeredShared.loaded) {
2703
- registeredShared.loaded = loaded;
2704
- }
2917
+ mergeAttrs(registeredShared);
2705
2918
  if (from && registeredShared.from !== from) {
2706
2919
  registeredShared.from = from;
2707
2920
  }
@@ -2729,6 +2942,7 @@ class RemoteHandler {
2729
2942
  generatePreloadAssets: new AsyncHook('generatePreloadAssets'),
2730
2943
  // not used yet
2731
2944
  afterPreloadRemote: new AsyncHook(),
2945
+ // TODO: Move to loaderHook
2732
2946
  loadEntry: new AsyncHook(),
2733
2947
  });
2734
2948
  this.host = host;
@@ -3077,7 +3291,7 @@ class ModuleFederation {
3077
3291
  // maybe will change, temporarily for internal use only
3078
3292
  initContainer: new AsyncWaterfallHook('initContainer'),
3079
3293
  });
3080
- this.version = "0.0.0-feat-rspack-async-startup-20251223091151";
3294
+ this.version = "0.0.0-feat-shared-treeshake-poc-20251224120020";
3081
3295
  this.moduleCache = new Map();
3082
3296
  this.loaderHook = new PluginSystem({
3083
3297
  // FIXME: may not be suitable , not open to the public yet
@@ -3158,7 +3372,7 @@ class ModuleFederation {
3158
3372
  this.sharedHandler.initShareScopeMap(scopeName, shareScope, extraOptions);
3159
3373
  }
3160
3374
  formatOptions(globalOptions, userOptions) {
3161
- const { shared } = formatShareConfigs(globalOptions, userOptions);
3375
+ const { allShareInfos: shared} = formatShareConfigs(globalOptions, userOptions);
3162
3376
  const { userOptions: userOptionsRes, options: globalOptionsRes } = this.hooks.lifecycle.beforeInit.emit({
3163
3377
  origin: this,
3164
3378
  userOptions,
@@ -3166,7 +3380,7 @@ class ModuleFederation {
3166
3380
  shareInfo: shared,
3167
3381
  });
3168
3382
  const remotes = this.remoteHandler.formatAndRegisterRemote(globalOptionsRes, userOptionsRes);
3169
- const { shared: handledShared } = this.sharedHandler.registerShared(globalOptionsRes, userOptionsRes);
3383
+ const { allShareInfos } = this.sharedHandler.registerShared(globalOptionsRes, userOptionsRes);
3170
3384
  const plugins = [...globalOptionsRes.plugins];
3171
3385
  if (userOptionsRes.plugins) {
3172
3386
  userOptionsRes.plugins.forEach((plugin) => {
@@ -3180,7 +3394,7 @@ class ModuleFederation {
3180
3394
  ...userOptions,
3181
3395
  plugins,
3182
3396
  remotes,
3183
- shared: handledShared,
3397
+ shared: allShareInfos,
3184
3398
  };
3185
3399
  this.hooks.lifecycle.init.emit({
3186
3400
  origin: this,