webpack 5.52.0 → 5.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

package/bin/webpack.js CHANGED
File without changes
@@ -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,16 @@ 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
+ }
122
+ }
123
+
111
124
  /**
112
125
  * @param {string} identifier unique name for the resource
113
126
  * @param {string | null} etag etag of the resource
@@ -115,7 +128,7 @@ class Pack {
115
128
  */
116
129
  get(identifier, etag) {
117
130
  const info = this.itemInfo.get(identifier);
118
- this.requests.push(identifier);
131
+ this._addRequest(identifier);
119
132
  if (info === undefined) {
120
133
  return undefined;
121
134
  }
@@ -147,12 +160,12 @@ class Pack {
147
160
  if (info === undefined) {
148
161
  const newInfo = new PackItemInfo(identifier, etag, data);
149
162
  this.itemInfo.set(identifier, newInfo);
150
- this.requests.push(identifier);
163
+ this._addRequest(identifier);
151
164
  this.freshContent.set(identifier, newInfo);
152
165
  } else {
153
166
  const loc = info.location;
154
167
  if (loc >= 0) {
155
- this.requests.push(identifier);
168
+ this._addRequest(identifier);
156
169
  this.freshContent.set(identifier, info);
157
170
  const content = this.content[loc];
158
171
  content.delete(identifier);
@@ -220,27 +233,39 @@ class Pack {
220
233
  }
221
234
 
222
235
  _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 }, () => {
236
+ const itemsCount = this.freshContent.size;
237
+ if (itemsCount > 0) {
238
+ const packCount = Math.ceil(itemsCount / MAX_ITEMS_IN_FRESH_PACK);
239
+ const itemsPerPack = Math.ceil(itemsCount / packCount);
240
+ const packs = [];
241
+ let i = 0;
242
+ let ignoreNextTimeTick = false;
243
+ const createNextPack = () => {
230
244
  const loc = this._findLocation();
231
245
  this.content[loc] = null; // reserve
232
- return {
246
+ const pack = {
233
247
  /** @type {Set<string>} */
234
248
  items: new Set(),
235
249
  /** @type {Map<string, any>} */
236
250
  map: new Map(),
237
251
  loc
238
252
  };
239
- });
240
- let i = 0;
241
- let pack = packs[0];
242
- let packIndex = 0;
253
+ packs.push(pack);
254
+ return pack;
255
+ };
256
+ let pack = createNextPack();
257
+ if (this.requestsTimeout !== undefined)
258
+ clearTimeout(this.requestsTimeout);
243
259
  for (const identifier of this.requests) {
260
+ if (identifier === undefined) {
261
+ if (ignoreNextTimeTick) {
262
+ ignoreNextTimeTick = false;
263
+ } else if (pack.items.size >= MIN_ITEMS_IN_FRESH_PACK) {
264
+ i = 0;
265
+ pack = createNextPack();
266
+ }
267
+ continue;
268
+ }
244
269
  const info = this.freshContent.get(identifier);
245
270
  if (info === undefined) continue;
246
271
  pack.items.add(identifier);
@@ -250,9 +275,11 @@ class Pack {
250
275
  this.freshContent.delete(identifier);
251
276
  if (++i > itemsPerPack) {
252
277
  i = 0;
253
- pack = packs[++packIndex];
278
+ pack = createNextPack();
279
+ ignoreNextTimeTick = true;
254
280
  }
255
281
  }
282
+ this.requests.length = 0;
256
283
  for (const pack of packs) {
257
284
  this.content[pack.loc] = new PackContent(
258
285
  pack.items,
@@ -260,6 +287,15 @@ class Pack {
260
287
  new PackContentItems(pack.map)
261
288
  );
262
289
  }
290
+ this.logger.log(
291
+ `${itemsCount} fresh items in cache put into pack ${
292
+ packs.length > 1
293
+ ? packs
294
+ .map(pack => `${pack.loc} (${pack.items.size} items)`)
295
+ .join(", ")
296
+ : packs[0].loc
297
+ }`
298
+ );
263
299
  }
264
300
  }
265
301
 
@@ -332,7 +368,9 @@ class Pack {
332
368
  addToMergedMap.push(async map => {
333
369
  // unpack existing content
334
370
  // after that values are accessible in .content
335
- await content.unpack();
371
+ await content.unpack(
372
+ "it should be merged with other small pack contents"
373
+ );
336
374
  for (const [identifier, value] of content.content) {
337
375
  map.set(identifier, value);
338
376
  }
@@ -392,7 +430,9 @@ class Pack {
392
430
  usedItems,
393
431
  new Set(usedItems),
394
432
  async () => {
395
- await content.unpack();
433
+ await content.unpack(
434
+ "it should be splitted into used and unused items"
435
+ );
396
436
  const map = new Map();
397
437
  for (const identifier of usedItems) {
398
438
  map.set(identifier, content.content.get(identifier));
@@ -417,7 +457,9 @@ class Pack {
417
457
  unusedItems,
418
458
  usedOfUnusedItems,
419
459
  async () => {
420
- await content.unpack();
460
+ await content.unpack(
461
+ "it should be splitted into used and unused items"
462
+ );
421
463
  const map = new Map();
422
464
  for (const identifier of unusedItems) {
423
465
  map.set(identifier, content.content.get(identifier));
@@ -466,7 +508,9 @@ class Pack {
466
508
  this.content[loc] =
467
509
  items.size > 0
468
510
  ? new PackContent(items, usedItems, async () => {
469
- await content.unpack();
511
+ await content.unpack(
512
+ "it contains old items that should be garbage collected"
513
+ );
470
514
  const map = new Map();
471
515
  for (const identifier of items) {
472
516
  map.set(identifier, content.content.get(identifier));
@@ -496,7 +540,7 @@ class Pack {
496
540
  const content = this.content[i];
497
541
  if (content !== undefined) {
498
542
  write(content.items);
499
- writeSeparate(content.getLazyContentItems(), { name: `${i}` });
543
+ content.writeLazy(lazy => writeSeparate(lazy, { name: `${i}` }));
500
544
  } else {
501
545
  write(undefined); // undefined marks an empty content slot
502
546
  }
@@ -669,6 +713,25 @@ makeSerializable(
669
713
  );
670
714
 
671
715
  class PackContent {
716
+ /*
717
+ This class can be in these states:
718
+ | this.lazy | this.content | this.outdated | state
719
+ A1 | undefined | Map | false | fresh content
720
+ A2 | undefined | Map | true | (will not happen)
721
+ B1 | lazy () => {} | undefined | false | not deserialized
722
+ B2 | lazy () => {} | undefined | true | not deserialized, but some items has been removed
723
+ C1 | lazy* () => {} | Map | false | deserialized
724
+ C2 | lazy* () => {} | Map | true | deserialized, and some items has been removed
725
+
726
+ this.used is a subset of this.items.
727
+ this.items is a subset of this.content.keys() resp. this.lazy().map.keys()
728
+ When this.outdated === false, this.items === this.content.keys() resp. this.lazy().map.keys()
729
+ When this.outdated === true, this.items should be used to recreated this.lazy/this.content.
730
+ When this.lazy and this.content is set, they contain the same data.
731
+ this.get must only be called with a valid item from this.items.
732
+ In state C this.lazy is unMemoized
733
+ */
734
+
672
735
  /**
673
736
  * @param {Set<string>} items keys
674
737
  * @param {Set<string>} usedItems used keys
@@ -678,7 +741,7 @@ class PackContent {
678
741
  */
679
742
  constructor(items, usedItems, dataOrFn, logger, lazyName) {
680
743
  this.items = items;
681
- /** @type {function(): Promise<PackContentItems> | PackContentItems } */
744
+ /** @type {function(): Promise<PackContentItems> | PackContentItems} */
682
745
  this.lazy = typeof dataOrFn === "function" ? dataOrFn : undefined;
683
746
  /** @type {Map<string, any>} */
684
747
  this.content = typeof dataOrFn === "function" ? undefined : dataOrFn.map;
@@ -693,6 +756,8 @@ class PackContent {
693
756
  if (this.content) {
694
757
  return this.content.get(identifier);
695
758
  }
759
+
760
+ // We are in state B
696
761
  const { lazyName } = this;
697
762
  let timeMessage;
698
763
  if (lazyName) {
@@ -715,6 +780,7 @@ class PackContent {
715
780
  if (timeMessage) {
716
781
  this.logger.timeEnd(timeMessage);
717
782
  }
783
+ // Move to state C
718
784
  this.content = map;
719
785
  this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
720
786
  return map.get(identifier);
@@ -724,6 +790,7 @@ class PackContent {
724
790
  if (timeMessage) {
725
791
  this.logger.timeEnd(timeMessage);
726
792
  }
793
+ // Move to state C
727
794
  this.content = map;
728
795
  this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
729
796
  return map.get(identifier);
@@ -731,10 +798,13 @@ class PackContent {
731
798
  }
732
799
 
733
800
  /**
801
+ * @param {string} reason explanation why unpack is necessary
734
802
  * @returns {void | Promise} maybe a promise if lazy
735
803
  */
736
- unpack() {
804
+ unpack(reason) {
737
805
  if (this.content) return;
806
+
807
+ // Move from state B to C
738
808
  if (this.lazy) {
739
809
  const { lazyName } = this;
740
810
  let timeMessage;
@@ -744,6 +814,11 @@ class PackContent {
744
814
  timeMessage = `unpack cache content ${lazyName} (${formatSize(
745
815
  this.getSize()
746
816
  )})`;
817
+ this.logger.log(
818
+ `starting to unpack cache content ${lazyName} (${formatSize(
819
+ this.getSize()
820
+ )}) because ${reason}`
821
+ );
747
822
  this.logger.time(timeMessage);
748
823
  }
749
824
  const value = this.lazy();
@@ -782,48 +857,93 @@ class PackContent {
782
857
  }
783
858
 
784
859
  /**
785
- * @returns {function(): PackContentItems | Promise<PackContentItems>} lazy content items
860
+ * @template T
861
+ * @param {function(any): function(): Promise<PackContentItems> | PackContentItems} write write function
862
+ * @returns {void}
786
863
  */
787
- getLazyContentItems() {
788
- if (!this.outdated && this.lazy) return this.lazy;
864
+ writeLazy(write) {
865
+ if (!this.outdated && this.lazy) {
866
+ // State B1 or C1
867
+ // this.lazy is still the valid deserialized version
868
+ write(this.lazy);
869
+ return;
870
+ }
789
871
  if (!this.outdated && this.content) {
872
+ // State A1
790
873
  const map = new Map(this.content);
791
- return (this.lazy = memoize(() => new PackContentItems(map)));
874
+ // Move to state C1
875
+ this.lazy = SerializerMiddleware.unMemoizeLazy(
876
+ write(() => new PackContentItems(map))
877
+ );
878
+ return;
792
879
  }
793
- this.outdated = false;
794
880
  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
- }));
881
+ // State A2 or C2
882
+ /** @type {Map<string, any>} */
883
+ const map = new Map();
884
+ for (const item of this.items) {
885
+ map.set(item, this.content.get(item));
886
+ }
887
+ // Move to state C1
888
+ this.outdated = false;
889
+ this.content = map;
890
+ this.lazy = SerializerMiddleware.unMemoizeLazy(
891
+ write(() => new PackContentItems(map))
892
+ );
893
+ return;
803
894
  }
804
- const lazy = this.lazy;
805
- return (this.lazy = () => {
806
- const value = lazy();
807
- if (value instanceof Promise) {
808
- return value.then(data => {
895
+ // State B2
896
+ const { lazyName } = this;
897
+ let timeMessage;
898
+ if (lazyName) {
899
+ // only log once
900
+ this.lazyName = undefined;
901
+ timeMessage = `unpack cache content ${lazyName} (${formatSize(
902
+ this.getSize()
903
+ )})`;
904
+ this.logger.log(
905
+ `starting to unpack cache content ${lazyName} (${formatSize(
906
+ this.getSize()
907
+ )}) because it's outdated and need to be serialized`
908
+ );
909
+ this.logger.time(timeMessage);
910
+ }
911
+ const value = this.lazy();
912
+ this.outdated = false;
913
+ if (value instanceof Promise) {
914
+ // Move to state B1
915
+ this.lazy = write(() =>
916
+ value.then(data => {
917
+ if (timeMessage) {
918
+ this.logger.timeEnd(timeMessage);
919
+ }
809
920
  const oldMap = data.map;
810
921
  /** @type {Map<string, any>} */
811
922
  const map = new Map();
812
923
  for (const item of this.items) {
813
924
  map.set(item, oldMap.get(item));
814
925
  }
926
+ // Move to state C1 (or maybe C2)
927
+ this.content = map;
928
+ this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
929
+
815
930
  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);
931
+ })
932
+ );
933
+ } else {
934
+ // Move to state C1
935
+ if (timeMessage) {
936
+ this.logger.timeEnd(timeMessage);
825
937
  }
826
- });
938
+ const oldMap = value.map;
939
+ /** @type {Map<string, any>} */
940
+ const map = new Map();
941
+ for (const item of this.items) {
942
+ map.set(item, oldMap.get(item));
943
+ }
944
+ this.content = map;
945
+ this.lazy = write(() => new PackContentItems(map));
946
+ }
827
947
  }
828
948
  }
829
949
 
@@ -1110,10 +1230,10 @@ class PackFileCacheStrategy {
1110
1230
  const packPromise = this.packPromise;
1111
1231
  if (packPromise === undefined) return Promise.resolve();
1112
1232
  const reportProgress = ProgressPlugin.getReporter(this.compiler);
1113
- this.packPromise = undefined;
1114
1233
  return (this.storePromise = packPromise
1115
1234
  .then(pack => {
1116
1235
  if (!pack.invalid) return;
1236
+ this.packPromise = undefined;
1117
1237
  this.logger.log(`Storing pack...`);
1118
1238
  let promise;
1119
1239
  const newBuildDependencies = new Set();
@@ -30,7 +30,7 @@ class RelativeUrlRuntimeModule extends HelperRuntimeModule {
30
30
  `values.toString = values.toJSON = ${runtimeTemplate.returningFunction(
31
31
  "url"
32
32
  )};`,
33
- "for (var key in values) Object.defineProperty(this, key, Object.assign({ enumerable: true, configurable: true, value: values[key] }));"
33
+ "for (var key in values) Object.defineProperty(this, key, { enumerable: true, configurable: true, value: values[key] });"
34
34
  ]),
35
35
  "};",
36
36
  `${RuntimeGlobals.relativeUrl}.prototype = URL.prototype;`
@@ -510,11 +510,11 @@ class ObjectMiddleware extends SerializerMiddleware {
510
510
  } else if (SerializerMiddleware.isLazy(item, this)) {
511
511
  throw new Error("Not implemented");
512
512
  } else {
513
- result.push(
514
- SerializerMiddleware.serializeLazy(item, data =>
515
- this.serialize([data], context)
516
- )
513
+ const data = SerializerMiddleware.serializeLazy(item, data =>
514
+ this.serialize([data], context)
517
515
  );
516
+ SerializerMiddleware.setLazySerializedValue(item, data);
517
+ result.push(data);
518
518
  }
519
519
  } else if (item === undefined) {
520
520
  result.push(ESCAPE, ESCAPE_UNDEFINED);
@@ -111,9 +111,13 @@ module.exports = {
111
111
  );
112
112
  };
113
113
  context.writeSeparate = (value, options) => {
114
- context.write(
115
- SerializerMiddleware.createLazy(value, fileMiddleware, options)
114
+ const lazy = SerializerMiddleware.createLazy(
115
+ value,
116
+ fileMiddleware,
117
+ options
116
118
  );
119
+ context.write(lazy);
120
+ return lazy;
117
121
  };
118
122
  }
119
123
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webpack",
3
- "version": "5.52.0",
3
+ "version": "5.52.1",
4
4
  "author": "Tobias Koppers @sokra",
5
5
  "description": "Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
6
6
  "license": "MIT",