webpack 5.90.1 → 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.

Files changed (37) hide show
  1. package/lib/Compilation.js +1 -1
  2. package/lib/ContextModule.js +2 -1
  3. package/lib/CssModule.js +0 -3
  4. package/lib/DelegatedModule.js +2 -1
  5. package/lib/DllModule.js +2 -1
  6. package/lib/ExternalModule.js +2 -1
  7. package/lib/Module.js +24 -3
  8. package/lib/MultiCompiler.js +36 -10
  9. package/lib/NormalModule.js +236 -85
  10. package/lib/NormalModuleFactory.js +162 -31
  11. package/lib/RawModule.js +2 -1
  12. package/lib/ResolverFactory.js +2 -0
  13. package/lib/RuntimeModule.js +2 -1
  14. package/lib/Stats.js +2 -2
  15. package/lib/asset/RawDataUrlModule.js +2 -1
  16. package/lib/buildChunkGraph.js +156 -348
  17. package/lib/container/ContainerEntryModule.js +2 -1
  18. package/lib/container/FallbackModule.js +2 -1
  19. package/lib/container/RemoteModule.js +2 -1
  20. package/lib/css/CssLoadingRuntimeModule.js +1 -1
  21. package/lib/dependencies/ExportsInfoDependency.js +6 -12
  22. package/lib/dependencies/HarmonyImportSpecifierDependency.js +15 -5
  23. package/lib/dependencies/ImportParserPlugin.js +1 -0
  24. package/lib/dependencies/WorkerDependency.js +1 -1
  25. package/lib/dependencies/WorkerPlugin.js +4 -4
  26. package/lib/hmr/HotModuleReplacement.runtime.js +1 -1
  27. package/lib/hmr/LazyCompilationPlugin.js +2 -1
  28. package/lib/optimize/ConcatenatedModule.js +2 -1
  29. package/lib/runtime/AutoPublicPathRuntimeModule.js +1 -1
  30. package/lib/sharing/ConsumeSharedModule.js +2 -1
  31. package/lib/sharing/ProvideSharedModule.js +2 -1
  32. package/lib/util/memoize.js +2 -0
  33. package/lib/util/numberHash.js +4 -15
  34. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +2 -1
  35. package/lib/webpack.js +5 -3
  36. package/package.json +2 -2
  37. package/types.d.ts +122 -78
@@ -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
- * @property {Set<[Module, ConnectionState]>=} 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
44
+ * @property {Set<[Module, ModuleGraphConnection[]]>=} skippedModuleConnections referenced modules that where skipped because they were not active in this runtime
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,16 +58,34 @@ 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;
69
+ const isOrdinalSetInMask = (mask, ordinal) =>
70
+ BigInt.asUintN(1, mask >> BigInt(ordinal)) !== ZERO_BIGINT;
71
+
72
+ /**
73
+ * @param {ModuleGraphConnection[]} connections list of connections
74
+ * @param {RuntimeSpec} runtime for which runtime
75
+ * @returns {ConnectionState} connection state
76
+ */
77
+ const getActiveStateOfConnections = (connections, runtime) => {
78
+ let merged = connections[0].getActiveState(runtime);
79
+ if (merged === true) return true;
80
+ for (let i = 1; i < connections.length; i++) {
81
+ const c = connections[i];
82
+ merged = ModuleGraphConnection.addConnectionStates(
83
+ merged,
84
+ c.getActiveState(runtime)
85
+ );
86
+ if (merged === true) return true;
87
+ }
88
+ return merged;
74
89
  };
75
90
 
76
91
  const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
@@ -99,9 +114,6 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
99
114
  if (!m) continue;
100
115
  // We skip weak connections
101
116
  if (connection.weak) continue;
102
- const state = connection.getActiveState(runtime);
103
- // We skip inactive connections
104
- if (state === false) continue;
105
117
 
106
118
  const block = moduleGraph.getParentBlock(d);
107
119
  let index = moduleGraph.getParentBlockIndex(d);
@@ -115,41 +127,47 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
115
127
  modules = blockModulesMap.get((blockCache = block));
116
128
  }
117
129
 
118
- const i = index << 2;
130
+ const i = index * 3;
119
131
  modules[i] = m;
120
- modules[i + 1] = state;
132
+ modules[i + 1] = connection.getActiveState(runtime);
133
+ modules[i + 2] = connection;
121
134
  }
122
135
 
123
136
  for (const modules of arrays) {
124
137
  if (modules.length === 0) continue;
125
138
  let indexMap;
126
139
  let length = 0;
127
- outer: for (let j = 0; j < modules.length; j += 2) {
140
+ outer: for (let j = 0; j < modules.length; j += 3) {
128
141
  const m = modules[j];
129
142
  if (m === undefined) continue;
130
143
  const state = modules[j + 1];
144
+ const connection = modules[j + 2];
131
145
  if (indexMap === undefined) {
132
146
  let i = 0;
133
- for (; i < length; i += 2) {
147
+ for (; i < length; i += 3) {
134
148
  if (modules[i] === m) {
135
149
  const merged = modules[i + 1];
150
+ modules[i + 2].push(connection);
136
151
  if (merged === true) continue outer;
137
152
  modules[i + 1] = ModuleGraphConnection.addConnectionStates(
138
153
  merged,
139
154
  state
140
155
  );
156
+ continue outer;
141
157
  }
142
158
  }
143
159
  modules[length] = m;
144
160
  length++;
145
161
  modules[length] = state;
146
162
  length++;
163
+ modules[length] = [connection];
164
+ length++;
147
165
  if (length > 30) {
148
166
  // To avoid worse case performance, we will use an index map for
149
167
  // linear cost access, which allows to maintain O(n) complexity
150
168
  // while keeping allocations down to a minimum
151
169
  indexMap = new Map();
152
- for (let i = 0; i < length; i += 2) {
170
+ for (let i = 0; i < length; i += 3) {
153
171
  indexMap.set(modules[i], i + 1);
154
172
  }
155
173
  }
@@ -157,6 +175,7 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
157
175
  const idx = indexMap.get(m);
158
176
  if (idx !== undefined) {
159
177
  const merged = modules[idx];
178
+ modules[idx + 1].push(connection);
160
179
  if (merged === true) continue outer;
161
180
  modules[idx] = ModuleGraphConnection.addConnectionStates(
162
181
  merged,
@@ -168,6 +187,8 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
168
187
  modules[length] = state;
169
188
  indexMap.set(m, length);
170
189
  length++;
190
+ modules[length] = [connection];
191
+ length++;
171
192
  }
172
193
  }
173
194
  }
@@ -184,6 +205,7 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
184
205
  * @param {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} blockConnections connection for blocks
185
206
  * @param {Set<DependenciesBlock>} blocksWithNestedBlocks flag for blocks that have nested blocks
186
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
187
209
  */
188
210
  const visitModules = (
189
211
  logger,
@@ -192,7 +214,8 @@ const visitModules = (
192
214
  chunkGroupInfoMap,
193
215
  blockConnections,
194
216
  blocksWithNestedBlocks,
195
- allCreatedChunkGroups
217
+ allCreatedChunkGroups,
218
+ maskByChunk
196
219
  ) => {
197
220
  const { moduleGraph, chunkGraph, moduleMemCaches } = compilation;
198
221
 
@@ -203,11 +226,35 @@ const visitModules = (
203
226
  /** @type {Map<DependenciesBlock, (Module | ConnectionState)[]>} */
204
227
  let blockModulesMap;
205
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
+
206
253
  /**
207
254
  *
208
255
  * @param {DependenciesBlock} block block
209
256
  * @param {RuntimeSpec} runtime runtime
210
- * @returns {(Module | ConnectionState)[]} block modules in flatten tuples
257
+ * @returns {(Module | ConnectionState | ModuleGraphConnection[])[]} block modules in flatten tuples
211
258
  */
212
259
  const getBlockModules = (block, runtime) => {
213
260
  if (blockModulesMapRuntime !== runtime) {
@@ -306,7 +353,6 @@ const visitModules = (
306
353
  chunkGroup,
307
354
  runtime,
308
355
  minAvailableModules: undefined,
309
- minAvailableModulesOwned: false,
310
356
  availableModulesToBeMerged: [],
311
357
  skippedItems: undefined,
312
358
  resultingAvailableModules: undefined,
@@ -329,15 +375,12 @@ const visitModules = (
329
375
  // minAvailableModules for child entrypoints are unknown yet, set to undefined.
330
376
  // This means no module is added until other sets are merged into
331
377
  // this minAvailableModules (by the parent entrypoints)
332
- const skippedItems = new Set();
333
- for (const module of modules) {
334
- skippedItems.add(module);
335
- }
378
+ const skippedItems = new Set(modules);
336
379
  chunkGroupInfo.skippedItems = skippedItems;
337
380
  chunkGroupsForCombining.add(chunkGroupInfo);
338
381
  } else {
339
382
  // The application may start here: We start with an empty list of available modules
340
- chunkGroupInfo.minAvailableModules = EMPTY_SET;
383
+ chunkGroupInfo.minAvailableModules = ZERO_BIGINT;
341
384
  const chunk = chunkGroup.getEntrypointChunk();
342
385
  for (const module of modules) {
343
386
  queue.push({
@@ -382,7 +425,7 @@ const visitModules = (
382
425
  /** @type {QueueItem[]} */
383
426
  let queueDelayed = [];
384
427
 
385
- /** @type {[Module, ConnectionState][]} */
428
+ /** @type {[Module, ModuleGraphConnection[]][]} */
386
429
  const skipConnectionBuffer = [];
387
430
  /** @type {Module[]} */
388
431
  const skipBuffer = [];
@@ -425,12 +468,12 @@ const visitModules = (
425
468
  b.loc,
426
469
  b.request
427
470
  );
471
+ maskByChunk.set(entrypoint.chunks[0], ZERO_BIGINT);
428
472
  entrypoint.index = nextChunkGroupIndex++;
429
473
  cgi = {
430
474
  chunkGroup: entrypoint,
431
475
  runtime: entrypoint.options.runtime || entrypoint.name,
432
- minAvailableModules: EMPTY_SET,
433
- minAvailableModulesOwned: false,
476
+ minAvailableModules: ZERO_BIGINT,
434
477
  availableModulesToBeMerged: [],
435
478
  skippedItems: undefined,
436
479
  resultingAvailableModules: undefined,
@@ -465,7 +508,7 @@ const visitModules = (
465
508
  queueDelayed.push({
466
509
  action: PROCESS_ENTRY_BLOCK,
467
510
  block: b,
468
- module: module,
511
+ module,
469
512
  chunk: entrypoint.chunks[0],
470
513
  chunkGroup: entrypoint,
471
514
  chunkGroupInfo: cgi
@@ -475,7 +518,7 @@ const visitModules = (
475
518
  queue.push({
476
519
  action: PROCESS_BLOCK,
477
520
  block: b,
478
- module: module,
521
+ module,
479
522
  chunk,
480
523
  chunkGroup,
481
524
  chunkGroupInfo
@@ -489,12 +532,12 @@ const visitModules = (
489
532
  b.loc,
490
533
  b.request
491
534
  );
535
+ maskByChunk.set(c.chunks[0], ZERO_BIGINT);
492
536
  c.index = nextChunkGroupIndex++;
493
537
  cgi = {
494
538
  chunkGroup: c,
495
539
  runtime: chunkGroupInfo.runtime,
496
540
  minAvailableModules: undefined,
497
- minAvailableModulesOwned: undefined,
498
541
  availableModulesToBeMerged: [],
499
542
  skippedItems: undefined,
500
543
  resultingAvailableModules: undefined,
@@ -559,7 +602,7 @@ const visitModules = (
559
602
  queueDelayed.push({
560
603
  action: PROCESS_BLOCK,
561
604
  block: b,
562
- module: module,
605
+ module,
563
606
  chunk: c.chunks[0],
564
607
  chunkGroup: c,
565
608
  chunkGroupInfo: /** @type {ChunkGroupInfo} */ (cgi)
@@ -582,24 +625,28 @@ const visitModules = (
582
625
  const { minAvailableModules } = chunkGroupInfo;
583
626
  // Buffer items because order need to be reversed to get indices correct
584
627
  // Traverse all referenced modules
585
- for (let i = 0; i < blockModules.length; i += 2) {
628
+ for (let i = 0, len = blockModules.length; i < len; i += 3) {
586
629
  const refModule = /** @type {Module} */ (blockModules[i]);
587
- if (chunkGraph.isModuleInChunk(refModule, chunk)) {
630
+ // For single comparisons this might be cheaper
631
+ const isModuleInChunk = chunkGraph.isModuleInChunk(refModule, chunk);
632
+
633
+ if (isModuleInChunk) {
588
634
  // skip early if already connected
589
635
  continue;
590
636
  }
637
+
638
+ const refOrdinal = /** @type {number} */ getModuleOrdinal(refModule);
591
639
  const activeState = /** @type {ConnectionState} */ (
592
640
  blockModules[i + 1]
593
641
  );
594
642
  if (activeState !== true) {
595
- skipConnectionBuffer.push([refModule, activeState]);
643
+ const connections = /** @type {ModuleGraphConnection[]} */ (
644
+ blockModules[i + 2]
645
+ );
646
+ skipConnectionBuffer.push([refModule, connections]);
647
+ // We skip inactive connections
596
648
  if (activeState === false) continue;
597
- }
598
- if (
599
- activeState === true &&
600
- (minAvailableModules.has(refModule) ||
601
- minAvailableModules.plus.has(refModule))
602
- ) {
649
+ } else if (isOrdinalSetInMask(minAvailableModules, refOrdinal)) {
603
650
  // already in parent chunks, skip it for now
604
651
  skipBuffer.push(refModule);
605
652
  continue;
@@ -665,15 +712,15 @@ const visitModules = (
665
712
  const blockModules = getBlockModules(block, chunkGroupInfo.runtime);
666
713
 
667
714
  if (blockModules !== undefined) {
668
- // Traverse all referenced modules
669
- for (let i = 0; i < blockModules.length; i += 2) {
715
+ // Traverse all referenced modules in reverse order
716
+ for (let i = blockModules.length - 3; i >= 0; i -= 3) {
670
717
  const refModule = /** @type {Module} */ (blockModules[i]);
671
718
  const activeState = /** @type {ConnectionState} */ (
672
719
  blockModules[i + 1]
673
720
  );
674
721
  // enqueue, then add and enter to be in the correct order
675
722
  // this is relevant with circular dependencies
676
- queueBuffer.push({
723
+ queue.push({
677
724
  action:
678
725
  activeState === true ? ADD_AND_ENTER_ENTRY_MODULE : PROCESS_BLOCK,
679
726
  block: refModule,
@@ -683,13 +730,6 @@ const visitModules = (
683
730
  chunkGroupInfo
684
731
  });
685
732
  }
686
- // Add buffered items in reverse order
687
- if (queueBuffer.length > 0) {
688
- for (let i = queueBuffer.length - 1; i >= 0; i--) {
689
- queue.push(queueBuffer[i]);
690
- }
691
- queueBuffer.length = 0;
692
- }
693
733
  }
694
734
 
695
735
  // Traverse all Blocks
@@ -721,12 +761,18 @@ const visitModules = (
721
761
  );
722
762
  // fallthrough
723
763
  case ADD_AND_ENTER_MODULE: {
724
- if (chunkGraph.isModuleInChunk(module, chunk)) {
764
+ const isModuleInChunk = chunkGraph.isModuleInChunk(module, chunk);
765
+
766
+ if (isModuleInChunk) {
725
767
  // already connected, skip it
726
768
  break;
727
769
  }
728
770
  // We connect Module and Chunk
729
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);
730
776
  }
731
777
  // fallthrough
732
778
  case ENTER_MODULE: {
@@ -783,44 +829,22 @@ const visitModules = (
783
829
  }
784
830
  };
785
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
+ */
786
836
  const calculateResultingAvailableModules = chunkGroupInfo => {
787
- if (chunkGroupInfo.resultingAvailableModules)
837
+ if (chunkGroupInfo.resultingAvailableModules !== undefined)
788
838
  return chunkGroupInfo.resultingAvailableModules;
789
839
 
790
- const minAvailableModules = chunkGroupInfo.minAvailableModules;
791
-
792
- // Create a new Set of available modules at this point
793
- // We want to be as lazy as possible. There are multiple ways doing this:
794
- // Note that resultingAvailableModules is stored as "(a) + (b)" as it's a ModuleSetPlus
795
- // - resultingAvailableModules = (modules of chunk) + (minAvailableModules + minAvailableModules.plus)
796
- // - resultingAvailableModules = (minAvailableModules + modules of chunk) + (minAvailableModules.plus)
797
- // We choose one depending on the size of minAvailableModules vs minAvailableModules.plus
798
-
799
- let resultingAvailableModules;
800
- if (minAvailableModules.size > minAvailableModules.plus.size) {
801
- // resultingAvailableModules = (modules of chunk) + (minAvailableModules + minAvailableModules.plus)
802
- resultingAvailableModules =
803
- /** @type {Set<Module> & {plus: Set<Module>}} */ (new Set());
804
- for (const module of minAvailableModules.plus)
805
- minAvailableModules.add(module);
806
- minAvailableModules.plus = EMPTY_SET;
807
- resultingAvailableModules.plus = minAvailableModules;
808
- chunkGroupInfo.minAvailableModulesOwned = false;
809
- } else {
810
- // resultingAvailableModules = (minAvailableModules + modules of chunk) + (minAvailableModules.plus)
811
- resultingAvailableModules =
812
- /** @type {Set<Module> & {plus: Set<Module>}} */ (
813
- new Set(minAvailableModules)
814
- );
815
- resultingAvailableModules.plus = minAvailableModules.plus;
816
- }
840
+ let resultingAvailableModules = chunkGroupInfo.minAvailableModules;
817
841
 
818
842
  // add the modules from the chunk group to the set
819
843
  for (const chunk of chunkGroupInfo.chunkGroup.chunks) {
820
- for (const m of chunkGraph.getChunkModulesIterable(chunk)) {
821
- resultingAvailableModules.add(m);
822
- }
844
+ const mask = maskByChunk.get(chunk);
845
+ resultingAvailableModules |= mask;
823
846
  }
847
+
824
848
  return (chunkGroupInfo.resultingAvailableModules =
825
849
  resultingAvailableModules);
826
850
  };
@@ -867,232 +891,24 @@ const visitModules = (
867
891
  // Execute the merge
868
892
  for (const info of chunkGroupsForMerging) {
869
893
  const availableModulesToBeMerged = info.availableModulesToBeMerged;
870
- let cachedMinAvailableModules = info.minAvailableModules;
894
+ const cachedMinAvailableModules = info.minAvailableModules;
895
+ let minAvailableModules = cachedMinAvailableModules;
871
896
 
872
897
  statMergedAvailableModuleSets += availableModulesToBeMerged.length;
873
898
 
874
- // 1. Get minimal available modules
875
- // It doesn't make sense to traverse a chunk again with more available modules.
876
- // This step calculates the minimal available modules and skips traversal when
877
- // the list didn't shrink.
878
- if (availableModulesToBeMerged.length > 1) {
879
- availableModulesToBeMerged.sort(bySetSize);
880
- }
881
- let changed = false;
882
- merge: for (const availableModules of availableModulesToBeMerged) {
883
- if (cachedMinAvailableModules === undefined) {
884
- cachedMinAvailableModules = availableModules;
885
- info.minAvailableModules = cachedMinAvailableModules;
886
- info.minAvailableModulesOwned = false;
887
- changed = true;
899
+ for (const availableModules of availableModulesToBeMerged) {
900
+ if (minAvailableModules === undefined) {
901
+ minAvailableModules = availableModules;
888
902
  } else {
889
- if (info.minAvailableModulesOwned) {
890
- // We own it and can modify it
891
- if (cachedMinAvailableModules.plus === availableModules.plus) {
892
- for (const m of cachedMinAvailableModules) {
893
- if (!availableModules.has(m)) {
894
- cachedMinAvailableModules.delete(m);
895
- changed = true;
896
- }
897
- }
898
- } else {
899
- for (const m of cachedMinAvailableModules) {
900
- if (!availableModules.has(m) && !availableModules.plus.has(m)) {
901
- cachedMinAvailableModules.delete(m);
902
- changed = true;
903
- }
904
- }
905
- for (const m of cachedMinAvailableModules.plus) {
906
- if (!availableModules.has(m) && !availableModules.plus.has(m)) {
907
- // We can't remove modules from the plus part
908
- // so we need to merge plus into the normal part to allow modifying it
909
- const iterator =
910
- cachedMinAvailableModules.plus[Symbol.iterator]();
911
- // fast forward add all modules until m
912
- /** @type {IteratorResult<Module>} */
913
- let it;
914
- while (!(it = iterator.next()).done) {
915
- const module = it.value;
916
- if (module === m) break;
917
- cachedMinAvailableModules.add(module);
918
- }
919
- // check the remaining modules before adding
920
- while (!(it = iterator.next()).done) {
921
- const module = it.value;
922
- if (
923
- availableModules.has(module) ||
924
- availableModules.plus.has(module)
925
- ) {
926
- cachedMinAvailableModules.add(module);
927
- }
928
- }
929
- cachedMinAvailableModules.plus = EMPTY_SET;
930
- changed = true;
931
- continue merge;
932
- }
933
- }
934
- }
935
- } else if (cachedMinAvailableModules.plus === availableModules.plus) {
936
- // Common and fast case when the plus part is shared
937
- // We only need to care about the normal part
938
- if (availableModules.size < cachedMinAvailableModules.size) {
939
- // the new availableModules is smaller so it's faster to
940
- // fork from the new availableModules
941
- statForkedAvailableModules++;
942
- statForkedAvailableModulesCount += availableModules.size;
943
- statForkedMergedModulesCount += cachedMinAvailableModules.size;
944
- // construct a new Set as intersection of cachedMinAvailableModules and availableModules
945
- const newSet = /** @type {ModuleSetPlus} */ (new Set());
946
- newSet.plus = availableModules.plus;
947
- for (const m of availableModules) {
948
- if (cachedMinAvailableModules.has(m)) {
949
- newSet.add(m);
950
- }
951
- }
952
- statForkedResultModulesCount += newSet.size;
953
- cachedMinAvailableModules = newSet;
954
- info.minAvailableModulesOwned = true;
955
- info.minAvailableModules = newSet;
956
- changed = true;
957
- continue merge;
958
- }
959
- for (const m of cachedMinAvailableModules) {
960
- if (!availableModules.has(m)) {
961
- // cachedMinAvailableModules need to be modified
962
- // but we don't own it
963
- statForkedAvailableModules++;
964
- statForkedAvailableModulesCount +=
965
- cachedMinAvailableModules.size;
966
- statForkedMergedModulesCount += availableModules.size;
967
- // construct a new Set as intersection of cachedMinAvailableModules and availableModules
968
- // as the plus part is equal we can just take over this one
969
- const newSet = /** @type {ModuleSetPlus} */ (new Set());
970
- newSet.plus = availableModules.plus;
971
- const iterator = cachedMinAvailableModules[Symbol.iterator]();
972
- // fast forward add all modules until m
973
- /** @type {IteratorResult<Module>} */
974
- let it;
975
- while (!(it = iterator.next()).done) {
976
- const module = it.value;
977
- if (module === m) break;
978
- newSet.add(module);
979
- }
980
- // check the remaining modules before adding
981
- while (!(it = iterator.next()).done) {
982
- const module = it.value;
983
- if (availableModules.has(module)) {
984
- newSet.add(module);
985
- }
986
- }
987
- statForkedResultModulesCount += newSet.size;
988
- cachedMinAvailableModules = newSet;
989
- info.minAvailableModulesOwned = true;
990
- info.minAvailableModules = newSet;
991
- changed = true;
992
- continue merge;
993
- }
994
- }
995
- } else {
996
- for (const m of cachedMinAvailableModules) {
997
- if (!availableModules.has(m) && !availableModules.plus.has(m)) {
998
- // cachedMinAvailableModules need to be modified
999
- // but we don't own it
1000
- statForkedAvailableModules++;
1001
- statForkedAvailableModulesCount +=
1002
- cachedMinAvailableModules.size;
1003
- statForkedAvailableModulesCountPlus +=
1004
- cachedMinAvailableModules.plus.size;
1005
- statForkedMergedModulesCount += availableModules.size;
1006
- statForkedMergedModulesCountPlus += availableModules.plus.size;
1007
- // construct a new Set as intersection of cachedMinAvailableModules and availableModules
1008
- const newSet = /** @type {ModuleSetPlus} */ (new Set());
1009
- newSet.plus = EMPTY_SET;
1010
- const iterator = cachedMinAvailableModules[Symbol.iterator]();
1011
- // fast forward add all modules until m
1012
- /** @type {IteratorResult<Module>} */
1013
- let it;
1014
- while (!(it = iterator.next()).done) {
1015
- const module = it.value;
1016
- if (module === m) break;
1017
- newSet.add(module);
1018
- }
1019
- // check the remaining modules before adding
1020
- while (!(it = iterator.next()).done) {
1021
- const module = it.value;
1022
- if (
1023
- availableModules.has(module) ||
1024
- availableModules.plus.has(module)
1025
- ) {
1026
- newSet.add(module);
1027
- }
1028
- }
1029
- // also check all modules in cachedMinAvailableModules.plus
1030
- for (const module of cachedMinAvailableModules.plus) {
1031
- if (
1032
- availableModules.has(module) ||
1033
- availableModules.plus.has(module)
1034
- ) {
1035
- newSet.add(module);
1036
- }
1037
- }
1038
- statForkedResultModulesCount += newSet.size;
1039
- cachedMinAvailableModules = newSet;
1040
- info.minAvailableModulesOwned = true;
1041
- info.minAvailableModules = newSet;
1042
- changed = true;
1043
- continue merge;
1044
- }
1045
- }
1046
- for (const m of cachedMinAvailableModules.plus) {
1047
- if (!availableModules.has(m) && !availableModules.plus.has(m)) {
1048
- // cachedMinAvailableModules need to be modified
1049
- // but we don't own it
1050
- statForkedAvailableModules++;
1051
- statForkedAvailableModulesCount +=
1052
- cachedMinAvailableModules.size;
1053
- statForkedAvailableModulesCountPlus +=
1054
- cachedMinAvailableModules.plus.size;
1055
- statForkedMergedModulesCount += availableModules.size;
1056
- statForkedMergedModulesCountPlus += availableModules.plus.size;
1057
- // construct a new Set as intersection of cachedMinAvailableModules and availableModules
1058
- // we already know that all modules directly from cachedMinAvailableModules are in availableModules too
1059
- const newSet = /** @type {ModuleSetPlus} */ (
1060
- new Set(cachedMinAvailableModules)
1061
- );
1062
- newSet.plus = EMPTY_SET;
1063
- const iterator =
1064
- cachedMinAvailableModules.plus[Symbol.iterator]();
1065
- // fast forward add all modules until m
1066
- /** @type {IteratorResult<Module>} */
1067
- let it;
1068
- while (!(it = iterator.next()).done) {
1069
- const module = it.value;
1070
- if (module === m) break;
1071
- newSet.add(module);
1072
- }
1073
- // check the remaining modules before adding
1074
- while (!(it = iterator.next()).done) {
1075
- const module = it.value;
1076
- if (
1077
- availableModules.has(module) ||
1078
- availableModules.plus.has(module)
1079
- ) {
1080
- newSet.add(module);
1081
- }
1082
- }
1083
- statForkedResultModulesCount += newSet.size;
1084
- cachedMinAvailableModules = newSet;
1085
- info.minAvailableModulesOwned = true;
1086
- info.minAvailableModules = newSet;
1087
- changed = true;
1088
- continue merge;
1089
- }
1090
- }
1091
- }
903
+ minAvailableModules &= availableModules;
1092
904
  }
1093
905
  }
906
+
907
+ const changed = minAvailableModules !== cachedMinAvailableModules;
908
+
1094
909
  availableModulesToBeMerged.length = 0;
1095
910
  if (changed) {
911
+ info.minAvailableModules = minAvailableModules;
1096
912
  info.resultingAvailableModules = undefined;
1097
913
  outdatedChunkGroupInfo.add(info);
1098
914
  }
@@ -1105,34 +921,24 @@ const visitModules = (
1105
921
  for (const source of /** @type {Set<ChunkGroupInfo>} */ (
1106
922
  info.availableSources
1107
923
  )) {
1108
- if (!source.minAvailableModules) {
924
+ if (source.minAvailableModules === undefined) {
1109
925
  chunkGroupsForCombining.delete(info);
1110
926
  break;
1111
927
  }
1112
928
  }
1113
929
  }
930
+
1114
931
  for (const info of chunkGroupsForCombining) {
1115
- const availableModules = /** @type {ModuleSetPlus} */ (new Set());
1116
- availableModules.plus = EMPTY_SET;
1117
- const mergeSet = set => {
1118
- if (set.size > availableModules.plus.size) {
1119
- for (const item of availableModules.plus) availableModules.add(item);
1120
- availableModules.plus = set;
1121
- } else {
1122
- for (const item of set) availableModules.add(item);
1123
- }
1124
- };
932
+ let availableModules = ZERO_BIGINT;
1125
933
  // combine minAvailableModules from all resultingAvailableModules
1126
934
  for (const source of /** @type {Set<ChunkGroupInfo>} */ (
1127
935
  info.availableSources
1128
936
  )) {
1129
937
  const resultingAvailableModules =
1130
938
  calculateResultingAvailableModules(source);
1131
- mergeSet(resultingAvailableModules);
1132
- mergeSet(resultingAvailableModules.plus);
939
+ availableModules |= resultingAvailableModules;
1133
940
  }
1134
941
  info.minAvailableModules = availableModules;
1135
- info.minAvailableModulesOwned = false;
1136
942
  info.resultingAvailableModules = undefined;
1137
943
  outdatedChunkGroupInfo.add(info);
1138
944
  }
@@ -1146,13 +952,11 @@ const visitModules = (
1146
952
  // 1. Reconsider skipped items
1147
953
  if (info.skippedItems !== undefined) {
1148
954
  const minAvailableModules =
1149
- /** @type {ModuleSetPlus} */
955
+ /** @type {bigint} */
1150
956
  (info.minAvailableModules);
1151
957
  for (const module of info.skippedItems) {
1152
- if (
1153
- !minAvailableModules.has(module) &&
1154
- !minAvailableModules.plus.has(module)
1155
- ) {
958
+ const ordinal = getModuleOrdinal(module);
959
+ if (!isOrdinalSetInMask(minAvailableModules, ordinal)) {
1156
960
  queue.push({
1157
961
  action: ADD_AND_ENTER_MODULE,
1158
962
  block: module,
@@ -1169,21 +973,22 @@ const visitModules = (
1169
973
  // 2. Reconsider skipped connections
1170
974
  if (info.skippedModuleConnections !== undefined) {
1171
975
  const minAvailableModules =
1172
- /** @type {ModuleSetPlus} */
976
+ /** @type {bigint} */
1173
977
  (info.minAvailableModules);
1174
978
  for (const entry of info.skippedModuleConnections) {
1175
- const [module, activeState] = entry;
979
+ const [module, connections] = entry;
980
+ const activeState = getActiveStateOfConnections(
981
+ connections,
982
+ info.runtime
983
+ );
1176
984
  if (activeState === false) continue;
1177
985
  if (activeState === true) {
986
+ const ordinal = getModuleOrdinal(module);
1178
987
  info.skippedModuleConnections.delete(entry);
1179
- }
1180
- if (
1181
- activeState === true &&
1182
- (minAvailableModules.has(module) ||
1183
- minAvailableModules.plus.has(module))
1184
- ) {
1185
- info.skippedItems.add(module);
1186
- continue;
988
+ if (isOrdinalSetInMask(minAvailableModules, ordinal)) {
989
+ info.skippedItems.add(module);
990
+ continue;
991
+ }
1187
992
  }
1188
993
  queue.push({
1189
994
  action: activeState === true ? ADD_AND_ENTER_MODULE : PROCESS_BLOCK,
@@ -1274,7 +1079,7 @@ const visitModules = (
1274
1079
  let preOrderIndex = 0;
1275
1080
  let postOrderIndex = 0;
1276
1081
 
1277
- const process = (current, visited = new Set()) => {
1082
+ const process = (current, visited) => {
1278
1083
  if (visited.has(current)) {
1279
1084
  return;
1280
1085
  }
@@ -1286,14 +1091,14 @@ const visitModules = (
1286
1091
  return;
1287
1092
  }
1288
1093
 
1289
- for (let i = 0; i < blockModules.length; i += 2) {
1290
- const refModule = /** @type {Module} */ (blockModules[i]);
1094
+ for (let i = 0, len = blockModules.length; i < len; i += 3) {
1291
1095
  const activeState = /** @type {ConnectionState} */ (
1292
1096
  blockModules[i + 1]
1293
1097
  );
1294
1098
  if (activeState === false) {
1295
1099
  continue;
1296
1100
  }
1101
+ const refModule = /** @type {Module} */ (blockModules[i]);
1297
1102
 
1298
1103
  if (refModule) {
1299
1104
  chunkGroup.setModulePreOrderIndex(refModule, preOrderIndex++);
@@ -1303,9 +1108,10 @@ const visitModules = (
1303
1108
  }
1304
1109
  };
1305
1110
 
1306
- process(block);
1111
+ process(block, new Set());
1307
1112
  }
1308
1113
  outdatedOrderIndexChunkGroups.clear();
1114
+ ordinalByModule.clear();
1309
1115
 
1310
1116
  logger.log(
1311
1117
  `${statProcessedQueueItems} queue items processed (${statProcessedBlocks} blocks)`
@@ -1324,13 +1130,13 @@ const visitModules = (
1324
1130
  * @param {Compilation} compilation the compilation
1325
1131
  * @param {Set<DependenciesBlock>} blocksWithNestedBlocks flag for blocks that have nested blocks
1326
1132
  * @param {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} blockConnections connection for blocks
1327
- * @param {Map<ChunkGroup, ChunkGroupInfo>} chunkGroupInfoMap mapping from chunk group to available modules
1133
+ * @param {Map<Chunk, bigint>} maskByChunk mapping from chunk to module mask
1328
1134
  */
1329
1135
  const connectChunkGroups = (
1330
1136
  compilation,
1331
1137
  blocksWithNestedBlocks,
1332
1138
  blockConnections,
1333
- chunkGroupInfoMap
1139
+ maskByChunk
1334
1140
  ) => {
1335
1141
  const { chunkGraph } = compilation;
1336
1142
 
@@ -1338,15 +1144,13 @@ const connectChunkGroups = (
1338
1144
  * Helper function to check if all modules of a chunk are available
1339
1145
  *
1340
1146
  * @param {ChunkGroup} chunkGroup the chunkGroup to scan
1341
- * @param {ModuleSetPlus} availableModules the comparator set
1147
+ * @param {bigint} availableModules the comparator set
1342
1148
  * @returns {boolean} return true if all modules of a chunk are available
1343
1149
  */
1344
1150
  const areModulesAvailable = (chunkGroup, availableModules) => {
1345
1151
  for (const chunk of chunkGroup.chunks) {
1346
- for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
1347
- if (!availableModules.has(module) && !availableModules.plus.has(module))
1348
- return false;
1349
- }
1152
+ const chunkMask = maskByChunk.get(chunk);
1153
+ if ((chunkMask & availableModules) !== chunkMask) return false;
1350
1154
  }
1351
1155
  return true;
1352
1156
  };
@@ -1431,6 +1235,9 @@ const buildChunkGraph = (compilation, inputEntrypointsAndModules) => {
1431
1235
  /** @type {Set<DependenciesBlock>} */
1432
1236
  const blocksWithNestedBlocks = new Set();
1433
1237
 
1238
+ /** @type {Map<Chunk, bigint>} */
1239
+ const maskByChunk = new Map();
1240
+
1434
1241
  // PART ONE
1435
1242
 
1436
1243
  logger.time("visitModules");
@@ -1441,7 +1248,8 @@ const buildChunkGraph = (compilation, inputEntrypointsAndModules) => {
1441
1248
  chunkGroupInfoMap,
1442
1249
  blockConnections,
1443
1250
  blocksWithNestedBlocks,
1444
- allCreatedChunkGroups
1251
+ allCreatedChunkGroups,
1252
+ maskByChunk
1445
1253
  );
1446
1254
  logger.timeEnd("visitModules");
1447
1255
 
@@ -1452,7 +1260,7 @@ const buildChunkGraph = (compilation, inputEntrypointsAndModules) => {
1452
1260
  compilation,
1453
1261
  blocksWithNestedBlocks,
1454
1262
  blockConnections,
1455
- chunkGroupInfoMap
1263
+ maskByChunk
1456
1264
  );
1457
1265
  logger.timeEnd("connectChunkGroups");
1458
1266