webpack 5.51.1 → 5.53.0

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.

@@ -76,7 +76,9 @@ makeSerializable(
76
76
 
77
77
  const MIN_CONTENT_SIZE = 1024 * 1024; // 1 MB
78
78
  const CONTENT_COUNT_TO_MERGE = 10;
79
+ const MIN_ITEMS_IN_FRESH_PACK = 100;
79
80
  const MAX_ITEMS_IN_FRESH_PACK = 50000;
81
+ const MAX_TIME_IN_FRESH_PACK = 1 * 60 * 1000; // 1 min
80
82
 
81
83
  class PackItemInfo {
82
84
  /**
@@ -99,6 +101,7 @@ class Pack {
99
101
  this.itemInfo = new Map();
100
102
  /** @type {string[]} */
101
103
  this.requests = [];
104
+ this.requestsTimeout = undefined;
102
105
  /** @type {Map<string, PackItemInfo>} */
103
106
  this.freshContent = new Map();
104
107
  /** @type {(undefined | PackContent)[]} */
@@ -108,6 +111,24 @@ class Pack {
108
111
  this.maxAge = maxAge;
109
112
  }
110
113
 
114
+ _addRequest(identifier) {
115
+ this.requests.push(identifier);
116
+ if (this.requestsTimeout === undefined) {
117
+ this.requestsTimeout = setTimeout(() => {
118
+ this.requests.push(undefined);
119
+ this.requestsTimeout = undefined;
120
+ }, MAX_TIME_IN_FRESH_PACK);
121
+ if (this.requestsTimeout.unref) this.requestsTimeout.unref();
122
+ }
123
+ }
124
+
125
+ stopCapturingRequests() {
126
+ if (this.requestsTimeout !== undefined) {
127
+ clearTimeout(this.requestsTimeout);
128
+ this.requestsTimeout = undefined;
129
+ }
130
+ }
131
+
111
132
  /**
112
133
  * @param {string} identifier unique name for the resource
113
134
  * @param {string | null} etag etag of the resource
@@ -115,7 +136,7 @@ class Pack {
115
136
  */
116
137
  get(identifier, etag) {
117
138
  const info = this.itemInfo.get(identifier);
118
- this.requests.push(identifier);
139
+ this._addRequest(identifier);
119
140
  if (info === undefined) {
120
141
  return undefined;
121
142
  }
@@ -147,12 +168,12 @@ class Pack {
147
168
  if (info === undefined) {
148
169
  const newInfo = new PackItemInfo(identifier, etag, data);
149
170
  this.itemInfo.set(identifier, newInfo);
150
- this.requests.push(identifier);
171
+ this._addRequest(identifier);
151
172
  this.freshContent.set(identifier, newInfo);
152
173
  } else {
153
174
  const loc = info.location;
154
175
  if (loc >= 0) {
155
- this.requests.push(identifier);
176
+ this._addRequest(identifier);
156
177
  this.freshContent.set(identifier, info);
157
178
  const content = this.content[loc];
158
179
  content.delete(identifier);
@@ -220,27 +241,39 @@ class Pack {
220
241
  }
221
242
 
222
243
  _persistFreshContent() {
223
- if (this.freshContent.size > 0) {
224
- const packCount = Math.ceil(
225
- this.freshContent.size / MAX_ITEMS_IN_FRESH_PACK
226
- );
227
- const itemsPerPack = Math.ceil(this.freshContent.size / packCount);
228
- this.logger.log(`${this.freshContent.size} fresh items in cache`);
229
- const packs = Array.from({ length: packCount }, () => {
244
+ const itemsCount = this.freshContent.size;
245
+ if (itemsCount > 0) {
246
+ const packCount = Math.ceil(itemsCount / MAX_ITEMS_IN_FRESH_PACK);
247
+ const itemsPerPack = Math.ceil(itemsCount / packCount);
248
+ const packs = [];
249
+ let i = 0;
250
+ let ignoreNextTimeTick = false;
251
+ const createNextPack = () => {
230
252
  const loc = this._findLocation();
231
253
  this.content[loc] = null; // reserve
232
- return {
254
+ const pack = {
233
255
  /** @type {Set<string>} */
234
256
  items: new Set(),
235
257
  /** @type {Map<string, any>} */
236
258
  map: new Map(),
237
259
  loc
238
260
  };
239
- });
240
- let i = 0;
241
- let pack = packs[0];
242
- let packIndex = 0;
261
+ packs.push(pack);
262
+ return pack;
263
+ };
264
+ let pack = createNextPack();
265
+ if (this.requestsTimeout !== undefined)
266
+ clearTimeout(this.requestsTimeout);
243
267
  for (const identifier of this.requests) {
268
+ if (identifier === undefined) {
269
+ if (ignoreNextTimeTick) {
270
+ ignoreNextTimeTick = false;
271
+ } else if (pack.items.size >= MIN_ITEMS_IN_FRESH_PACK) {
272
+ i = 0;
273
+ pack = createNextPack();
274
+ }
275
+ continue;
276
+ }
244
277
  const info = this.freshContent.get(identifier);
245
278
  if (info === undefined) continue;
246
279
  pack.items.add(identifier);
@@ -250,9 +283,11 @@ class Pack {
250
283
  this.freshContent.delete(identifier);
251
284
  if (++i > itemsPerPack) {
252
285
  i = 0;
253
- pack = packs[++packIndex];
286
+ pack = createNextPack();
287
+ ignoreNextTimeTick = true;
254
288
  }
255
289
  }
290
+ this.requests.length = 0;
256
291
  for (const pack of packs) {
257
292
  this.content[pack.loc] = new PackContent(
258
293
  pack.items,
@@ -260,6 +295,15 @@ class Pack {
260
295
  new PackContentItems(pack.map)
261
296
  );
262
297
  }
298
+ this.logger.log(
299
+ `${itemsCount} fresh items in cache put into pack ${
300
+ packs.length > 1
301
+ ? packs
302
+ .map(pack => `${pack.loc} (${pack.items.size} items)`)
303
+ .join(", ")
304
+ : packs[0].loc
305
+ }`
306
+ );
263
307
  }
264
308
  }
265
309
 
@@ -332,7 +376,9 @@ class Pack {
332
376
  addToMergedMap.push(async map => {
333
377
  // unpack existing content
334
378
  // after that values are accessible in .content
335
- await content.unpack();
379
+ await content.unpack(
380
+ "it should be merged with other small pack contents"
381
+ );
336
382
  for (const [identifier, value] of content.content) {
337
383
  map.set(identifier, value);
338
384
  }
@@ -392,7 +438,9 @@ class Pack {
392
438
  usedItems,
393
439
  new Set(usedItems),
394
440
  async () => {
395
- await content.unpack();
441
+ await content.unpack(
442
+ "it should be splitted into used and unused items"
443
+ );
396
444
  const map = new Map();
397
445
  for (const identifier of usedItems) {
398
446
  map.set(identifier, content.content.get(identifier));
@@ -417,7 +465,9 @@ class Pack {
417
465
  unusedItems,
418
466
  usedOfUnusedItems,
419
467
  async () => {
420
- await content.unpack();
468
+ await content.unpack(
469
+ "it should be splitted into used and unused items"
470
+ );
421
471
  const map = new Map();
422
472
  for (const identifier of unusedItems) {
423
473
  map.set(identifier, content.content.get(identifier));
@@ -466,7 +516,9 @@ class Pack {
466
516
  this.content[loc] =
467
517
  items.size > 0
468
518
  ? new PackContent(items, usedItems, async () => {
469
- await content.unpack();
519
+ await content.unpack(
520
+ "it contains old items that should be garbage collected"
521
+ );
470
522
  const map = new Map();
471
523
  for (const identifier of items) {
472
524
  map.set(identifier, content.content.get(identifier));
@@ -496,7 +548,7 @@ class Pack {
496
548
  const content = this.content[i];
497
549
  if (content !== undefined) {
498
550
  write(content.items);
499
- writeSeparate(content.getLazyContentItems(), { name: `${i}` });
551
+ content.writeLazy(lazy => writeSeparate(lazy, { name: `${i}` }));
500
552
  } else {
501
553
  write(undefined); // undefined marks an empty content slot
502
554
  }
@@ -669,6 +721,25 @@ makeSerializable(
669
721
  );
670
722
 
671
723
  class PackContent {
724
+ /*
725
+ This class can be in these states:
726
+ | this.lazy | this.content | this.outdated | state
727
+ A1 | undefined | Map | false | fresh content
728
+ A2 | undefined | Map | true | (will not happen)
729
+ B1 | lazy () => {} | undefined | false | not deserialized
730
+ B2 | lazy () => {} | undefined | true | not deserialized, but some items has been removed
731
+ C1 | lazy* () => {} | Map | false | deserialized
732
+ C2 | lazy* () => {} | Map | true | deserialized, and some items has been removed
733
+
734
+ this.used is a subset of this.items.
735
+ this.items is a subset of this.content.keys() resp. this.lazy().map.keys()
736
+ When this.outdated === false, this.items === this.content.keys() resp. this.lazy().map.keys()
737
+ When this.outdated === true, this.items should be used to recreated this.lazy/this.content.
738
+ When this.lazy and this.content is set, they contain the same data.
739
+ this.get must only be called with a valid item from this.items.
740
+ In state C this.lazy is unMemoized
741
+ */
742
+
672
743
  /**
673
744
  * @param {Set<string>} items keys
674
745
  * @param {Set<string>} usedItems used keys
@@ -678,7 +749,7 @@ class PackContent {
678
749
  */
679
750
  constructor(items, usedItems, dataOrFn, logger, lazyName) {
680
751
  this.items = items;
681
- /** @type {function(): Promise<PackContentItems> | PackContentItems } */
752
+ /** @type {function(): Promise<PackContentItems> | PackContentItems} */
682
753
  this.lazy = typeof dataOrFn === "function" ? dataOrFn : undefined;
683
754
  /** @type {Map<string, any>} */
684
755
  this.content = typeof dataOrFn === "function" ? undefined : dataOrFn.map;
@@ -693,6 +764,8 @@ class PackContent {
693
764
  if (this.content) {
694
765
  return this.content.get(identifier);
695
766
  }
767
+
768
+ // We are in state B
696
769
  const { lazyName } = this;
697
770
  let timeMessage;
698
771
  if (lazyName) {
@@ -715,6 +788,7 @@ class PackContent {
715
788
  if (timeMessage) {
716
789
  this.logger.timeEnd(timeMessage);
717
790
  }
791
+ // Move to state C
718
792
  this.content = map;
719
793
  this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
720
794
  return map.get(identifier);
@@ -724,6 +798,7 @@ class PackContent {
724
798
  if (timeMessage) {
725
799
  this.logger.timeEnd(timeMessage);
726
800
  }
801
+ // Move to state C
727
802
  this.content = map;
728
803
  this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
729
804
  return map.get(identifier);
@@ -731,10 +806,13 @@ class PackContent {
731
806
  }
732
807
 
733
808
  /**
809
+ * @param {string} reason explanation why unpack is necessary
734
810
  * @returns {void | Promise} maybe a promise if lazy
735
811
  */
736
- unpack() {
812
+ unpack(reason) {
737
813
  if (this.content) return;
814
+
815
+ // Move from state B to C
738
816
  if (this.lazy) {
739
817
  const { lazyName } = this;
740
818
  let timeMessage;
@@ -744,6 +822,11 @@ class PackContent {
744
822
  timeMessage = `unpack cache content ${lazyName} (${formatSize(
745
823
  this.getSize()
746
824
  )})`;
825
+ this.logger.log(
826
+ `starting to unpack cache content ${lazyName} (${formatSize(
827
+ this.getSize()
828
+ )}) because ${reason}`
829
+ );
747
830
  this.logger.time(timeMessage);
748
831
  }
749
832
  const value = this.lazy();
@@ -782,48 +865,93 @@ class PackContent {
782
865
  }
783
866
 
784
867
  /**
785
- * @returns {function(): PackContentItems | Promise<PackContentItems>} lazy content items
868
+ * @template T
869
+ * @param {function(any): function(): Promise<PackContentItems> | PackContentItems} write write function
870
+ * @returns {void}
786
871
  */
787
- getLazyContentItems() {
788
- if (!this.outdated && this.lazy) return this.lazy;
872
+ writeLazy(write) {
873
+ if (!this.outdated && this.lazy) {
874
+ // State B1 or C1
875
+ // this.lazy is still the valid deserialized version
876
+ write(this.lazy);
877
+ return;
878
+ }
789
879
  if (!this.outdated && this.content) {
880
+ // State A1
790
881
  const map = new Map(this.content);
791
- return (this.lazy = memoize(() => new PackContentItems(map)));
882
+ // Move to state C1
883
+ this.lazy = SerializerMiddleware.unMemoizeLazy(
884
+ write(() => new PackContentItems(map))
885
+ );
886
+ return;
792
887
  }
793
- this.outdated = false;
794
888
  if (this.content) {
795
- return (this.lazy = memoize(() => {
796
- /** @type {Map<string, any>} */
797
- const map = new Map();
798
- for (const item of this.items) {
799
- map.set(item, this.content.get(item));
800
- }
801
- return new PackContentItems(map);
802
- }));
889
+ // State A2 or C2
890
+ /** @type {Map<string, any>} */
891
+ const map = new Map();
892
+ for (const item of this.items) {
893
+ map.set(item, this.content.get(item));
894
+ }
895
+ // Move to state C1
896
+ this.outdated = false;
897
+ this.content = map;
898
+ this.lazy = SerializerMiddleware.unMemoizeLazy(
899
+ write(() => new PackContentItems(map))
900
+ );
901
+ return;
803
902
  }
804
- const lazy = this.lazy;
805
- return (this.lazy = () => {
806
- const value = lazy();
807
- if (value instanceof Promise) {
808
- return value.then(data => {
903
+ // State B2
904
+ const { lazyName } = this;
905
+ let timeMessage;
906
+ if (lazyName) {
907
+ // only log once
908
+ this.lazyName = undefined;
909
+ timeMessage = `unpack cache content ${lazyName} (${formatSize(
910
+ this.getSize()
911
+ )})`;
912
+ this.logger.log(
913
+ `starting to unpack cache content ${lazyName} (${formatSize(
914
+ this.getSize()
915
+ )}) because it's outdated and need to be serialized`
916
+ );
917
+ this.logger.time(timeMessage);
918
+ }
919
+ const value = this.lazy();
920
+ this.outdated = false;
921
+ if (value instanceof Promise) {
922
+ // Move to state B1
923
+ this.lazy = write(() =>
924
+ value.then(data => {
925
+ if (timeMessage) {
926
+ this.logger.timeEnd(timeMessage);
927
+ }
809
928
  const oldMap = data.map;
810
929
  /** @type {Map<string, any>} */
811
930
  const map = new Map();
812
931
  for (const item of this.items) {
813
932
  map.set(item, oldMap.get(item));
814
933
  }
934
+ // Move to state C1 (or maybe C2)
935
+ this.content = map;
936
+ this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
937
+
815
938
  return new PackContentItems(map);
816
- });
817
- } else {
818
- const oldMap = value.map;
819
- /** @type {Map<string, any>} */
820
- const map = new Map();
821
- for (const item of this.items) {
822
- map.set(item, oldMap.get(item));
823
- }
824
- return new PackContentItems(map);
939
+ })
940
+ );
941
+ } else {
942
+ // Move to state C1
943
+ if (timeMessage) {
944
+ this.logger.timeEnd(timeMessage);
825
945
  }
826
- });
946
+ const oldMap = value.map;
947
+ /** @type {Map<string, any>} */
948
+ const map = new Map();
949
+ for (const item of this.items) {
950
+ map.set(item, oldMap.get(item));
951
+ }
952
+ this.content = map;
953
+ this.lazy = write(() => new PackContentItems(map));
954
+ }
827
955
  }
828
956
  }
829
957
 
@@ -1110,10 +1238,11 @@ class PackFileCacheStrategy {
1110
1238
  const packPromise = this.packPromise;
1111
1239
  if (packPromise === undefined) return Promise.resolve();
1112
1240
  const reportProgress = ProgressPlugin.getReporter(this.compiler);
1113
- this.packPromise = undefined;
1114
1241
  return (this.storePromise = packPromise
1115
1242
  .then(pack => {
1243
+ pack.stopCapturingRequests();
1116
1244
  if (!pack.invalid) return;
1245
+ this.packPromise = undefined;
1117
1246
  this.logger.log(`Storing pack...`);
1118
1247
  let promise;
1119
1248
  const newBuildDependencies = new Set();
@@ -211,7 +211,10 @@ const applyWebpackOptionsDefaults = options => {
211
211
  : "var";
212
212
  });
213
213
 
214
- applyNodeDefaults(options.node, { targetProperties });
214
+ applyNodeDefaults(options.node, {
215
+ futureDefaults: options.experiments.futureDefaults,
216
+ targetProperties
217
+ });
215
218
 
216
219
  F(options, "performance", () =>
217
220
  production &&
@@ -259,10 +262,10 @@ const applyExperimentsDefaults = (experiments, { production, development }) => {
259
262
  D(experiments, "asyncWebAssembly", false);
260
263
  D(experiments, "outputModule", false);
261
264
  D(experiments, "asset", false);
262
- D(experiments, "executeModule", false);
263
265
  D(experiments, "layers", false);
264
266
  D(experiments, "lazyCompilation", false);
265
267
  D(experiments, "buildHttp", false);
268
+ D(experiments, "futureDefaults", false);
266
269
 
267
270
  if (typeof experiments.buildHttp === "object") {
268
271
  D(experiments.buildHttp, "frozen", production);
@@ -944,21 +947,26 @@ const applyLoaderDefaults = (loader, { targetProperties }) => {
944
947
  * @param {WebpackNode} node options
945
948
  * @param {Object} options options
946
949
  * @param {TargetProperties | false} options.targetProperties target properties
950
+ * @param {boolean} options.futureDefaults is future defaults enabled
947
951
  * @returns {void}
948
952
  */
949
- const applyNodeDefaults = (node, { targetProperties }) => {
953
+ const applyNodeDefaults = (node, { futureDefaults, targetProperties }) => {
950
954
  if (node === false) return;
955
+
951
956
  F(node, "global", () => {
952
957
  if (targetProperties && targetProperties.global) return false;
953
- return true;
958
+ // TODO webpack 6 should always default to false
959
+ return futureDefaults ? "warn" : true;
954
960
  });
955
961
  F(node, "__filename", () => {
956
962
  if (targetProperties && targetProperties.node) return "eval-only";
957
- return "mock";
963
+ // TODO webpack 6 should always default to false
964
+ return futureDefaults ? "warn-mock" : "mock";
958
965
  });
959
966
  F(node, "__dirname", () => {
960
967
  if (targetProperties && targetProperties.node) return "eval-only";
961
- return "mock";
968
+ // TODO webpack 6 should always default to false
969
+ return futureDefaults ? "warn-mock" : "mock";
962
970
  });
963
971
  };
964
972
 
@@ -1039,7 +1039,9 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
1039
1039
  ids,
1040
1040
  runtimeRequirements
1041
1041
  ),
1042
- InitFragment.STAGE_HARMONY_IMPORTS,
1042
+ moduleGraph.isAsync(importedModule)
1043
+ ? InitFragment.STAGE_ASYNC_HARMONY_IMPORTS
1044
+ : InitFragment.STAGE_HARMONY_IMPORTS,
1043
1045
  dep.sourceOrder
1044
1046
  )
1045
1047
  );
@@ -1100,7 +1102,9 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
1100
1102
  initFragments.push(
1101
1103
  new InitFragment(
1102
1104
  `${content}\n/* harmony reexport (unknown) */ ${RuntimeGlobals.definePropertyGetters}(${exportsName}, __WEBPACK_REEXPORT_OBJECT__);\n`,
1103
- InitFragment.STAGE_HARMONY_IMPORTS,
1105
+ moduleGraph.isAsync(importedModule)
1106
+ ? InitFragment.STAGE_ASYNC_HARMONY_IMPORTS
1107
+ : InitFragment.STAGE_HARMONY_IMPORTS,
1104
1108
  dep.sourceOrder
1105
1109
  )
1106
1110
  );