webpack 5.108.2 → 5.108.4

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.
@@ -435,15 +435,13 @@ class ImportParserPlugin {
435
435
  }
436
436
  }
437
437
  if (importOptions.webpackExports !== undefined) {
438
- if (
439
- !(
440
- typeof importOptions.webpackExports === "string" ||
441
- (Array.isArray(importOptions.webpackExports) &&
442
- importOptions.webpackExports.every(
443
- (item) => typeof item === "string"
444
- ))
445
- )
446
- ) {
438
+ if (!(
439
+ typeof importOptions.webpackExports === "string" ||
440
+ (Array.isArray(importOptions.webpackExports) &&
441
+ importOptions.webpackExports.every(
442
+ (item) => typeof item === "string"
443
+ ))
444
+ )) {
447
445
  parser.state.module.addWarning(
448
446
  new UnsupportedFeatureWarning(
449
447
  `\`webpackExports\` expected a string or an array of strings, but received: ${importOptions.webpackExports}.`,
@@ -14,8 +14,12 @@ const {
14
14
  } = require("../ModuleSourceTypeConstants");
15
15
  const RuntimeGlobals = require("../RuntimeGlobals");
16
16
  const Template = require("../Template");
17
+ const memoize = require("../util/memoize");
17
18
  const { PUBLIC_PATH_AUTO } = require("../util/publicPathPlaceholder");
18
19
 
20
+ // Lazy so loading the HTML generator doesn't pull in the whole CSS pipeline.
21
+ const getCssModulesPlugin = memoize(() => require("../css/CssModulesPlugin"));
22
+
19
23
  /** @typedef {import("webpack-sources").Source} Source */
20
24
  /** @typedef {import("../../declarations/WebpackOptions").HtmlGeneratorOptions} HtmlGeneratorOptions */
21
25
  /** @typedef {import("../Chunk")} Chunk */
@@ -31,6 +35,7 @@ const { PUBLIC_PATH_AUTO } = require("../util/publicPathPlaceholder");
31
35
  /** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
32
36
  /** @typedef {import("../ModuleGraph")} ModuleGraph */
33
37
  /** @typedef {import("../NormalModule")} NormalModule */
38
+ /** @typedef {import("./HtmlModule").HtmlModuleBuildInfo} HtmlModuleBuildInfo */
34
39
  /** @typedef {import("../Module").RuntimeRequirements} RuntimeRequirements */
35
40
  /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
36
41
  /** @typedef {import("../util/Hash")} Hash */
@@ -94,9 +99,7 @@ class HtmlGenerator extends Generator {
94
99
  if (!chunk) return "data:,";
95
100
  let filenameTemplate;
96
101
  if (contentHashType === "css") {
97
- const CssModulesPlugin = require("../css/CssModulesPlugin");
98
-
99
- filenameTemplate = CssModulesPlugin.getChunkFilenameTemplate(
102
+ filenameTemplate = getCssModulesPlugin().getChunkFilenameTemplate(
100
103
  chunk,
101
104
  outputOptions
102
105
  );
@@ -238,25 +241,53 @@ class HtmlGenerator extends Generator {
238
241
 
239
242
  /**
240
243
  * Processes the provided module.
241
- * @param {NormalModule} module the current module
242
244
  * @param {Dependency} dependency the dependency to generate
243
- * @param {InitFragment<GenerateContext>[]} initFragments mutable list of init fragments
244
245
  * @param {ReplaceSource} source the current replace source which can be modified
245
- * @param {GenerateContext} generateContext the render context
246
+ * @param {DependencyTemplateContext} templateContext the template context (shared across all dependencies of the module)
246
247
  * @returns {void}
247
248
  */
248
- sourceDependency(module, dependency, initFragments, source, generateContext) {
249
+ sourceDependency(dependency, source, templateContext) {
249
250
  const constructor =
250
251
  /** @type {DependencyConstructor} */
251
252
  (dependency.constructor);
252
- const template = generateContext.dependencyTemplates.get(constructor);
253
+ const template = templateContext.dependencyTemplates.get(constructor);
253
254
  if (!template) {
254
255
  throw new Error(
255
256
  `No template for dependency: ${dependency.constructor.name}`
256
257
  );
257
258
  }
258
259
 
259
- /** @type {DependencyTemplateContext} */
260
+ template.apply(dependency, source, templateContext);
261
+ }
262
+
263
+ /**
264
+ * Processes the provided dependencies block.
265
+ * @param {import("../DependenciesBlock")} block the dependencies block which will be processed
266
+ * @param {ReplaceSource} source the current replace source which can be modified
267
+ * @param {DependencyTemplateContext} templateContext the template context
268
+ * @returns {void}
269
+ */
270
+ sourceBlock(block, source, templateContext) {
271
+ for (const dependency of block.dependencies) {
272
+ this.sourceDependency(dependency, source, templateContext);
273
+ }
274
+
275
+ for (const childBlock of block.blocks) {
276
+ this.sourceBlock(childBlock, source, templateContext);
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Processes the provided module.
282
+ * @param {NormalModule} module the module to generate
283
+ * @param {InitFragment<GenerateContext>[]} initFragments mutable list of init fragments
284
+ * @param {ReplaceSource} source the current replace source which can be modified
285
+ * @param {GenerateContext} generateContext the generateContext
286
+ * @returns {void}
287
+ */
288
+ sourceModule(module, initFragments, source, generateContext) {
289
+ // Only `dependency` varies across `template.apply` calls, so one context
290
+ // (and one lazy `chunkInitFragments` getter) serves the whole module.
260
291
  /** @type {InitFragment<GenerateContext>[] | undefined} */
261
292
  let chunkInitFragments;
262
293
  /** @type {DependencyTemplateContext} */
@@ -289,79 +320,18 @@ class HtmlGenerator extends Generator {
289
320
  }
290
321
  };
291
322
 
292
- template.apply(dependency, source, templateContext);
293
- }
294
-
295
- /**
296
- * Processes the provided dependencies block.
297
- * @param {NormalModule} module the module to generate
298
- * @param {import("../DependenciesBlock")} block the dependencies block which will be processed
299
- * @param {InitFragment<GenerateContext>[]} initFragments mutable list of init fragments
300
- * @param {ReplaceSource} source the current replace source which can be modified
301
- * @param {GenerateContext} generateContext the generateContext
302
- * @returns {void}
303
- */
304
- sourceBlock(module, block, initFragments, source, generateContext) {
305
- for (const dependency of block.dependencies) {
306
- this.sourceDependency(
307
- module,
308
- dependency,
309
- initFragments,
310
- source,
311
- generateContext
312
- );
313
- }
314
-
315
- for (const childBlock of block.blocks) {
316
- this.sourceBlock(
317
- module,
318
- childBlock,
319
- initFragments,
320
- source,
321
- generateContext
322
- );
323
- }
324
- }
325
-
326
- /**
327
- * Processes the provided module.
328
- * @param {NormalModule} module the module to generate
329
- * @param {InitFragment<GenerateContext>[]} initFragments mutable list of init fragments
330
- * @param {ReplaceSource} source the current replace source which can be modified
331
- * @param {GenerateContext} generateContext the generateContext
332
- * @returns {void}
333
- */
334
- sourceModule(module, initFragments, source, generateContext) {
335
323
  for (const dependency of module.dependencies) {
336
- this.sourceDependency(
337
- module,
338
- dependency,
339
- initFragments,
340
- source,
341
- generateContext
342
- );
324
+ this.sourceDependency(dependency, source, templateContext);
343
325
  }
344
326
 
345
327
  if (module.presentationalDependencies !== undefined) {
346
328
  for (const dependency of module.presentationalDependencies) {
347
- this.sourceDependency(
348
- module,
349
- dependency,
350
- initFragments,
351
- source,
352
- generateContext
353
- );
329
+ this.sourceDependency(dependency, source, templateContext);
354
330
  }
355
331
  }
356
332
 
357
333
  for (const childBlock of module.blocks) {
358
- this.sourceBlock(
359
- module,
360
- childBlock,
361
- initFragments,
362
- source,
363
- generateContext
364
- );
334
+ this.sourceBlock(childBlock, source, templateContext);
365
335
  }
366
336
  }
367
337
 
@@ -403,7 +373,12 @@ class HtmlGenerator extends Generator {
403
373
 
404
374
  // JS-export path — resolve `[webpack/auto]` inline; chunk-URL sentinels
405
375
  // stay for `HtmlModulesPlugin`'s `JavascriptModulesPlugin.render` tap.
406
- return rawContent.split(PUBLIC_PATH_AUTO).join(undoPath);
376
+ if (!rawContent.includes(PUBLIC_PATH_AUTO)) return rawContent;
377
+ // A relative `<base href>` prepends `../`s so the base can't misdirect
378
+ // the rewritten URLs (see `HtmlParser`).
379
+ const basePrefix =
380
+ /** @type {HtmlModuleBuildInfo} */ (module.buildInfo).baseUrlPrefix || "";
381
+ return rawContent.split(PUBLIC_PATH_AUTO).join(basePrefix + undoPath);
407
382
  }
408
383
 
409
384
  /**
@@ -603,10 +578,12 @@ class HtmlGenerator extends Generator {
603
578
  // Source-type set changes when html-type exposure flips; the HMR shim's
604
579
  // `extracting` branch changes when the emit decision flips. They differ
605
580
  // only for `"inline"` (exposes html, but does not emit), so hash both.
606
- if (this._shouldExposeHtmlType(updateHashContext.module)) {
581
+ // One `_shouldExtract` walk covers both checks (expose = extract ∪ inline).
582
+ const extract = this._shouldExtract(updateHashContext.module);
583
+ if (extract || this.options.extract === "inline") {
607
584
  hash.update("html-type");
608
585
  }
609
- if (this._shouldExtract(updateHashContext.module)) {
586
+ if (extract) {
610
587
  hash.update("extract");
611
588
  }
612
589
  // The HMR shim emits additional self-accept / DOM-patch code that
@@ -15,6 +15,7 @@ const makeSerializable = require("../util/makeSerializable");
15
15
  * Defines the build info properties specific to html modules.
16
16
  * @typedef {object} KnownHtmlModuleBuildInfo
17
17
  * @property {Record<string, EntryScriptInfo[]>=} htmlEntryScripts entries collected from the document, grouped by kind
18
+ * @property {string=} baseUrlPrefix `../` per `<base href>` path segment, prepended to the auto-public-path undo path so a relative base doesn't misdirect bundled URLs
18
19
  */
19
20
 
20
21
  /** @typedef {NormalModuleBuildInfo & KnownHtmlModuleBuildInfo} HtmlModuleBuildInfo */
@@ -568,14 +568,21 @@ class HtmlModulesPlugin {
568
568
  // `main.js` root-relative, so the browser would resolve
569
569
  // them under the HTML's directory instead of the
570
570
  // `output.path` root.
571
- const undoPath = getUndoPath(
572
- filename,
573
- /** @type {string} */ (outputOptions.path),
574
- false
575
- );
576
- const finalContent = resolvedContent
577
- .split(autoPlaceholder)
578
- .join(undoPath);
571
+ // A relative `<base href>` prepends `../`s so the base can't
572
+ // misdirect the rewritten URLs (see `HtmlParser`).
573
+ const basePrefix =
574
+ /** @type {HtmlModuleBuildInfo} */ (normalModule.buildInfo)
575
+ .baseUrlPrefix || "";
576
+ const undoPath =
577
+ basePrefix +
578
+ getUndoPath(
579
+ filename,
580
+ /** @type {string} */ (outputOptions.path),
581
+ false
582
+ );
583
+ const finalContent = resolvedContent.includes(autoPlaceholder)
584
+ ? resolvedContent.split(autoPlaceholder).join(undoPath)
585
+ : resolvedContent;
579
586
  const finalSource = new RawSource(finalContent);
580
587
  // The same HTML module can land in multiple chunks
581
588
  // with different `output.htmlFilename` /
@@ -585,11 +592,15 @@ class HtmlModulesPlugin {
585
592
  // the emitted filename in the asset cache key and
586
593
  // the post-undo-path content in the hash, so the
587
594
  // asset cache can't reuse one variant's bytes at
588
- // another variant's URL.
589
- const finalContentHash = HtmlModulesPlugin.computeContentHash(
590
- finalContent,
591
- outputOptions
592
- );
595
+ // another variant's URL. Unchanged content reuses
596
+ // the memoized hash instead of re-digesting.
597
+ const finalContentHash =
598
+ finalContent === resolvedContent
599
+ ? contentHash
600
+ : HtmlModulesPlugin.computeContentHash(
601
+ finalContent,
602
+ outputOptions
603
+ );
593
604
 
594
605
  result.push({
595
606
  render: () => finalSource,