webpack 5.110.0 → 5.110.2

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 (52) hide show
  1. package/README.md +10 -17
  2. package/lib/ExportsInfo.js +10 -0
  3. package/lib/FileSystemInfo.js +17 -2
  4. package/lib/Generator.js +17 -0
  5. package/lib/NormalModule.js +3 -3
  6. package/lib/RuntimeTemplate.js +423 -430
  7. package/lib/asset/AssetBytesGenerator.js +1 -3
  8. package/lib/asset/AssetGenerator.js +1 -3
  9. package/lib/asset/AssetSourceGenerator.js +1 -3
  10. package/lib/config/defaults.js +6 -0
  11. package/lib/css/CssGenerator.js +1 -3
  12. package/lib/css/CssLoadingRuntimeModule.js +32 -13
  13. package/lib/css/CssModulesPlugin.js +9 -17
  14. package/lib/css/data.js +13 -3
  15. package/lib/css/syntax.js +78 -10
  16. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +10 -4
  17. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +2 -0
  18. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +48 -3
  19. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +83 -14
  20. package/lib/dependencies/HarmonyImportSideEffectDependency.js +114 -0
  21. package/lib/dependencies/WorkerAndWorkletPlugin.js +1 -0
  22. package/lib/dependencies/WorkerDependency.js +6 -12
  23. package/lib/dependencies/WorkletDependency.js +7 -11
  24. package/lib/esm/ModuleChunkLoadingPlugin.js +6 -9
  25. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +7 -1
  26. package/lib/html/HtmlGenerator.js +1 -1
  27. package/lib/html/HtmlModulesPlugin.js +55 -16
  28. package/lib/html/syntax.js +113 -26
  29. package/lib/javascript/JavascriptGenerator.js +1 -1
  30. package/lib/javascript/JavascriptModulesPlugin.js +3 -10
  31. package/lib/json/JsonGenerator.js +1 -1
  32. package/lib/loaders/LoaderRunner.js +33 -5
  33. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +8 -15
  34. package/lib/optimize/ConcatenatedModule.js +8 -0
  35. package/lib/optimize/ConstExportsPlugin.js +5 -0
  36. package/lib/optimize/InlineExports.js +121 -0
  37. package/lib/optimize/RealContentHashPlugin.js +111 -35
  38. package/lib/prefetch/ResourceHintPlugin.js +6 -12
  39. package/lib/serialization/ObjectMiddleware.js +128 -108
  40. package/lib/typescript/TypeScriptPlugin.js +8 -10
  41. package/lib/util/SourceProcessor.js +24 -8
  42. package/lib/util/createMappings.js +25 -3
  43. package/lib/util/removeBOM.js +82 -1
  44. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +5 -3
  45. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +5 -3
  46. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +3 -1
  47. package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +7 -12
  48. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +3 -1
  49. package/lib/web/FetchCompileAsyncWasmPlugin.js +10 -6
  50. package/lib/web/FetchCompileWasmPlugin.js +4 -2
  51. package/package.json +1 -1
  52. package/types.d.ts +77 -10
@@ -114,9 +114,7 @@ class AssetBytesGenerator extends Generator {
114
114
  generateError(error, module, generateContext) {
115
115
  switch (generateContext.type) {
116
116
  case JAVASCRIPT_TYPE: {
117
- return new RawSource(
118
- `throw new Error(${JSON.stringify(error.message)});`
119
- );
117
+ return new RawSource(Generator.throwBuildErrorCode(error));
120
118
  }
121
119
  default:
122
120
  return null;
@@ -777,9 +777,7 @@ class AssetGenerator extends Generator {
777
777
  return new RawSource(error.message);
778
778
  }
779
779
  case JAVASCRIPT_TYPE: {
780
- return new RawSource(
781
- `throw new Error(${JSON.stringify(error.message)});`
782
- );
780
+ return new RawSource(Generator.throwBuildErrorCode(error));
783
781
  }
784
782
  default:
785
783
  return null;
@@ -158,9 +158,7 @@ class AssetSourceGenerator extends Generator {
158
158
  generateError(error, module, generateContext) {
159
159
  switch (generateContext.type) {
160
160
  case JAVASCRIPT_TYPE: {
161
- return new RawSource(
162
- `throw new Error(${JSON.stringify(error.message)});`
163
- );
161
+ return new RawSource(Generator.throwBuildErrorCode(error));
164
162
  }
165
163
  default:
166
164
  return null;
@@ -2464,6 +2464,12 @@ const applyOptimizationDefaults = (
2464
2464
  D(optimization, "portableRecords", records);
2465
2465
  D(optimization, "realContentHash", production);
2466
2466
  F(optimization, "minimize", () => (production ? {} : false));
2467
+ // A plugin can assign the `true` shorthand in `apply()`, which runs after
2468
+ // `getNormalizedOptimizationMinimize` and so never gets normalized. The
2469
+ // normalized type does not allow it, hence the cast.
2470
+ if (/** @type {unknown} */ (optimization.minimize) === true) {
2471
+ optimization.minimize = {};
2472
+ }
2467
2473
  const { minimize } = optimization;
2468
2474
  if (minimize) {
2469
2475
  // Canonicalize the object form: the JS minimizer's defaults become
@@ -617,9 +617,7 @@ class CssGenerator extends Generator {
617
617
  generateError(error, module, generateContext) {
618
618
  switch (generateContext.type) {
619
619
  case JAVASCRIPT_TYPE: {
620
- return new RawSource(
621
- `throw new Error(${JSON.stringify(error.message)});`
622
- );
620
+ return new RawSource(Generator.throwBuildErrorCode(error));
623
621
  }
624
622
  case CSS_TYPE: {
625
623
  return new RawSource(`/**\n ${error.message} \n**/`);
@@ -76,10 +76,26 @@ class CssLoadingRuntimeModule extends RuntimeModule {
76
76
  } = compilation;
77
77
  const dedupePrefetch = Boolean(resourceHints && resourceHints.dedupe);
78
78
  const fn = RuntimeGlobals.ensureChunkHandlers;
79
+ /** @type {Set<ChunkId>} */
80
+ const initialChunkIds = new Set();
81
+ for (const c of chunk.getAllInitialChunks()) {
82
+ if (chunkHasCss(c, chunkGraph)) {
83
+ initialChunkIds.add(/** @type {ChunkId} */ (c.id));
84
+ }
85
+ }
79
86
  // The predicate the stylesheet is emitted from: an `@import` external gives a
80
87
  // chunk a css asset without a `CSS_TYPE` module, and it still has to load.
81
88
  const conditionMap = chunkGraph.getChunkConditionMap(chunk, chunkHasCss);
82
- const hasCssMatcher = compileBooleanMatcher(conditionMap);
89
+ // An initial chunk is installed before the handler can run, so it never
90
+ // reaches the loading path — with no other one there is nothing to load.
91
+ const loadableConditionMap = { ...conditionMap };
92
+ for (const id of initialChunkIds) {
93
+ loadableConditionMap[id] = false;
94
+ }
95
+ const hasCssMatcher =
96
+ compileBooleanMatcher(loadableConditionMap) === false
97
+ ? false
98
+ : compileBooleanMatcher(conditionMap);
83
99
 
84
100
  const withLoading =
85
101
  _runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers) &&
@@ -88,13 +104,6 @@ class CssLoadingRuntimeModule extends RuntimeModule {
88
104
  const withHmr = _runtimeRequirements.has(
89
105
  RuntimeGlobals.hmrDownloadUpdateHandlers
90
106
  );
91
- /** @type {Set<ChunkId>} */
92
- const initialChunkIds = new Set();
93
- for (const c of chunk.getAllInitialChunks()) {
94
- if (chunkHasCss(c, chunkGraph)) {
95
- initialChunkIds.add(/** @type {ChunkId} */ (c.id));
96
- }
97
- }
98
107
 
99
108
  if (!withLoading && !withHmr) {
100
109
  return null;
@@ -176,22 +185,32 @@ class CssLoadingRuntimeModule extends RuntimeModule {
176
185
  ",\n"
177
186
  )
178
187
  )}\n}`;
188
+ /**
189
+ * @param {string} id expression naming the chunk whose stylesheet is wanted
190
+ * @returns {string} expression building its url at runtime
191
+ */
192
+ const runtimeCssUrl = (id) =>
193
+ `${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkCssFilename}(${id})`;
179
194
  // The url is read through a thunk so a runtime carrying many stylesheets builds
180
195
  // only the one it loads.
181
196
  /**
182
197
  * @param {string} id expression naming the chunk whose stylesheet is wanted
183
198
  * @returns {string} expression evaluating to its url
184
199
  */
185
- const cssUrl = (id) =>
186
- cssUrls === undefined || cssUrls === null
187
- ? `${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkCssFilename}(${id})`
188
- : `cssUrls[${id}]()`;
200
+ const cssUrl = (id) => {
201
+ if (!cssUrls) return runtimeCssUrl(id);
202
+ // An id the incomplete map lacks still resolves through the runtime lookup,
203
+ // which the plugin kept required for exactly this case.
204
+ return cssUrls.complete
205
+ ? `cssUrls[${id}]()`
206
+ : `(cssUrls[${id}] ? cssUrls[${id}]() : ${runtimeCssUrl(id)})`;
207
+ };
189
208
  return Template.asString([
190
209
  ...(cssUrls
191
210
  ? [
192
211
  `${cst} cssUrls = {\n${Template.indent(
193
212
  Array.from(
194
- cssUrls,
213
+ cssUrls.urls,
195
214
  ([id, url]) =>
196
215
  `${JSON.stringify(String(id))}: ${runtimeTemplate.returningFunction(url)}`
197
216
  ).join(",\n")
@@ -43,7 +43,7 @@ const {
43
43
  PUBLIC_PATH_AUTO,
44
44
  walkFullHashPlaceholders
45
45
  } = require("../util/publicPathPlaceholder");
46
- const removeBOM = require("../util/removeBOM");
46
+ const { removeBOMFromResult } = require("../util/removeBOM");
47
47
  const CssModule = require("./CssModule");
48
48
 
49
49
  /** @import { Source } from "webpack-sources" */
@@ -516,15 +516,8 @@ class CssModulesPlugin {
516
516
 
517
517
  NormalModule.getCompilationHooks(compilation).processResult.tap(
518
518
  PLUGIN_NAME,
519
- (result, module) => {
520
- if (module.type === type) {
521
- const [source, ...rest] = result;
522
-
523
- return [removeBOM(source), ...rest];
524
- }
525
-
526
- return result;
527
- }
519
+ (result, module) =>
520
+ module.type === type ? removeBOMFromResult(result) : result
528
521
  );
529
522
  }
530
523
 
@@ -779,13 +772,12 @@ class CssModulesPlugin {
779
772
  // A baked url carries where the stylesheet is, so neither the public
780
773
  // path nor the name lookup is read for it. Asked exactly as the
781
774
  // loading runtime module asks, so the two always agree.
782
- if (
783
- compilation.runtimeTemplate.analyzableCssChunkUrls(
784
- chunk,
785
- chunkGraph,
786
- set
787
- ) === null
788
- ) {
775
+ const baked = compilation.runtimeTemplate.analyzableCssChunkUrls(
776
+ chunk,
777
+ chunkGraph,
778
+ set
779
+ );
780
+ if (baked === null || !baked.complete) {
789
781
  set.add(RuntimeGlobals.publicPath);
790
782
  set.add(RuntimeGlobals.getChunkCssFilename);
791
783
  }
package/lib/css/data.js CHANGED
@@ -517,7 +517,7 @@ const UNSHARED_LONGHAND_KEYWORDS = new Map([
517
517
  // appearing once, in grammar order. A merge emits every value, so the only
518
518
  // question is whether each parses back into the longhand it was authored on.
519
519
  // prettier-ignore
520
- const FAMILY_LONGHANDS = new Map([["border-bottom", ["border-bottom-width","border-bottom-style","border-bottom-color"]], ["border-left", ["border-left-width","border-left-style","border-left-color"]], ["border-right", ["border-right-width","border-right-style","border-right-color"]], ["border-top", ["border-top-width","border-top-style","border-top-color"]], ["column-rule", ["column-rule-width","column-rule-style","column-rule-color"]], ["flex-flow", ["flex-direction","flex-wrap"]], ["list-style", ["list-style-type","list-style-position","list-style-image"]], ["outline", ["outline-width","outline-style","outline-color"]], ["text-decoration", ["text-decoration-line","text-decoration-style","text-decoration-color","text-decoration-thickness"]], ["text-emphasis", ["text-emphasis-style","text-emphasis-color"]], ["text-wrap", ["text-wrap-mode","text-wrap-style"]]]);
520
+ const FAMILY_LONGHANDS = new Map([["border-block-end", ["border-block-end-width","border-block-end-style","border-block-end-color"]], ["border-block-start", ["border-block-start-width","border-block-start-style","border-block-start-color"]], ["border-bottom", ["border-bottom-width","border-bottom-style","border-bottom-color"]], ["border-inline-end", ["border-inline-end-width","border-inline-end-style","border-inline-end-color"]], ["border-inline-start", ["border-inline-start-width","border-inline-start-style","border-inline-start-color"]], ["border-left", ["border-left-width","border-left-style","border-left-color"]], ["border-right", ["border-right-width","border-right-style","border-right-color"]], ["border-top", ["border-top-width","border-top-style","border-top-color"]], ["column-rule", ["column-rule-width","column-rule-style","column-rule-color"]], ["flex-flow", ["flex-direction","flex-wrap"]], ["list-style", ["list-style-type","list-style-position","list-style-image"]], ["outline", ["outline-width","outline-style","outline-color"]], ["text-decoration", ["text-decoration-line","text-decoration-style","text-decoration-color","text-decoration-thickness"]], ["text-emphasis", ["text-emphasis-style","text-emphasis-color"]], ["text-wrap", ["text-wrap-mode","text-wrap-style"]]]);
521
521
 
522
522
  // The properties whose comma-separated items take a `<custom-ident>`, where a
523
523
  // vendor spelling is a name the engine parses rather than one it may drop — so a
@@ -537,6 +537,12 @@ const CUSTOM_IDENT_LIST_PROPERTIES = new Set([
537
537
  "will-change"
538
538
  ]);
539
539
 
540
+ // The shorthands whose grammar juxtaposes its longhands in a fixed order, so a
541
+ // merge writes every value by position rather than reading which slot takes it.
542
+ const ORDERED_LONGHANDS = new Map([
543
+ ["flex", ["flex-grow", "flex-shrink", "flex-basis"]]
544
+ ]);
545
+
540
546
  const SLASH_LONGHANDS = new Map([
541
547
  [
542
548
  "grid-area",
@@ -597,7 +603,10 @@ const MERGE_LONGHANDS = new Set([
597
603
  "corner-start-start-shape",
598
604
  "corner-top-left-shape",
599
605
  "corner-top-right-shape",
606
+ "flex-basis",
600
607
  "flex-direction",
608
+ "flex-grow",
609
+ "flex-shrink",
601
610
  "flex-wrap",
602
611
  "grid-column-end",
603
612
  "grid-column-start",
@@ -682,10 +691,10 @@ const OMITTABLE_INITIAL_KEYWORDS = new Map([["grid-auto-flow", ["row", ["column"
682
691
  // makes the merge ambiguous, and `FAMILY_SLOT_CLASSES` names a type the printer
683
692
  // cannot classify as readily as one it can, so an unknown one declines.
684
693
  // prettier-ignore
685
- const FAMILY_SLOT_KEYWORDS = new Map([["border-bottom-width", ["medium","thick","thin"]], ["border-bottom-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-bottom-color", []], ["border-left-width", ["medium","thick","thin"]], ["border-left-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-left-color", []], ["border-right-width", ["medium","thick","thin"]], ["border-right-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-right-color", []], ["border-top-width", ["medium","thick","thin"]], ["border-top-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-top-color", []], ["column-rule-width", ["medium","thick","thin"]], ["column-rule-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["column-rule-color", []], ["flex-direction", ["column","column-reverse","row","row-reverse"]], ["flex-wrap", ["nowrap","wrap","wrap-reverse"]], ["list-style-type", ["none"]], ["list-style-position", ["inside","outside"]], ["list-style-image", ["none"]], ["outline-width", ["medium","thick","thin"]], ["outline-style", ["auto","dashed","dotted","double","groove","inset","none","outset","ridge","solid"]], ["outline-color", ["auto"]], ["text-decoration-line", ["blink","grammar-error","line-through","none","overline","spelling-error","underline"]], ["text-decoration-style", ["dashed","dotted","double","solid","wavy"]], ["text-decoration-color", []], ["text-decoration-thickness", ["auto","from-font"]], ["text-emphasis-style", ["circle","dot","double-circle","filled","none","open","sesame","triangle"]], ["text-emphasis-color", []], ["text-wrap-mode", ["nowrap","wrap"]], ["text-wrap-style", ["auto","balance","pretty","stable"]]]);
694
+ const FAMILY_SLOT_KEYWORDS = new Map([["border-block-end-width", ["medium","thick","thin"]], ["border-block-end-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-block-end-color", []], ["border-block-start-width", ["medium","thick","thin"]], ["border-block-start-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-block-start-color", []], ["border-bottom-width", ["medium","thick","thin"]], ["border-bottom-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-bottom-color", []], ["border-inline-end-width", ["medium","thick","thin"]], ["border-inline-end-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-inline-end-color", []], ["border-inline-start-width", ["medium","thick","thin"]], ["border-inline-start-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-inline-start-color", []], ["border-left-width", ["medium","thick","thin"]], ["border-left-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-left-color", []], ["border-right-width", ["medium","thick","thin"]], ["border-right-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-right-color", []], ["border-top-width", ["medium","thick","thin"]], ["border-top-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-top-color", []], ["column-rule-width", ["medium","thick","thin"]], ["column-rule-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["column-rule-color", []], ["flex-direction", ["column","column-reverse","row","row-reverse"]], ["flex-wrap", ["nowrap","wrap","wrap-reverse"]], ["list-style-type", ["none"]], ["list-style-position", ["inside","outside"]], ["list-style-image", ["none"]], ["outline-width", ["medium","thick","thin"]], ["outline-style", ["auto","dashed","dotted","double","groove","inset","none","outset","ridge","solid"]], ["outline-color", ["auto"]], ["text-decoration-line", ["blink","grammar-error","line-through","none","overline","spelling-error","underline"]], ["text-decoration-style", ["dashed","dotted","double","solid","wavy"]], ["text-decoration-color", []], ["text-decoration-thickness", ["auto","from-font"]], ["text-emphasis-style", ["circle","dot","double-circle","filled","none","open","sesame","triangle"]], ["text-emphasis-color", []], ["text-wrap-mode", ["nowrap","wrap"]], ["text-wrap-style", ["auto","balance","pretty","stable"]]]);
686
695
 
687
696
  // prettier-ignore
688
- const FAMILY_SLOT_CLASSES = new Map([["border-bottom-width", ["length"]], ["border-bottom-style", []], ["border-bottom-color", ["color"]], ["border-left-width", ["length"]], ["border-left-style", []], ["border-left-color", ["color"]], ["border-right-width", ["length"]], ["border-right-style", []], ["border-right-color", ["color"]], ["border-top-width", ["length"]], ["border-top-style", []], ["border-top-color", ["color"]], ["column-rule-width", ["length"]], ["column-rule-style", []], ["column-rule-color", ["color"]], ["flex-direction", []], ["flex-wrap", []], ["list-style-type", ["custom-ident","string"]], ["list-style-position", []], ["list-style-image", ["image"]], ["outline-width", ["length"]], ["outline-style", []], ["outline-color", ["color"]], ["text-decoration-line", []], ["text-decoration-style", []], ["text-decoration-color", ["color"]], ["text-decoration-thickness", ["length","percentage"]], ["text-emphasis-style", ["string"]], ["text-emphasis-color", ["color"]], ["text-wrap-mode", []], ["text-wrap-style", []]]);
697
+ const FAMILY_SLOT_CLASSES = new Map([["border-block-end-width", ["length"]], ["border-block-end-style", []], ["border-block-end-color", ["color"]], ["border-block-start-width", ["length"]], ["border-block-start-style", []], ["border-block-start-color", ["color"]], ["border-bottom-width", ["length"]], ["border-bottom-style", []], ["border-bottom-color", ["color"]], ["border-inline-end-width", ["length"]], ["border-inline-end-style", []], ["border-inline-end-color", ["color"]], ["border-inline-start-width", ["length"]], ["border-inline-start-style", []], ["border-inline-start-color", ["color"]], ["border-left-width", ["length"]], ["border-left-style", []], ["border-left-color", ["color"]], ["border-right-width", ["length"]], ["border-right-style", []], ["border-right-color", ["color"]], ["border-top-width", ["length"]], ["border-top-style", []], ["border-top-color", ["color"]], ["column-rule-width", ["length"]], ["column-rule-style", []], ["column-rule-color", ["color"]], ["flex-direction", []], ["flex-wrap", []], ["list-style-type", ["custom-ident","string"]], ["list-style-position", []], ["list-style-image", ["image"]], ["outline-width", ["length"]], ["outline-style", []], ["outline-color", ["color"]], ["text-decoration-line", []], ["text-decoration-style", []], ["text-decoration-color", ["color"]], ["text-decoration-thickness", ["length","percentage"]], ["text-emphasis-style", ["string"]], ["text-emphasis-color", ["color"]], ["text-wrap-mode", []], ["text-wrap-style", []]]);
689
698
 
690
699
  // The identifiers that are a `<color>` on their own — named, system and the two
691
700
  // context-dependent ones. Read off the `<color>` grammar outside any function,
@@ -5282,6 +5291,7 @@ module.exports.NTH_NAMED_EQUIVALENTS = NTH_NAMED_EQUIVALENTS;
5282
5291
  module.exports.NTH_PSEUDO_FUNCTIONS = NTH_PSEUDO_FUNCTIONS;
5283
5292
  module.exports.OMITTABLE_INITIAL_KEYWORDS = OMITTABLE_INITIAL_KEYWORDS;
5284
5293
  module.exports.ONE_VALUE_PAIR_SHORTHANDS = ONE_VALUE_PAIR_SHORTHANDS;
5294
+ module.exports.ORDERED_LONGHANDS = ORDERED_LONGHANDS;
5285
5295
  module.exports.PAIR_LONGHANDS = PAIR_LONGHANDS;
5286
5296
  module.exports.PLACE_SHORTHANDS = PLACE_SHORTHANDS;
5287
5297
  module.exports.POSITION_PROPERTIES = POSITION_PROPERTIES;
package/lib/css/syntax.js CHANGED
@@ -88,6 +88,7 @@ const {
88
88
  NTH_PSEUDO_FUNCTIONS,
89
89
  OMITTABLE_INITIAL_KEYWORDS,
90
90
  ONE_VALUE_PAIR_SHORTHANDS,
91
+ ORDERED_LONGHANDS,
91
92
  PAIR_LONGHANDS,
92
93
  PLACE_SHORTHANDS,
93
94
  POSITION_PROPERTIES,
@@ -5268,8 +5269,13 @@ const _emitTopLevel = (writer, node, offset, line, column, text, own) => {
5268
5269
  // Folding two named layer blocks into one, and taking back a rule an
5269
5270
  // identical later one makes dead, each answer to their own option.
5270
5271
  const minify = printing && _transforms.removeDeadRules;
5272
+ // The node type first: only an at-rule can be a named layer block, and
5273
+ // reading the text asks the rope this node printed to flatten — a copy of
5274
+ // the whole rule, for every rule.
5271
5275
  const opener =
5272
- printing && _transforms.mergeRules ? _namedLayerOpener(text) : null;
5276
+ printing && _transforms.mergeRules && _types[_nodeIndex(node)] === T_AT_RULE
5277
+ ? _namedLayerOpener(text)
5278
+ : null;
5273
5279
  // Nothing folds back over a kept comment — it was written above what follows
5274
5280
  // it — nor over a sibling naming a layer any other way, since it writes into
5275
5281
  // one of these and the order within a layer is the cascade's.
@@ -9582,15 +9588,31 @@ const _BARE_NUMBER_RE = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
9582
9588
  * @param {PrintContext} writer the print context (children's printed text)
9583
9589
  * @returns {string[] | null} the fragments to join, or `null` to keep the value as it is
9584
9590
  */
9585
- const _collapseFlexShorthand = (path, node, writer) => {
9586
- const components = _valueComponents(path, node, writer);
9591
+ const _collapseFlexShorthand = (path, node, writer) =>
9592
+ _shortestFlexValue(_valueComponents(path, node, writer));
9593
+
9594
+ /**
9595
+ * The shortest spelling of a three-factor `flex` value, or `null` when it is
9596
+ * already the shortest. Shared with the merge, which arrives at the same three
9597
+ * factors from the longhands rather than from an authored shorthand.
9598
+ * @param {string[]} components the value's components, in grammar order
9599
+ * @returns {string[] | null} the fragments to join, or `null` to keep them as they are
9600
+ */
9601
+ const _shortestFlexValue = (components) => {
9587
9602
  if (components.length !== 3) return null;
9588
9603
  const keyword = FLEX_KEYWORDS.get(components.join(" ").toLowerCase());
9589
9604
  if (keyword !== undefined) return [keyword];
9605
+ // CSS Flexbox 1 §7.1.1 reads an omitted basis as `0%`, so one spelt that way
9606
+ // says nothing — and an omitted shrink as `1`, so that says nothing either.
9607
+ if (components[2] === "0%") {
9608
+ return components[1] === "1"
9609
+ ? [components[0]]
9610
+ : [components[0], components[1]];
9611
+ }
9590
9612
  // `<'flex-shrink'>` follows the grow factor and defaults to 1, so a `1` there
9591
9613
  // says nothing — but only over a basis that cannot be read as a factor
9592
- // itself: CSS Flexbox 1 §7.1.1 reads a unitless zero not preceded by two
9593
- // factors as a factor, so `1 1 0` is not `1 0`.
9614
+ // itself: §7.1.1 reads a unitless zero not preceded by two factors as a
9615
+ // factor, so `1 1 0` is not `1 0`.
9594
9616
  return components[1] === "1" && !_BARE_NUMBER_RE.test(components[2])
9595
9617
  ? [components[0], components[2]]
9596
9618
  : null;
@@ -10655,13 +10677,32 @@ const _mergeBoxLonghands = (
10655
10677
  // A bare number is no length, so one written beside a length is a value the
10656
10678
  // property never read — the engine dropped that declaration and kept the
10657
10679
  // others. Merging them writes it into a shorthand the engine drops whole,
10658
- // which loses the slots that were fine.
10659
- if (_mixesBareNumberWithLength(values)) continue;
10680
+ // which loses the slots that were fine. Not asked of an ordered grammar,
10681
+ // whose slots take different types by position (`flex:1 1 0px`).
10682
+ if (mode !== MERGE_ORDERED && _mixesBareNumberWithLength(values)) continue;
10660
10683
  /** @type {string | null} */
10661
10684
  let value;
10662
10685
  if (mode === MERGE_FAMILY) {
10663
10686
  value = _familyValue(longhands, values);
10664
10687
  if (value === null) continue;
10688
+ } else if (mode === MERGE_ORDERED) {
10689
+ // The same two refusals every other mode makes: a `var()` may expand
10690
+ // across a slot boundary, and a CSS-wide keyword beside another value is
10691
+ // a shorthand the engine drops whole.
10692
+ let refused = false;
10693
+ for (const slot of values) {
10694
+ if (
10695
+ _hasSubstitution(slot) ||
10696
+ CSS_WIDE_KEYWORDS.has(toLowerCaseIfNeeded(slot))
10697
+ ) {
10698
+ refused = true;
10699
+ break;
10700
+ }
10701
+ }
10702
+ if (refused) continue;
10703
+ // Written by position, then shortened the way an authored one would be.
10704
+ const shortest = _shortestFlexValue(values);
10705
+ value = (shortest === null ? values : shortest).join(" ");
10665
10706
  } else if (mode === MERGE_SLASH) {
10666
10707
  // The same two refusals a box makes: a `var()` may expand across the `/`
10667
10708
  // into another slot, and a CSS-wide keyword beside another value is a
@@ -10728,12 +10769,14 @@ const _mergeBoxLonghands = (
10728
10769
  const MERGE_BOX = 0;
10729
10770
  const MERGE_FAMILY = 1;
10730
10771
  const MERGE_SLASH = 2;
10772
+ const MERGE_ORDERED = 3;
10731
10773
 
10732
10774
  /** @type {[Map<string, string[]>, number][]} */
10733
10775
  const MERGE_TABLES = [
10734
10776
  [BOX_LONGHANDS, MERGE_BOX],
10735
10777
  [PAIR_LONGHANDS, MERGE_BOX],
10736
10778
  [FAMILY_LONGHANDS, MERGE_FAMILY],
10779
+ [ORDERED_LONGHANDS, MERGE_ORDERED],
10737
10780
  [SLASH_LONGHANDS, MERGE_SLASH]
10738
10781
  ];
10739
10782
 
@@ -11243,6 +11286,21 @@ const _opensNestedLayer = (text, opener) =>
11243
11286
  // is never dropped as a repeat, wherever in its text it sits.
11244
11287
  const POSITIONAL_AT_RULE_RE = /@(?:charset|import|layer|namespace)\b/i;
11245
11288
 
11289
+ /**
11290
+ * Whether a node is an `@layer` at-rule carrying a name — the only shape a
11291
+ * named layer block can have, answered from the node rather than from the text
11292
+ * it printed.
11293
+ * @param {Node} node a block item
11294
+ * @returns {boolean} true for `@layer <name>`
11295
+ */
11296
+ const _isNamedLayerAtRule = (node) => {
11297
+ const i = _nodeIndex(node);
11298
+ return (
11299
+ _types[i] === T_AT_RULE &&
11300
+ rangeEqualsLowerCase(_input, _starts[i] + 1, _aux0[i], "layer")
11301
+ );
11302
+ };
11303
+
11246
11304
  /**
11247
11305
  * Gather each named `@layer` block into the first sibling block of that name.
11248
11306
  * They are one layer however far apart they stand, and what separates them is in
@@ -11250,16 +11308,26 @@ const POSITIONAL_AT_RULE_RE = /@(?:charset|import|layer|namespace)\b/i;
11250
11308
  * rather than by where they sit, so moving the later body up is not a move the
11251
11309
  * cascade can see. An anonymous `@layer {` is a layer of its own and is left
11252
11310
  * alone (see `ANONYMOUS_LAYER_RE`).
11311
+ * @param {Node[]} items the siblings, in the order their texts stand in
11253
11312
  * @param {string[]} texts the siblings' printed texts, rewritten in place
11254
11313
  * @returns {void}
11255
11314
  */
11256
- const _mergeNamedLayerBlocks = (texts) => {
11315
+ const _mergeNamedLayerBlocks = (items, texts) => {
11257
11316
  if (!_transforms.mergeRules) return;
11317
+ // Which siblings could be one at all, read off the nodes: asking a text
11318
+ // makes the rope that node printed flatten, and this runs for every block.
11319
+ let named = false;
11320
+ for (let i = 0; i < items.length && !named; i++) {
11321
+ named = _isNamedLayerAtRule(items[i]);
11322
+ }
11323
+ if (!named) return;
11258
11324
  /** @type {Map<string, SeenLayer> | null} */
11259
11325
  let first = null;
11260
11326
  for (let i = 0; i < texts.length; i++) {
11261
11327
  const text = texts[i];
11262
- const prelude = _namedLayerOpener(text);
11328
+ const prelude = _isNamedLayerAtRule(items[i])
11329
+ ? _namedLayerOpener(text)
11330
+ : null;
11263
11331
  if (prelude === null) {
11264
11332
  // A sibling naming a layer any other way writes into one of these, and
11265
11333
  // the order within a layer is the cascade's, so nothing folds over it.
@@ -11754,7 +11822,7 @@ const _composeBlockBody = (path, decls, rules, writer, minify, nl, owner) => {
11754
11822
  ? null
11755
11823
  : new Set(childScope.pending.values())
11756
11824
  );
11757
- _mergeNamedLayerBlocks(texts);
11825
+ _mergeNamedLayerBlocks(items, texts);
11758
11826
  }
11759
11827
  // Only the last of a set of declarations of one property can be read, so
11760
11828
  // the earlier ones carry nothing — whatever stands between them. Identical
@@ -150,10 +150,16 @@ HarmonyEvaluatedImportSpecifierDependency.Template = class HarmonyEvaluatedImpor
150
150
  break;
151
151
  }
152
152
  case "namespace": {
153
- value =
154
- ids[0] === "__esModule"
155
- ? ids.length === 1 || undefined
156
- : exportsInfo.isExportProvided(ids);
153
+ // Empty ids are an `export * as ns` hop skipped as side-effect free,
154
+ // leaving the target's own namespace, which always exists.
155
+ if (ids.length === 0) {
156
+ value = true;
157
+ } else {
158
+ value =
159
+ ids[0] === "__esModule"
160
+ ? ids.length === 1 || undefined
161
+ : exportsInfo.isExportProvided(ids);
162
+ }
157
163
  break;
158
164
  }
159
165
  case "dynamic": {
@@ -130,6 +130,7 @@ module.exports = class HarmonyExportDependencyParserPlugin {
130
130
  /** @type {HarmonySettings | undefined} */
131
131
  (parser.getTagData(name, harmonySpecifierTag));
132
132
  if (!settings || settings.ids.length !== 0) return;
133
+ settings.used = true;
133
134
  if (ImportPhaseUtils.isDefer(settings.phase)) return;
134
135
  const harmonyNamedExports = (parser.state.harmonyNamedExports =
135
136
  parser.state.harmonyNamedExports || new Set());
@@ -255,6 +256,7 @@ module.exports = class HarmonyExportDependencyParserPlugin {
255
256
  const settings =
256
257
  /** @type {HarmonySettings} */
257
258
  (parser.getTagData(id, harmonySpecifierTag));
259
+ if (settings) settings.used = true;
258
260
  const harmonyNamedExports = (parser.state.harmonyNamedExports =
259
261
  parser.state.harmonyNamedExports || new Set());
260
262
  harmonyNamedExports.add(name);
@@ -135,6 +135,11 @@ class ExportMode {
135
135
  /** @type {InstanceType<ExportInfo> | null} */
136
136
  this.partialNamespaceExportInfo = null;
137
137
 
138
+ // for "reexport-undefined": the name resolves through a circular
139
+ // reexport chain rather than being absent from a non-harmony module
140
+ /** @type {boolean} */
141
+ this.circular = false;
142
+
138
143
  // for "dynamic-reexport":
139
144
  /** @type {ExportModeIgnored | null} */
140
145
  this.ignored = null;
@@ -396,6 +401,14 @@ const getMode = (moduleGraph, dep, runtimeKey) => {
396
401
  mode.name = name;
397
402
  break;
398
403
  default:
404
+ // forwarding to a circular chain would recurse until the stack
405
+ // blows, so the name resolves to undefined like a missing one
406
+ if (exportInfo.hasCircularTarget(moduleGraph)) {
407
+ mode = new ExportMode("reexport-undefined");
408
+ mode.name = name;
409
+ mode.circular = true;
410
+ break;
411
+ }
399
412
  mode = new ExportMode("normal-reexport");
400
413
  mode.items = [
401
414
  new NormalReexportItem(name, ids, exportInfo, false, false)
@@ -1059,10 +1072,40 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
1059
1072
  */
1060
1073
  getWarnings(moduleGraph) {
1061
1074
  const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
1075
+ const circular = this._getCircularReexportWarnings(moduleGraph);
1062
1076
  if (exportsPresence === ExportPresenceModes.WARN) {
1063
- return this._getErrors(moduleGraph);
1077
+ const errors = this._getErrors(moduleGraph);
1078
+ if (!circular) return errors;
1079
+ return errors ? [...errors, ...circular] : circular;
1064
1080
  }
1065
- return null;
1081
+ return circular;
1082
+ }
1083
+
1084
+ /**
1085
+ * Returns warnings for a name resolving through a circular reexport chain,
1086
+ * off the export-presence path so a strict harmony module warns, not fails.
1087
+ * @param {ModuleGraph} moduleGraph module graph
1088
+ * @returns {WebpackError[] | undefined} warnings
1089
+ */
1090
+ _getCircularReexportWarnings(moduleGraph) {
1091
+ const ids = this.getIds(moduleGraph);
1092
+ if (ids.length === 0 || !this.name) return;
1093
+ const parentModule = /** @type {Module} */ (
1094
+ moduleGraph.getParentModule(this)
1095
+ );
1096
+ const exportInfo = moduleGraph
1097
+ .getExportsInfo(parentModule)
1098
+ .getReadOnlyExportInfo(this.name);
1099
+ if (!exportInfo.hasCircularTarget(moduleGraph)) return;
1100
+ return [
1101
+ new HarmonyLinkingError(
1102
+ `export '${ids.join(".")}' (reexported as '${
1103
+ this.name
1104
+ }') is part of a circular reexport chain in '${
1105
+ this.userRequest
1106
+ }' and is undefined`
1107
+ )
1108
+ ];
1066
1109
  }
1067
1110
 
1068
1111
  /**
@@ -1429,7 +1472,9 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
1429
1472
  initFragments.push(
1430
1473
  this.getReexportFragment(
1431
1474
  module,
1432
- "reexport non-default export from non-harmony",
1475
+ mode.circular
1476
+ ? "reexport circular"
1477
+ : "reexport non-default export from non-harmony",
1433
1478
  moduleGraph
1434
1479
  .getExportsInfo(module)
1435
1480
  .getUsedName(/** @type {string} */ (mode.name), runtime),