webpack 5.110.2 → 5.110.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.
Files changed (42) hide show
  1. package/README.md +0 -2
  2. package/lib/ChunkGraph.js +20 -18
  3. package/lib/Compilation.js +1 -1
  4. package/lib/ConcatenationScope.js +25 -35
  5. package/lib/DotenvPlugin.js +41 -13
  6. package/lib/FlagDependencyUsagePlugin.js +8 -2
  7. package/lib/NormalModule.js +13 -20
  8. package/lib/RuntimePlugin.js +3 -0
  9. package/lib/RuntimeTemplate.js +14 -2
  10. package/lib/async-modules/AsyncModuleHelpers.js +10 -4
  11. package/lib/config/defaults.js +26 -16
  12. package/lib/config/normalization.js +18 -8
  13. package/lib/dependencies/CommonJsRequireDependency.js +18 -4
  14. package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +20 -7
  15. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +100 -19
  16. package/lib/dependencies/HarmonyImportDependency.js +94 -41
  17. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +12 -2
  18. package/lib/dependencies/HtmlEntryDependency.js +12 -2
  19. package/lib/dependencies/ImportContextDependency.js +43 -3
  20. package/lib/dependencies/ImportDependency.js +8 -29
  21. package/lib/dependencies/ImportParserPlugin.js +24 -14
  22. package/lib/dependencies/RequireHeaderDependency.js +20 -21
  23. package/lib/dependencies/importOptionsCheck.js +47 -0
  24. package/lib/errors/DotenvFileError.js +29 -0
  25. package/lib/errors/ImportedBindingAssignmentError.js +30 -0
  26. package/lib/html/HtmlModulesPlugin.js +29 -22
  27. package/lib/html/syntax.js +304 -143
  28. package/lib/javascript/JavascriptModulesPlugin.js +2 -0
  29. package/lib/optimize/ConcatenatedModule.js +38 -7
  30. package/lib/prefetch/ResourceHintPlugin.js +6 -1
  31. package/lib/runtime/AsyncModuleRuntimeModule.js +5 -1
  32. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +11 -1
  33. package/lib/schemes/HttpUriPlugin.js +22 -5
  34. package/lib/serialization/FileMiddleware.js +15 -2
  35. package/lib/util/ArrayQueue.js +3 -3
  36. package/lib/util/URLAbsoluteSpecifier.js +3 -1
  37. package/lib/util/conventions.js +5 -1
  38. package/lib/util/internalSerializables.js +2 -0
  39. package/package.json +1 -1
  40. package/schemas/WebpackOptions.check.js +1 -1
  41. package/schemas/WebpackOptions.json +9 -10
  42. package/types.d.ts +26 -17
@@ -1680,6 +1680,8 @@ class JavascriptModulesPlugin {
1680
1680
  continue;
1681
1681
  }
1682
1682
  }
1683
+ // An async entry is not awaited here: that needs top-level `await`,
1684
+ // gated on an option held back from the patch release (revert #21881).
1683
1685
  let i = jsEntries.length;
1684
1686
  for (const [entryModule, entrypoint] of jsEntries) {
1685
1687
  const chunks =
@@ -181,6 +181,7 @@ const findIdentifiers = (source) => {
181
181
  * @property {string=} comment
182
182
  * @property {ExportName} ids
183
183
  * @property {ExportName} exportName
184
+ * @property {boolean=} accessorCall the raw name is the wrapper accessor call itself, so it binds looser than the identifier it replaces
184
185
  */
185
186
 
186
187
  /**
@@ -494,11 +495,14 @@ const getFinalBinding = (
494
495
  /** @type {NonNullable<ConcatenatedModuleInfo["namespaceObjectName"]>} */
495
496
  (info.namespaceObjectName),
496
497
  ids: /** @type {ExportName} */ (usedName),
497
- exportName
498
+ exportName,
499
+ accessorCall: info.wrapped
498
500
  };
499
501
  }
500
502
 
501
- if (exportName.length === 0) {
503
+ if (moduleExportsAccess) {
504
+ // Skip ESM interop when require() targets a module outside the concatenation
505
+ } else if (exportName.length === 0) {
502
506
  switch (exportsType) {
503
507
  case "default-only":
504
508
  if (deferred) info.deferredNamespaceObjectUsed = true;
@@ -509,7 +513,8 @@ const getFinalBinding = (
509
513
  ? /** @type {string} */ (info.deferredNamespaceObjectName)
510
514
  : getInteropExpr(info, info.interopNamespaceObject2Name),
511
515
  ids: exportName,
512
- exportName
516
+ exportName,
517
+ accessorCall: !deferred && info.wrapped
513
518
  };
514
519
  case "default-with-named":
515
520
  if (deferred) info.deferredNamespaceObjectUsed = true;
@@ -520,7 +525,8 @@ const getFinalBinding = (
520
525
  ? /** @type {string} */ (info.deferredNamespaceObjectName)
521
526
  : getInteropExpr(info, info.interopNamespaceObjectName),
522
527
  ids: exportName,
523
- exportName
528
+ exportName,
529
+ accessorCall: !deferred && info.wrapped
524
530
  };
525
531
  case "namespace":
526
532
  case "dynamic":
@@ -611,7 +617,8 @@ const getFinalBinding = (
611
617
  info,
612
618
  rawName: getExternalModuleExpr(info),
613
619
  ids: exportName,
614
- exportName
620
+ exportName,
621
+ accessorCall: info.wrapped
615
622
  };
616
623
  }
617
624
  info.interopDefaultAccessUsed = true;
@@ -657,7 +664,8 @@ const getFinalBinding = (
657
664
  /** @type {NonNullable<ConcatenatedModuleInfo["namespaceObjectName"]>} */
658
665
  (info.namespaceObjectName),
659
666
  ids: exportName,
660
- exportName
667
+ exportName,
668
+ accessorCall: info.wrapped
661
669
  };
662
670
  case "external":
663
671
  if (deferred) {
@@ -673,7 +681,8 @@ const getFinalBinding = (
673
681
  info,
674
682
  rawName: getExternalModuleExpr(info),
675
683
  ids: exportName,
676
- exportName
684
+ exportName,
685
+ accessorCall: info.wrapped
677
686
  };
678
687
  }
679
688
  }
@@ -938,9 +947,13 @@ const getFinalName = (
938
947
  let reference;
939
948
  /** @type {boolean} */
940
949
  let isPropertyAccess;
950
+ // the raw name is the wrapper accessor call itself, so the reference binds
951
+ // looser than the identifier it stands in for
952
+ let accessorCall = false;
941
953
  if ("rawName" in binding) {
942
954
  reference = `${binding.rawName}${comment || ""}${propertyAccess(ids)}`;
943
955
  isPropertyAccess = ids.length > 0;
956
+ accessorCall = binding.accessorCall === true;
944
957
  } else {
945
958
  const { info, name: exportId } = binding;
946
959
  const name = info.internalNames.get(exportId);
@@ -970,6 +983,10 @@ const getFinalName = (
970
983
  } else if (binding.info.wrapped) {
971
984
  return asiSafe === false ? `;(${reference})` : `(${reference})`;
972
985
  }
986
+ } else if (accessorCall && !asCall) {
987
+ // without parentheses `new X()` would construct the accessor rather
988
+ // than what it returns
989
+ return asiSafe === false ? `;(${reference})` : `(${reference})`;
973
990
  }
974
991
 
975
992
  return reference;
@@ -1849,6 +1866,13 @@ class ConcatenatedModule extends Module {
1849
1866
  for (const reference of ConcatenationScope.findModuleReferences(
1850
1867
  /** @type {Source} */ (info.internalSource)
1851
1868
  )) {
1869
+ if (reference.leaked) {
1870
+ throw new Error(
1871
+ `Unsubstituted module reference "${reference.name}" in ${info.module.readableIdentifier(
1872
+ requestShortener
1873
+ )}`
1874
+ );
1875
+ }
1852
1876
  if (visitedReferences.has(reference.name)) continue;
1853
1877
  visitedReferences.add(reference.name);
1854
1878
  const match = ConcatenationScope.matchModuleReference(
@@ -1942,6 +1966,13 @@ class ConcatenatedModule extends Module {
1942
1966
  ignoredScopes
1943
1967
  );
1944
1968
  } else {
1969
+ if (ConcatenationScope.isLeakedModuleReference(name)) {
1970
+ throw new Error(
1971
+ `Unsubstituted module reference "${name}" in ${info.module.readableIdentifier(
1972
+ requestShortener
1973
+ )}`
1974
+ );
1975
+ }
1945
1976
  allUsedNames.add(name);
1946
1977
  freeNames.add(name);
1947
1978
  }
@@ -300,7 +300,12 @@ const collectEntrypointHints = (compilation, entryName, hints) => {
300
300
  const out = [];
301
301
  /** @type {Set<string>} */
302
302
  const seenKeys = new Set();
303
- const push = (/** @type {EntrypointHint} */ h) => {
303
+ /**
304
+ * Appends a hint, dropping one already emitted for the same rel + href.
305
+ * @param {EntrypointHint} h hint to append
306
+ * @returns {void}
307
+ */
308
+ const push = (h) => {
304
309
  const key = `${h.rel}\0${h.href}`;
305
310
  if (seenKeys.has(key)) return;
306
311
  seenKeys.add(key);
@@ -57,7 +57,11 @@ class AsyncModuleRuntimeModule extends HelperRuntimeModule {
57
57
  `${cst} hasUnresolvedAsyncSubgraph = asyncDeps.some((id) => {`,
58
58
  Template.indent([
59
59
  `${cst} cache = __webpack_module_cache__[id];`,
60
- "return !cache || cache[webpackDone] === false;"
60
+ "if (!cache) return true;",
61
+ // A cached entry no longer means finished, and a rejected
62
+ // one is done but its error must still reach the importer.
63
+ `${cst} deps = cache.exports;`,
64
+ "return deps[webpackDone] !== true || deps[webpackError] !== undefined;"
61
65
  ]),
62
66
  "});",
63
67
  "if (hasUnresolvedAsyncSubgraph) {",
@@ -290,7 +290,17 @@ class MakeOptimizedDeferredNamespaceObjectRuntimeModule extends HelperRuntimeMod
290
290
  ]),
291
291
  "};",
292
292
  hasAsync
293
- ? `if(isAsync) obj[${RuntimeGlobals.deferredModuleAsyncTransitiveDependenciesSymbol}] = asyncDeps;`
293
+ ? // `GatherAsynchronousTransitiveDependencies` skips a module that is
294
+ // already evaluating, and evaluates the rest right here.
295
+ `if(isAsync) obj[${RuntimeGlobals.deferredModuleAsyncTransitiveDependenciesSymbol}] = asyncDeps.filter(${runtimeTemplate.basicFunction(
296
+ "id",
297
+ [
298
+ `${cst} dep = __webpack_module_cache__[id];`,
299
+ "if (dep && (dep.evaluating || dep.evaluatingAsync)) return false;",
300
+ "r(id);",
301
+ "return true;"
302
+ ]
303
+ )});`
294
304
  : "",
295
305
  "return obj;"
296
306
  ]),
@@ -149,7 +149,8 @@ const verifyIntegrity = (content, integrity) => {
149
149
  };
150
150
 
151
151
  /**
152
- * Parses key value pairs.
152
+ * Parses key value pairs. Keys are lower-cased because HTTP directive names are
153
+ * case-insensitive; values are kept verbatim (they may be quoted field lists).
153
154
  * @param {string} str input
154
155
  * @returns {Record<string, string>} parsed
155
156
  */
@@ -159,11 +160,11 @@ const parseKeyValuePairs = (str) => {
159
160
  for (const item of str.split(",")) {
160
161
  const i = item.indexOf("=");
161
162
  if (i >= 0) {
162
- const key = item.slice(0, i).trim();
163
+ const key = item.slice(0, i).trim().toLowerCase();
163
164
  const value = item.slice(i + 1).trim();
164
165
  result[key] = value;
165
166
  } else {
166
- const key = item.trim();
167
+ const key = item.trim().toLowerCase();
167
168
  if (!key) continue;
168
169
  result[key] = key;
169
170
  }
@@ -186,7 +187,9 @@ const parseCacheControl = (cacheControl, requestTime) => {
186
187
  let validUntil = 0;
187
188
  if (cacheControl) {
188
189
  const parsed = parseKeyValuePairs(cacheControl);
189
- if (parsed["no-cache"]) storeCache = storeLock = false;
190
+ if (parsed["no-cache"] || parsed["no-store"]) {
191
+ storeCache = storeLock = false;
192
+ }
190
193
  if (parsed["max-age"] && !Number.isNaN(Number(parsed["max-age"]))) {
191
194
  validUntil = requestTime + Number(parsed["max-age"]) * 1000;
192
195
  }
@@ -984,7 +987,11 @@ class HttpUriPlugin {
984
987
  /** @type {Buffer[]} */
985
988
  const bufferArr = [];
986
989
 
987
- const contentEncoding = res.headers["content-encoding"];
990
+ // content codings are case-insensitive tokens
991
+ const contentEncodingHeader = res.headers["content-encoding"];
992
+ const contentEncoding =
993
+ contentEncodingHeader &&
994
+ contentEncodingHeader.trim().toLowerCase();
988
995
  /** @type {Readable} */
989
996
  let stream = res;
990
997
  if (contentEncoding === "gzip") {
@@ -994,6 +1001,16 @@ class HttpUriPlugin {
994
1001
  } else if (contentEncoding === "deflate") {
995
1002
  stream = stream.pipe(createInflate());
996
1003
  }
1004
+ if (stream !== res) {
1005
+ // a decompressor error never reaches the request's handler
1006
+ stream.once("error", (err) => {
1007
+ logger.log(
1008
+ `GET ${url} [${res.statusCode}] (invalid encoding)`
1009
+ );
1010
+ err.message += `\nwhile decompressing ${url}`;
1011
+ callback(err);
1012
+ });
1013
+ }
997
1014
 
998
1015
  stream.on(
999
1016
  "data",
@@ -549,9 +549,13 @@ class FileMiddleware extends SerializerMiddleware {
549
549
  });
550
550
  }
551
551
  if (compression) {
552
- pipeline(compression, stream, reject);
552
+ // resolve on the pipeline, not on the transform's "finish":
553
+ // the latter fires before the destination has flushed
554
+ pipeline(compression, stream, (err) => {
555
+ if (err) return reject(err);
556
+ resolve();
557
+ });
553
558
  stream = compression;
554
- stream.on("finish", () => resolve());
555
559
  } else {
556
560
  stream.on("error", (err) => reject(err));
557
561
  stream.on("finish", () => resolve());
@@ -793,6 +797,15 @@ class FileMiddleware extends SerializerMiddleware {
793
797
  });
794
798
  return;
795
799
  }
800
+ // a file truncated after `stat` reads 0 bytes forever
801
+ if (bytesRead === 0 && remaining > 0) {
802
+ this.fs.close(fd, (err) => {
803
+ reject(
804
+ err || new Error(`Unexpected end of file ${file}`)
805
+ );
806
+ });
807
+ return;
808
+ }
796
809
  /** @type {number} */
797
810
  (currentBufferUsed) += bytesRead;
798
811
  remaining -= bytesRead;
@@ -90,11 +90,11 @@ class ArrayQueue {
90
90
  [Symbol.iterator]() {
91
91
  return {
92
92
  next: () => {
93
- const item = this.dequeue();
94
- if (item) {
93
+ // length, not truthiness: a queued `0`/`false`/`undefined` is a value
94
+ if (this.length > 0) {
95
95
  return {
96
96
  done: false,
97
- value: item
97
+ value: /** @type {T} */ (this.dequeue())
98
98
  };
99
99
  }
100
100
  return {
@@ -17,6 +17,7 @@ const _0CharCode = "0".charCodeAt(0);
17
17
  const _9CharCode = "9".charCodeAt(0);
18
18
  const plusCharCode = "+".charCodeAt(0);
19
19
  const hyphenCharCode = "-".charCodeAt(0);
20
+ const dotCharCode = ".".charCodeAt(0);
20
21
  const colonCharCode = ":".charCodeAt(0);
21
22
  const hashCharCode = "#".charCodeAt(0);
22
23
  const queryCharCode = "?".charCodeAt(0);
@@ -46,7 +47,8 @@ function getScheme(specifier) {
46
47
  (ch >= aUpperCaseCharCode && ch <= zUpperCaseCharCode) ||
47
48
  (ch >= _0CharCode && ch <= _9CharCode) ||
48
49
  ch === plusCharCode ||
49
- ch === hyphenCharCode
50
+ ch === hyphenCharCode ||
51
+ ch === dotCharCode
50
52
  ) {
51
53
  if (++i === specifier.length) return;
52
54
  ch = specifier.charCodeAt(i);
@@ -115,7 +115,11 @@ module.exports.cssExportConvention = (input, convention) => {
115
115
  const set = new Set();
116
116
  if (typeof convention === "function") {
117
117
  const result = convention(input);
118
- const validate = (/** @type {string} */ name) => {
118
+ /**
119
+ * @param {string} name name returned by the convention function
120
+ * @returns {void}
121
+ */
122
+ const validate = (name) => {
119
123
  if (typeof name !== "string" || name.length === 0) {
120
124
  throw new Error(
121
125
  `exportsConvention function must return a non-empty string or an array of non-empty strings, got ${safeStringify(result)}`
@@ -211,6 +211,8 @@ module.exports = {
211
211
  "errors/EnvironmentNotSupportAsyncWarning": () =>
212
212
  require("../errors/EnvironmentNotSupportAsyncWarning"),
213
213
  "errors/HookWebpackError": () => require("../errors/HookWebpackError"),
214
+ "errors/ImportedBindingAssignmentError": () =>
215
+ require("../errors/ImportedBindingAssignmentError"),
214
216
  "errors/InvalidDependenciesModuleWarning": () =>
215
217
  require("../errors/InvalidDependenciesModuleWarning"),
216
218
  "errors/JSONParseError": () => require("../errors/JSONParseError"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webpack",
3
- "version": "5.110.2",
3
+ "version": "5.110.3",
4
4
  "description": "Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
5
5
  "homepage": "https://github.com/webpack/webpack",
6
6
  "bugs": "https://github.com/webpack/webpack/issues",