webpack 5.90.2 → 5.90.3

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.

Potentially problematic release.


This version of webpack might be problematic. Click here for more details.

@@ -34,18 +34,15 @@ const { getEntryRuntime, mergeRuntime } = require("./util/runtime");
34
34
  * @property {ChunkGroupInfo} chunkGroupInfo
35
35
  */
36
36
 
37
- /** @typedef {Set<Module> & { plus: Set<Module> }} ModuleSetPlus */
38
-
39
37
  /**
40
38
  * @typedef {Object} ChunkGroupInfo
41
39
  * @property {ChunkGroup} chunkGroup the chunk group
42
40
  * @property {RuntimeSpec} runtime the runtimes
43
- * @property {ModuleSetPlus | undefined} minAvailableModules current minimal set of modules available at this point
44
- * @property {boolean | undefined} minAvailableModulesOwned true, if minAvailableModules is owned and can be modified
45
- * @property {ModuleSetPlus[]} availableModulesToBeMerged enqueued updates to the minimal set of available modules
41
+ * @property {bigint | undefined} minAvailableModules current minimal set of modules available at this point
42
+ * @property {bigint[]} availableModulesToBeMerged enqueued updates to the minimal set of available modules
46
43
  * @property {Set<Module>=} skippedItems modules that were skipped because module is already available in parent chunks (need to reconsider when minAvailableModules is shrinking)
47
44
  * @property {Set<[Module, ModuleGraphConnection[]]>=} skippedModuleConnections referenced modules that where skipped because they were not active in this runtime
48
- * @property {ModuleSetPlus | undefined} resultingAvailableModules set of modules available including modules from this chunk group
45
+ * @property {bigint | undefined} resultingAvailableModules set of modules available including modules from this chunk group
49
46
  * @property {Set<ChunkGroupInfo> | undefined} children set of children chunk groups, that will be revisited when availableModules shrink
50
47
  * @property {Set<ChunkGroupInfo> | undefined} availableSources set of chunk groups that are the source for minAvailableModules
51
48
  * @property {Set<ChunkGroupInfo> | undefined} availableChildren set of chunk groups which depend on the this chunk group as availableSource
@@ -61,17 +58,16 @@ const { getEntryRuntime, mergeRuntime } = require("./util/runtime");
61
58
  * @property {ChunkGroup} chunkGroup referenced chunk group
62
59
  */
63
60
 
64
- const EMPTY_SET = /** @type {ModuleSetPlus} */ (new Set());
65
- EMPTY_SET.plus = EMPTY_SET;
61
+ const ZERO_BIGINT = BigInt(0);
62
+ const ONE_BIGINT = BigInt(1);
66
63
 
67
64
  /**
68
- * @param {ModuleSetPlus} a first set
69
- * @param {ModuleSetPlus} b second set
70
- * @returns {number} cmp
65
+ * @param {bigint} mask The mask to test
66
+ * @param {number} ordinal The ordinal of the bit to test
67
+ * @returns {boolean} If the ordinal-th bit is set in the mask
71
68
  */
72
- const bySetSize = (a, b) => {
73
- return b.size + b.plus.size - a.size - a.plus.size;
74
- };
69
+ const isOrdinalSetInMask = (mask, ordinal) =>
70
+ BigInt.asUintN(1, mask >> BigInt(ordinal)) !== ZERO_BIGINT;
75
71
 
76
72
  /**
77
73
  * @param {ModuleGraphConnection[]} connections list of connections
@@ -209,6 +205,7 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
209
205
  * @param {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} blockConnections connection for blocks
210
206
  * @param {Set<DependenciesBlock>} blocksWithNestedBlocks flag for blocks that have nested blocks
211
207
  * @param {Set<ChunkGroup>} allCreatedChunkGroups filled with all chunk groups that are created here
208
+ * @param {Map<Chunk, bigint>} maskByChunk module content mask by chunk
212
209
  */
213
210
  const visitModules = (
214
211
  logger,
@@ -217,7 +214,8 @@ const visitModules = (
217
214
  chunkGroupInfoMap,
218
215
  blockConnections,
219
216
  blocksWithNestedBlocks,
220
- allCreatedChunkGroups
217
+ allCreatedChunkGroups,
218
+ maskByChunk
221
219
  ) => {
222
220
  const { moduleGraph, chunkGraph, moduleMemCaches } = compilation;
223
221
 
@@ -228,6 +226,30 @@ const visitModules = (
228
226
  /** @type {Map<DependenciesBlock, (Module | ConnectionState)[]>} */
229
227
  let blockModulesMap;
230
228
 
229
+ /** @type {Map<Module, number>} */
230
+ const ordinalByModule = new Map();
231
+
232
+ /**
233
+ * @param {Module} module The module to look up
234
+ * @returns {number} The ordinal of the module in masks
235
+ */
236
+ const getModuleOrdinal = module => {
237
+ let ordinal = ordinalByModule.get(module);
238
+ if (ordinal === undefined) {
239
+ ordinal = ordinalByModule.size;
240
+ ordinalByModule.set(module, ordinal);
241
+ }
242
+ return ordinal;
243
+ };
244
+
245
+ for (const chunk of compilation.chunks) {
246
+ let mask = ZERO_BIGINT;
247
+ for (const m of chunkGraph.getChunkModulesIterable(chunk)) {
248
+ mask |= ONE_BIGINT << BigInt(getModuleOrdinal(m));
249
+ }
250
+ maskByChunk.set(chunk, mask);
251
+ }
252
+
231
253
  /**
232
254
  *
233
255
  * @param {DependenciesBlock} block block
@@ -331,7 +353,6 @@ const visitModules = (
331
353
  chunkGroup,
332
354
  runtime,
333
355
  minAvailableModules: undefined,
334
- minAvailableModulesOwned: false,
335
356
  availableModulesToBeMerged: [],
336
357
  skippedItems: undefined,
337
358
  resultingAvailableModules: undefined,
@@ -354,15 +375,12 @@ const visitModules = (
354
375
  // minAvailableModules for child entrypoints are unknown yet, set to undefined.
355
376
  // This means no module is added until other sets are merged into
356
377
  // this minAvailableModules (by the parent entrypoints)
357
- const skippedItems = new Set();
358
- for (const module of modules) {
359
- skippedItems.add(module);
360
- }
378
+ const skippedItems = new Set(modules);
361
379
  chunkGroupInfo.skippedItems = skippedItems;
362
380
  chunkGroupsForCombining.add(chunkGroupInfo);
363
381
  } else {
364
382
  // The application may start here: We start with an empty list of available modules
365
- chunkGroupInfo.minAvailableModules = EMPTY_SET;
383
+ chunkGroupInfo.minAvailableModules = ZERO_BIGINT;
366
384
  const chunk = chunkGroup.getEntrypointChunk();
367
385
  for (const module of modules) {
368
386
  queue.push({
@@ -450,12 +468,12 @@ const visitModules = (
450
468
  b.loc,
451
469
  b.request
452
470
  );
471
+ maskByChunk.set(entrypoint.chunks[0], ZERO_BIGINT);
453
472
  entrypoint.index = nextChunkGroupIndex++;
454
473
  cgi = {
455
474
  chunkGroup: entrypoint,
456
475
  runtime: entrypoint.options.runtime || entrypoint.name,
457
- minAvailableModules: EMPTY_SET,
458
- minAvailableModulesOwned: false,
476
+ minAvailableModules: ZERO_BIGINT,
459
477
  availableModulesToBeMerged: [],
460
478
  skippedItems: undefined,
461
479
  resultingAvailableModules: undefined,
@@ -490,7 +508,7 @@ const visitModules = (
490
508
  queueDelayed.push({
491
509
  action: PROCESS_ENTRY_BLOCK,
492
510
  block: b,
493
- module: module,
511
+ module,
494
512
  chunk: entrypoint.chunks[0],
495
513
  chunkGroup: entrypoint,
496
514
  chunkGroupInfo: cgi
@@ -500,7 +518,7 @@ const visitModules = (
500
518
  queue.push({
501
519
  action: PROCESS_BLOCK,
502
520
  block: b,
503
- module: module,
521
+ module,
504
522
  chunk,
505
523
  chunkGroup,
506
524
  chunkGroupInfo
@@ -514,12 +532,12 @@ const visitModules = (
514
532
  b.loc,
515
533
  b.request
516
534
  );
535
+ maskByChunk.set(c.chunks[0], ZERO_BIGINT);
517
536
  c.index = nextChunkGroupIndex++;
518
537
  cgi = {
519
538
  chunkGroup: c,
520
539
  runtime: chunkGroupInfo.runtime,
521
540
  minAvailableModules: undefined,
522
- minAvailableModulesOwned: undefined,
523
541
  availableModulesToBeMerged: [],
524
542
  skippedItems: undefined,
525
543
  resultingAvailableModules: undefined,
@@ -584,7 +602,7 @@ const visitModules = (
584
602
  queueDelayed.push({
585
603
  action: PROCESS_BLOCK,
586
604
  block: b,
587
- module: module,
605
+ module,
588
606
  chunk: c.chunks[0],
589
607
  chunkGroup: c,
590
608
  chunkGroupInfo: /** @type {ChunkGroupInfo} */ (cgi)
@@ -607,12 +625,17 @@ const visitModules = (
607
625
  const { minAvailableModules } = chunkGroupInfo;
608
626
  // Buffer items because order need to be reversed to get indices correct
609
627
  // Traverse all referenced modules
610
- for (let i = 0; i < blockModules.length; i += 3) {
628
+ for (let i = 0, len = blockModules.length; i < len; i += 3) {
611
629
  const refModule = /** @type {Module} */ (blockModules[i]);
612
- if (chunkGraph.isModuleInChunk(refModule, chunk)) {
630
+ // For single comparisons this might be cheaper
631
+ const isModuleInChunk = chunkGraph.isModuleInChunk(refModule, chunk);
632
+
633
+ if (isModuleInChunk) {
613
634
  // skip early if already connected
614
635
  continue;
615
636
  }
637
+
638
+ const refOrdinal = /** @type {number} */ getModuleOrdinal(refModule);
616
639
  const activeState = /** @type {ConnectionState} */ (
617
640
  blockModules[i + 1]
618
641
  );
@@ -623,12 +646,7 @@ const visitModules = (
623
646
  skipConnectionBuffer.push([refModule, connections]);
624
647
  // We skip inactive connections
625
648
  if (activeState === false) continue;
626
- }
627
- if (
628
- activeState === true &&
629
- (minAvailableModules.has(refModule) ||
630
- minAvailableModules.plus.has(refModule))
631
- ) {
649
+ } else if (isOrdinalSetInMask(minAvailableModules, refOrdinal)) {
632
650
  // already in parent chunks, skip it for now
633
651
  skipBuffer.push(refModule);
634
652
  continue;
@@ -694,15 +712,15 @@ const visitModules = (
694
712
  const blockModules = getBlockModules(block, chunkGroupInfo.runtime);
695
713
 
696
714
  if (blockModules !== undefined) {
697
- // Traverse all referenced modules
698
- for (let i = 0; i < blockModules.length; i += 3) {
715
+ // Traverse all referenced modules in reverse order
716
+ for (let i = blockModules.length - 3; i >= 0; i -= 3) {
699
717
  const refModule = /** @type {Module} */ (blockModules[i]);
700
718
  const activeState = /** @type {ConnectionState} */ (
701
719
  blockModules[i + 1]
702
720
  );
703
721
  // enqueue, then add and enter to be in the correct order
704
722
  // this is relevant with circular dependencies
705
- queueBuffer.push({
723
+ queue.push({
706
724
  action:
707
725
  activeState === true ? ADD_AND_ENTER_ENTRY_MODULE : PROCESS_BLOCK,
708
726
  block: refModule,
@@ -712,13 +730,6 @@ const visitModules = (
712
730
  chunkGroupInfo
713
731
  });
714
732
  }
715
- // Add buffered items in reverse order
716
- if (queueBuffer.length > 0) {
717
- for (let i = queueBuffer.length - 1; i >= 0; i--) {
718
- queue.push(queueBuffer[i]);
719
- }
720
- queueBuffer.length = 0;
721
- }
722
733
  }
723
734
 
724
735
  // Traverse all Blocks
@@ -750,12 +761,18 @@ const visitModules = (
750
761
  );
751
762
  // fallthrough
752
763
  case ADD_AND_ENTER_MODULE: {
753
- if (chunkGraph.isModuleInChunk(module, chunk)) {
764
+ const isModuleInChunk = chunkGraph.isModuleInChunk(module, chunk);
765
+
766
+ if (isModuleInChunk) {
754
767
  // already connected, skip it
755
768
  break;
756
769
  }
757
770
  // We connect Module and Chunk
758
771
  chunkGraph.connectChunkAndModule(chunk, module);
772
+ const moduleOrdinal = getModuleOrdinal(module);
773
+ let chunkMask = maskByChunk.get(chunk);
774
+ chunkMask |= ONE_BIGINT << BigInt(moduleOrdinal);
775
+ maskByChunk.set(chunk, chunkMask);
759
776
  }
760
777
  // fallthrough
761
778
  case ENTER_MODULE: {
@@ -812,44 +829,22 @@ const visitModules = (
812
829
  }
813
830
  };
814
831
 
832
+ /**
833
+ * @param {ChunkGroupInfo} chunkGroupInfo The info object for the chunk group
834
+ * @returns {bigint} The mask of available modules after the chunk group
835
+ */
815
836
  const calculateResultingAvailableModules = chunkGroupInfo => {
816
- if (chunkGroupInfo.resultingAvailableModules)
837
+ if (chunkGroupInfo.resultingAvailableModules !== undefined)
817
838
  return chunkGroupInfo.resultingAvailableModules;
818
839
 
819
- const minAvailableModules = chunkGroupInfo.minAvailableModules;
820
-
821
- // Create a new Set of available modules at this point
822
- // We want to be as lazy as possible. There are multiple ways doing this:
823
- // Note that resultingAvailableModules is stored as "(a) + (b)" as it's a ModuleSetPlus
824
- // - resultingAvailableModules = (modules of chunk) + (minAvailableModules + minAvailableModules.plus)
825
- // - resultingAvailableModules = (minAvailableModules + modules of chunk) + (minAvailableModules.plus)
826
- // We choose one depending on the size of minAvailableModules vs minAvailableModules.plus
827
-
828
- let resultingAvailableModules;
829
- if (minAvailableModules.size > minAvailableModules.plus.size) {
830
- // resultingAvailableModules = (modules of chunk) + (minAvailableModules + minAvailableModules.plus)
831
- resultingAvailableModules =
832
- /** @type {Set<Module> & {plus: Set<Module>}} */ (new Set());
833
- for (const module of minAvailableModules.plus)
834
- minAvailableModules.add(module);
835
- minAvailableModules.plus = EMPTY_SET;
836
- resultingAvailableModules.plus = minAvailableModules;
837
- chunkGroupInfo.minAvailableModulesOwned = false;
838
- } else {
839
- // resultingAvailableModules = (minAvailableModules + modules of chunk) + (minAvailableModules.plus)
840
- resultingAvailableModules =
841
- /** @type {Set<Module> & {plus: Set<Module>}} */ (
842
- new Set(minAvailableModules)
843
- );
844
- resultingAvailableModules.plus = minAvailableModules.plus;
845
- }
840
+ let resultingAvailableModules = chunkGroupInfo.minAvailableModules;
846
841
 
847
842
  // add the modules from the chunk group to the set
848
843
  for (const chunk of chunkGroupInfo.chunkGroup.chunks) {
849
- for (const m of chunkGraph.getChunkModulesIterable(chunk)) {
850
- resultingAvailableModules.add(m);
851
- }
844
+ const mask = maskByChunk.get(chunk);
845
+ resultingAvailableModules |= mask;
852
846
  }
847
+
853
848
  return (chunkGroupInfo.resultingAvailableModules =
854
849
  resultingAvailableModules);
855
850
  };
@@ -896,232 +891,24 @@ const visitModules = (
896
891
  // Execute the merge
897
892
  for (const info of chunkGroupsForMerging) {
898
893
  const availableModulesToBeMerged = info.availableModulesToBeMerged;
899
- let cachedMinAvailableModules = info.minAvailableModules;
894
+ const cachedMinAvailableModules = info.minAvailableModules;
895
+ let minAvailableModules = cachedMinAvailableModules;
900
896
 
901
897
  statMergedAvailableModuleSets += availableModulesToBeMerged.length;
902
898
 
903
- // 1. Get minimal available modules
904
- // It doesn't make sense to traverse a chunk again with more available modules.
905
- // This step calculates the minimal available modules and skips traversal when
906
- // the list didn't shrink.
907
- if (availableModulesToBeMerged.length > 1) {
908
- availableModulesToBeMerged.sort(bySetSize);
909
- }
910
- let changed = false;
911
- merge: for (const availableModules of availableModulesToBeMerged) {
912
- if (cachedMinAvailableModules === undefined) {
913
- cachedMinAvailableModules = availableModules;
914
- info.minAvailableModules = cachedMinAvailableModules;
915
- info.minAvailableModulesOwned = false;
916
- changed = true;
899
+ for (const availableModules of availableModulesToBeMerged) {
900
+ if (minAvailableModules === undefined) {
901
+ minAvailableModules = availableModules;
917
902
  } else {
918
- if (info.minAvailableModulesOwned) {
919
- // We own it and can modify it
920
- if (cachedMinAvailableModules.plus === availableModules.plus) {
921
- for (const m of cachedMinAvailableModules) {
922
- if (!availableModules.has(m)) {
923
- cachedMinAvailableModules.delete(m);
924
- changed = true;
925
- }
926
- }
927
- } else {
928
- for (const m of cachedMinAvailableModules) {
929
- if (!availableModules.has(m) && !availableModules.plus.has(m)) {
930
- cachedMinAvailableModules.delete(m);
931
- changed = true;
932
- }
933
- }
934
- for (const m of cachedMinAvailableModules.plus) {
935
- if (!availableModules.has(m) && !availableModules.plus.has(m)) {
936
- // We can't remove modules from the plus part
937
- // so we need to merge plus into the normal part to allow modifying it
938
- const iterator =
939
- cachedMinAvailableModules.plus[Symbol.iterator]();
940
- // fast forward add all modules until m
941
- /** @type {IteratorResult<Module>} */
942
- let it;
943
- while (!(it = iterator.next()).done) {
944
- const module = it.value;
945
- if (module === m) break;
946
- cachedMinAvailableModules.add(module);
947
- }
948
- // check the remaining modules before adding
949
- while (!(it = iterator.next()).done) {
950
- const module = it.value;
951
- if (
952
- availableModules.has(module) ||
953
- availableModules.plus.has(module)
954
- ) {
955
- cachedMinAvailableModules.add(module);
956
- }
957
- }
958
- cachedMinAvailableModules.plus = EMPTY_SET;
959
- changed = true;
960
- continue merge;
961
- }
962
- }
963
- }
964
- } else if (cachedMinAvailableModules.plus === availableModules.plus) {
965
- // Common and fast case when the plus part is shared
966
- // We only need to care about the normal part
967
- if (availableModules.size < cachedMinAvailableModules.size) {
968
- // the new availableModules is smaller so it's faster to
969
- // fork from the new availableModules
970
- statForkedAvailableModules++;
971
- statForkedAvailableModulesCount += availableModules.size;
972
- statForkedMergedModulesCount += cachedMinAvailableModules.size;
973
- // construct a new Set as intersection of cachedMinAvailableModules and availableModules
974
- const newSet = /** @type {ModuleSetPlus} */ (new Set());
975
- newSet.plus = availableModules.plus;
976
- for (const m of availableModules) {
977
- if (cachedMinAvailableModules.has(m)) {
978
- newSet.add(m);
979
- }
980
- }
981
- statForkedResultModulesCount += newSet.size;
982
- cachedMinAvailableModules = newSet;
983
- info.minAvailableModulesOwned = true;
984
- info.minAvailableModules = newSet;
985
- changed = true;
986
- continue merge;
987
- }
988
- for (const m of cachedMinAvailableModules) {
989
- if (!availableModules.has(m)) {
990
- // cachedMinAvailableModules need to be modified
991
- // but we don't own it
992
- statForkedAvailableModules++;
993
- statForkedAvailableModulesCount +=
994
- cachedMinAvailableModules.size;
995
- statForkedMergedModulesCount += availableModules.size;
996
- // construct a new Set as intersection of cachedMinAvailableModules and availableModules
997
- // as the plus part is equal we can just take over this one
998
- const newSet = /** @type {ModuleSetPlus} */ (new Set());
999
- newSet.plus = availableModules.plus;
1000
- const iterator = cachedMinAvailableModules[Symbol.iterator]();
1001
- // fast forward add all modules until m
1002
- /** @type {IteratorResult<Module>} */
1003
- let it;
1004
- while (!(it = iterator.next()).done) {
1005
- const module = it.value;
1006
- if (module === m) break;
1007
- newSet.add(module);
1008
- }
1009
- // check the remaining modules before adding
1010
- while (!(it = iterator.next()).done) {
1011
- const module = it.value;
1012
- if (availableModules.has(module)) {
1013
- newSet.add(module);
1014
- }
1015
- }
1016
- statForkedResultModulesCount += newSet.size;
1017
- cachedMinAvailableModules = newSet;
1018
- info.minAvailableModulesOwned = true;
1019
- info.minAvailableModules = newSet;
1020
- changed = true;
1021
- continue merge;
1022
- }
1023
- }
1024
- } else {
1025
- for (const m of cachedMinAvailableModules) {
1026
- if (!availableModules.has(m) && !availableModules.plus.has(m)) {
1027
- // cachedMinAvailableModules need to be modified
1028
- // but we don't own it
1029
- statForkedAvailableModules++;
1030
- statForkedAvailableModulesCount +=
1031
- cachedMinAvailableModules.size;
1032
- statForkedAvailableModulesCountPlus +=
1033
- cachedMinAvailableModules.plus.size;
1034
- statForkedMergedModulesCount += availableModules.size;
1035
- statForkedMergedModulesCountPlus += availableModules.plus.size;
1036
- // construct a new Set as intersection of cachedMinAvailableModules and availableModules
1037
- const newSet = /** @type {ModuleSetPlus} */ (new Set());
1038
- newSet.plus = EMPTY_SET;
1039
- const iterator = cachedMinAvailableModules[Symbol.iterator]();
1040
- // fast forward add all modules until m
1041
- /** @type {IteratorResult<Module>} */
1042
- let it;
1043
- while (!(it = iterator.next()).done) {
1044
- const module = it.value;
1045
- if (module === m) break;
1046
- newSet.add(module);
1047
- }
1048
- // check the remaining modules before adding
1049
- while (!(it = iterator.next()).done) {
1050
- const module = it.value;
1051
- if (
1052
- availableModules.has(module) ||
1053
- availableModules.plus.has(module)
1054
- ) {
1055
- newSet.add(module);
1056
- }
1057
- }
1058
- // also check all modules in cachedMinAvailableModules.plus
1059
- for (const module of cachedMinAvailableModules.plus) {
1060
- if (
1061
- availableModules.has(module) ||
1062
- availableModules.plus.has(module)
1063
- ) {
1064
- newSet.add(module);
1065
- }
1066
- }
1067
- statForkedResultModulesCount += newSet.size;
1068
- cachedMinAvailableModules = newSet;
1069
- info.minAvailableModulesOwned = true;
1070
- info.minAvailableModules = newSet;
1071
- changed = true;
1072
- continue merge;
1073
- }
1074
- }
1075
- for (const m of cachedMinAvailableModules.plus) {
1076
- if (!availableModules.has(m) && !availableModules.plus.has(m)) {
1077
- // cachedMinAvailableModules need to be modified
1078
- // but we don't own it
1079
- statForkedAvailableModules++;
1080
- statForkedAvailableModulesCount +=
1081
- cachedMinAvailableModules.size;
1082
- statForkedAvailableModulesCountPlus +=
1083
- cachedMinAvailableModules.plus.size;
1084
- statForkedMergedModulesCount += availableModules.size;
1085
- statForkedMergedModulesCountPlus += availableModules.plus.size;
1086
- // construct a new Set as intersection of cachedMinAvailableModules and availableModules
1087
- // we already know that all modules directly from cachedMinAvailableModules are in availableModules too
1088
- const newSet = /** @type {ModuleSetPlus} */ (
1089
- new Set(cachedMinAvailableModules)
1090
- );
1091
- newSet.plus = EMPTY_SET;
1092
- const iterator =
1093
- cachedMinAvailableModules.plus[Symbol.iterator]();
1094
- // fast forward add all modules until m
1095
- /** @type {IteratorResult<Module>} */
1096
- let it;
1097
- while (!(it = iterator.next()).done) {
1098
- const module = it.value;
1099
- if (module === m) break;
1100
- newSet.add(module);
1101
- }
1102
- // check the remaining modules before adding
1103
- while (!(it = iterator.next()).done) {
1104
- const module = it.value;
1105
- if (
1106
- availableModules.has(module) ||
1107
- availableModules.plus.has(module)
1108
- ) {
1109
- newSet.add(module);
1110
- }
1111
- }
1112
- statForkedResultModulesCount += newSet.size;
1113
- cachedMinAvailableModules = newSet;
1114
- info.minAvailableModulesOwned = true;
1115
- info.minAvailableModules = newSet;
1116
- changed = true;
1117
- continue merge;
1118
- }
1119
- }
1120
- }
903
+ minAvailableModules &= availableModules;
1121
904
  }
1122
905
  }
906
+
907
+ const changed = minAvailableModules !== cachedMinAvailableModules;
908
+
1123
909
  availableModulesToBeMerged.length = 0;
1124
910
  if (changed) {
911
+ info.minAvailableModules = minAvailableModules;
1125
912
  info.resultingAvailableModules = undefined;
1126
913
  outdatedChunkGroupInfo.add(info);
1127
914
  }
@@ -1134,34 +921,24 @@ const visitModules = (
1134
921
  for (const source of /** @type {Set<ChunkGroupInfo>} */ (
1135
922
  info.availableSources
1136
923
  )) {
1137
- if (!source.minAvailableModules) {
924
+ if (source.minAvailableModules === undefined) {
1138
925
  chunkGroupsForCombining.delete(info);
1139
926
  break;
1140
927
  }
1141
928
  }
1142
929
  }
930
+
1143
931
  for (const info of chunkGroupsForCombining) {
1144
- const availableModules = /** @type {ModuleSetPlus} */ (new Set());
1145
- availableModules.plus = EMPTY_SET;
1146
- const mergeSet = set => {
1147
- if (set.size > availableModules.plus.size) {
1148
- for (const item of availableModules.plus) availableModules.add(item);
1149
- availableModules.plus = set;
1150
- } else {
1151
- for (const item of set) availableModules.add(item);
1152
- }
1153
- };
932
+ let availableModules = ZERO_BIGINT;
1154
933
  // combine minAvailableModules from all resultingAvailableModules
1155
934
  for (const source of /** @type {Set<ChunkGroupInfo>} */ (
1156
935
  info.availableSources
1157
936
  )) {
1158
937
  const resultingAvailableModules =
1159
938
  calculateResultingAvailableModules(source);
1160
- mergeSet(resultingAvailableModules);
1161
- mergeSet(resultingAvailableModules.plus);
939
+ availableModules |= resultingAvailableModules;
1162
940
  }
1163
941
  info.minAvailableModules = availableModules;
1164
- info.minAvailableModulesOwned = false;
1165
942
  info.resultingAvailableModules = undefined;
1166
943
  outdatedChunkGroupInfo.add(info);
1167
944
  }
@@ -1175,13 +952,11 @@ const visitModules = (
1175
952
  // 1. Reconsider skipped items
1176
953
  if (info.skippedItems !== undefined) {
1177
954
  const minAvailableModules =
1178
- /** @type {ModuleSetPlus} */
955
+ /** @type {bigint} */
1179
956
  (info.minAvailableModules);
1180
957
  for (const module of info.skippedItems) {
1181
- if (
1182
- !minAvailableModules.has(module) &&
1183
- !minAvailableModules.plus.has(module)
1184
- ) {
958
+ const ordinal = getModuleOrdinal(module);
959
+ if (!isOrdinalSetInMask(minAvailableModules, ordinal)) {
1185
960
  queue.push({
1186
961
  action: ADD_AND_ENTER_MODULE,
1187
962
  block: module,
@@ -1198,7 +973,7 @@ const visitModules = (
1198
973
  // 2. Reconsider skipped connections
1199
974
  if (info.skippedModuleConnections !== undefined) {
1200
975
  const minAvailableModules =
1201
- /** @type {ModuleSetPlus} */
976
+ /** @type {bigint} */
1202
977
  (info.minAvailableModules);
1203
978
  for (const entry of info.skippedModuleConnections) {
1204
979
  const [module, connections] = entry;
@@ -1208,15 +983,12 @@ const visitModules = (
1208
983
  );
1209
984
  if (activeState === false) continue;
1210
985
  if (activeState === true) {
986
+ const ordinal = getModuleOrdinal(module);
1211
987
  info.skippedModuleConnections.delete(entry);
1212
- }
1213
- if (
1214
- activeState === true &&
1215
- (minAvailableModules.has(module) ||
1216
- minAvailableModules.plus.has(module))
1217
- ) {
1218
- info.skippedItems.add(module);
1219
- continue;
988
+ if (isOrdinalSetInMask(minAvailableModules, ordinal)) {
989
+ info.skippedItems.add(module);
990
+ continue;
991
+ }
1220
992
  }
1221
993
  queue.push({
1222
994
  action: activeState === true ? ADD_AND_ENTER_MODULE : PROCESS_BLOCK,
@@ -1307,7 +1079,7 @@ const visitModules = (
1307
1079
  let preOrderIndex = 0;
1308
1080
  let postOrderIndex = 0;
1309
1081
 
1310
- const process = (current, visited = new Set()) => {
1082
+ const process = (current, visited) => {
1311
1083
  if (visited.has(current)) {
1312
1084
  return;
1313
1085
  }
@@ -1319,14 +1091,14 @@ const visitModules = (
1319
1091
  return;
1320
1092
  }
1321
1093
 
1322
- for (let i = 0; i < blockModules.length; i += 3) {
1323
- const refModule = /** @type {Module} */ (blockModules[i]);
1094
+ for (let i = 0, len = blockModules.length; i < len; i += 3) {
1324
1095
  const activeState = /** @type {ConnectionState} */ (
1325
1096
  blockModules[i + 1]
1326
1097
  );
1327
1098
  if (activeState === false) {
1328
1099
  continue;
1329
1100
  }
1101
+ const refModule = /** @type {Module} */ (blockModules[i]);
1330
1102
 
1331
1103
  if (refModule) {
1332
1104
  chunkGroup.setModulePreOrderIndex(refModule, preOrderIndex++);
@@ -1336,9 +1108,10 @@ const visitModules = (
1336
1108
  }
1337
1109
  };
1338
1110
 
1339
- process(block);
1111
+ process(block, new Set());
1340
1112
  }
1341
1113
  outdatedOrderIndexChunkGroups.clear();
1114
+ ordinalByModule.clear();
1342
1115
 
1343
1116
  logger.log(
1344
1117
  `${statProcessedQueueItems} queue items processed (${statProcessedBlocks} blocks)`
@@ -1357,13 +1130,13 @@ const visitModules = (
1357
1130
  * @param {Compilation} compilation the compilation
1358
1131
  * @param {Set<DependenciesBlock>} blocksWithNestedBlocks flag for blocks that have nested blocks
1359
1132
  * @param {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} blockConnections connection for blocks
1360
- * @param {Map<ChunkGroup, ChunkGroupInfo>} chunkGroupInfoMap mapping from chunk group to available modules
1133
+ * @param {Map<Chunk, bigint>} maskByChunk mapping from chunk to module mask
1361
1134
  */
1362
1135
  const connectChunkGroups = (
1363
1136
  compilation,
1364
1137
  blocksWithNestedBlocks,
1365
1138
  blockConnections,
1366
- chunkGroupInfoMap
1139
+ maskByChunk
1367
1140
  ) => {
1368
1141
  const { chunkGraph } = compilation;
1369
1142
 
@@ -1371,15 +1144,13 @@ const connectChunkGroups = (
1371
1144
  * Helper function to check if all modules of a chunk are available
1372
1145
  *
1373
1146
  * @param {ChunkGroup} chunkGroup the chunkGroup to scan
1374
- * @param {ModuleSetPlus} availableModules the comparator set
1147
+ * @param {bigint} availableModules the comparator set
1375
1148
  * @returns {boolean} return true if all modules of a chunk are available
1376
1149
  */
1377
1150
  const areModulesAvailable = (chunkGroup, availableModules) => {
1378
1151
  for (const chunk of chunkGroup.chunks) {
1379
- for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
1380
- if (!availableModules.has(module) && !availableModules.plus.has(module))
1381
- return false;
1382
- }
1152
+ const chunkMask = maskByChunk.get(chunk);
1153
+ if ((chunkMask & availableModules) !== chunkMask) return false;
1383
1154
  }
1384
1155
  return true;
1385
1156
  };
@@ -1464,6 +1235,9 @@ const buildChunkGraph = (compilation, inputEntrypointsAndModules) => {
1464
1235
  /** @type {Set<DependenciesBlock>} */
1465
1236
  const blocksWithNestedBlocks = new Set();
1466
1237
 
1238
+ /** @type {Map<Chunk, bigint>} */
1239
+ const maskByChunk = new Map();
1240
+
1467
1241
  // PART ONE
1468
1242
 
1469
1243
  logger.time("visitModules");
@@ -1474,7 +1248,8 @@ const buildChunkGraph = (compilation, inputEntrypointsAndModules) => {
1474
1248
  chunkGroupInfoMap,
1475
1249
  blockConnections,
1476
1250
  blocksWithNestedBlocks,
1477
- allCreatedChunkGroups
1251
+ allCreatedChunkGroups,
1252
+ maskByChunk
1478
1253
  );
1479
1254
  logger.timeEnd("visitModules");
1480
1255
 
@@ -1485,7 +1260,7 @@ const buildChunkGraph = (compilation, inputEntrypointsAndModules) => {
1485
1260
  compilation,
1486
1261
  blocksWithNestedBlocks,
1487
1262
  blockConnections,
1488
- chunkGroupInfoMap
1263
+ maskByChunk
1489
1264
  );
1490
1265
  logger.timeEnd("connectChunkGroups");
1491
1266