webpack 5.107.0 → 5.107.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.
Files changed (47) hide show
  1. package/lib/BannerPlugin.js +3 -4
  2. package/lib/Chunk.js +21 -25
  3. package/lib/ChunkGroup.js +57 -15
  4. package/lib/Compilation.js +33 -11
  5. package/lib/EvalSourceMapDevToolPlugin.js +0 -1
  6. package/lib/ExportsInfo.js +30 -34
  7. package/lib/ExternalModule.js +15 -11
  8. package/lib/ExternalModuleFactoryPlugin.js +2 -1
  9. package/lib/Module.js +1 -1
  10. package/lib/ModuleNotFoundError.js +10 -0
  11. package/lib/ModuleSourceTypeConstants.js +24 -22
  12. package/lib/NormalModule.js +106 -46
  13. package/lib/NormalModuleFactory.js +38 -26
  14. package/lib/RuntimePlugin.js +1 -1
  15. package/lib/SourceMapDevToolPlugin.js +250 -49
  16. package/lib/Template.js +1 -1
  17. package/lib/TemplatedPathPlugin.js +22 -4
  18. package/lib/asset/AssetBytesGenerator.js +6 -6
  19. package/lib/asset/AssetGenerator.js +14 -14
  20. package/lib/asset/AssetModulesPlugin.js +3 -7
  21. package/lib/asset/AssetSourceGenerator.js +6 -6
  22. package/lib/css/CssModulesPlugin.js +2 -2
  23. package/lib/dependencies/CommonJsImportsParserPlugin.js +108 -1
  24. package/lib/dependencies/CssUrlDependency.js +3 -2
  25. package/lib/dependencies/HarmonyDetectionParserPlugin.js +21 -1
  26. package/lib/dependencies/HtmlScriptSrcDependency.js +264 -25
  27. package/lib/dependencies/HtmlSourceDependency.js +3 -2
  28. package/lib/html/HtmlModulesPlugin.js +1 -5
  29. package/lib/html/walkHtmlTokens.js +641 -125
  30. package/lib/index.js +2 -0
  31. package/lib/javascript/JavascriptModulesPlugin.js +2 -2
  32. package/lib/optimize/SideEffectsFlagPlugin.js +1 -2
  33. package/lib/optimize/SplitChunksPlugin.js +4 -4
  34. package/lib/runtime/AutoPublicPathRuntimeModule.js +3 -3
  35. package/lib/runtime/GetChunkFilenameRuntimeModule.js +5 -5
  36. package/lib/sharing/ConsumeSharedPlugin.js +2 -8
  37. package/lib/sharing/ProvideSharedPlugin.js +4 -4
  38. package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +1 -2
  39. package/package.json +3 -3
  40. package/schemas/WebpackOptions.check.js +1 -1
  41. package/schemas/WebpackOptions.json +11 -9
  42. package/schemas/plugins/container/ContainerReferencePlugin.check.js +1 -1
  43. package/schemas/plugins/container/ContainerReferencePlugin.json +1 -0
  44. package/schemas/plugins/container/ExternalsType.check.js +1 -1
  45. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  46. package/schemas/plugins/container/ModuleFederationPlugin.json +1 -0
  47. package/types.d.ts +355 -144
@@ -30,7 +30,7 @@ const { makePathsAbsolute } = require("./util/identifier");
30
30
  /** @typedef {import("./Compiler")} Compiler */
31
31
  /** @typedef {import("./Module")} Module */
32
32
  /** @typedef {import("./NormalModule").RawSourceMap} RawSourceMap */
33
- /** @typedef {import("./TemplatedPathPlugin").TemplatePath} TemplatePath */
33
+ /** @typedef {import("./TemplatedPathPlugin").TemplatePath} SourceMappingURLComment */
34
34
  /** @typedef {import("./util/fs").OutputFileSystem} OutputFileSystem */
35
35
 
36
36
  /**
@@ -70,6 +70,91 @@ const resetRegexpState = (regexp) => {
70
70
  */
71
71
  const quoteMeta = (str) => str.replace(METACHARACTERS_REGEXP, "\\$&");
72
72
 
73
+ /**
74
+ * Compilation-scoped registry of original asset sources for multi-plugin
75
+ * cooperation. The first SourceMapDevToolPlugin instance to see a file pins a
76
+ * reference to the asset's still-unwrapped {@link Source} object; later
77
+ * instances whose `asset.source.sourceAndMap()` would now return `null` (the
78
+ * earlier instance replaced the asset with a `RawSource`) can re-extract the
79
+ * map from this pinned reference. We keep the registry on a module-scoped
80
+ * `WeakMap` so the entries are reclaimed automatically when the compilation
81
+ * itself becomes unreachable; we never store anything on the compilation
82
+ * object directly.
83
+ *
84
+ * Stashing the `Source` object itself rather than an extracted map keeps the
85
+ * fast path free of cloning and source-map serialization work — the
86
+ * extraction only happens if a subsequent plugin actually needs the map.
87
+ * @type {WeakMap<Compilation, Map<string, Source>>}
88
+ */
89
+ const originalSourceRegistry = new WeakMap();
90
+
91
+ /**
92
+ * Returns (creating if necessary) the per-compilation registry of original
93
+ * asset {@link Source} objects.
94
+ * @param {Compilation} compilation compilation
95
+ * @returns {Map<string, Source>} registry
96
+ */
97
+ const getOriginalSourceRegistry = (compilation) => {
98
+ let registry = originalSourceRegistry.get(compilation);
99
+ if (registry === undefined) {
100
+ registry = new Map();
101
+ originalSourceRegistry.set(compilation, registry);
102
+ }
103
+ return registry;
104
+ };
105
+
106
+ /**
107
+ * Extracts source and source map from a Source object, falling back to a
108
+ * registered original source for assets that another SourceMapDevToolPlugin
109
+ * instance has already wrapped (whose internal map is now `null`).
110
+ *
111
+ * The returned source is read from the asset as it currently stands — that way
112
+ * any `sourceMappingURL` comments appended by earlier plugin instances survive
113
+ * — while the map is taken from the pinned original Source when the current
114
+ * one no longer carries it.
115
+ * @param {string} file file name
116
+ * @param {Source} asset source object as currently held by the compilation
117
+ * @param {MapOptions} options map extraction options
118
+ * @param {Map<string, Source>} registry compilation-scoped original-source registry
119
+ * @returns {{ source: string, sourceMap: RawSourceMap } | undefined} extracted pair or `undefined` when no map is recoverable
120
+ */
121
+ const extractSourceAndMap = (file, asset, options, registry) => {
122
+ /** @type {string | Buffer} */
123
+ let source;
124
+ /** @type {null | RawSourceMap} */
125
+ let sourceMap;
126
+ if (asset.sourceAndMap) {
127
+ const sourceAndMap = asset.sourceAndMap(options);
128
+ source = sourceAndMap.source;
129
+ sourceMap = sourceAndMap.map;
130
+ } else {
131
+ source = asset.source();
132
+ sourceMap = asset.map(options);
133
+ }
134
+ // Bail before touching the registry if we can't return a usable string
135
+ // source — pinning a non-string-producing asset would only waste the slot.
136
+ if (typeof source !== "string") return;
137
+ if (sourceMap) {
138
+ // The current asset still owns the original map — pin a reference so
139
+ // that a later plugin instance (which will see a rewrapped asset
140
+ // without a map) can recover it on demand.
141
+ if (!registry.has(file)) registry.set(file, asset);
142
+ } else {
143
+ // The current asset (typically a `RawSource` left by an earlier
144
+ // SourceMapDevToolPlugin instance) has no internal map. Re-extract
145
+ // the map from the original Source we pinned earlier. We keep using
146
+ // `source` from the current asset so that any prior wrappers (e.g.
147
+ // appended sourceMappingURL comments) are preserved.
148
+ const original = registry.get(file);
149
+ if (!original) return;
150
+ sourceMap = original.sourceAndMap
151
+ ? original.sourceAndMap(options).map
152
+ : original.map(options);
153
+ if (!sourceMap) return;
154
+ }
155
+ return { source, sourceMap };
156
+ };
157
+
73
158
  /**
74
159
  * Creating {@link SourceMapTask} for given file
75
160
  * @param {string} file current compiled file
@@ -78,6 +163,7 @@ const quoteMeta = (str) => str.replace(METACHARACTERS_REGEXP, "\\$&");
78
163
  * @param {MapOptions} options source map options
79
164
  * @param {Compilation} compilation compilation instance
80
165
  * @param {ItemCacheFacade} cacheItem cache item
166
+ * @param {Map<string, Source>} registry compilation-scoped original-source registry
81
167
  * @returns {SourceMapTask | undefined} created task instance or `undefined`
82
168
  */
83
169
  const getTaskForFile = (
@@ -86,24 +172,12 @@ const getTaskForFile = (
86
172
  assetInfo,
87
173
  options,
88
174
  compilation,
89
- cacheItem
175
+ cacheItem,
176
+ registry
90
177
  ) => {
91
- /** @type {string | Buffer} */
92
- let source;
93
- /** @type {null | RawSourceMap} */
94
- let sourceMap;
95
- /**
96
- * Check if asset can build source map
97
- */
98
- if (asset.sourceAndMap) {
99
- const sourceAndMap = asset.sourceAndMap(options);
100
- sourceMap = sourceAndMap.map;
101
- source = sourceAndMap.source;
102
- } else {
103
- sourceMap = asset.map(options);
104
- source = asset.source();
105
- }
106
- if (!sourceMap || typeof source !== "string") return;
178
+ const extracted = extractSourceAndMap(file, asset, options, registry);
179
+ if (!extracted) return;
180
+ const { source, sourceMap } = extracted;
107
181
  const context = compilation.options.context;
108
182
  const root = compilation.compiler.root;
109
183
  const cachedAbsolutify = makePathsAbsolute.bindContextCache(context, root);
@@ -117,7 +191,7 @@ const getTaskForFile = (
117
191
  return {
118
192
  file,
119
193
  asset,
120
- source,
194
+ source: /** @type {string} */ (source),
121
195
  assetInfo,
122
196
  sourceMap,
123
197
  modules,
@@ -127,6 +201,29 @@ const getTaskForFile = (
127
201
 
128
202
  const PLUGIN_NAME = "SourceMapDevToolPlugin";
129
203
 
204
+ /**
205
+ * Maps a configuration value (string, RegExp, function, nullish, or array of
206
+ * such) into a JSON-serializable form. Functions and RegExps are turned into
207
+ * their `.toString()` representation so that changes to inline callbacks
208
+ * invalidate caches; everything else is returned as-is so that the surrounding
209
+ * `JSON.stringify` does the escaping.
210
+ *
211
+ * The result is used through `JSON.stringify` to build cache identifiers, so
212
+ * we deliberately avoid any homemade `|` / `,` separators that could collide
213
+ * with characters appearing inside user-provided values such as `publicPath`,
214
+ * template strings, or `sourceRoot`.
215
+ * @param {EXPECTED_ANY} value option value
216
+ * @returns {EXPECTED_ANY} JSON-serializable representation
217
+ */
218
+ const toCacheKeyValue = (value) => {
219
+ if (value === undefined || value === null) return value;
220
+ if (Array.isArray(value)) return value.map(toCacheKeyValue);
221
+ if (value instanceof RegExp || typeof value === "function") {
222
+ return value.toString();
223
+ }
224
+ return value;
225
+ };
226
+
130
227
  class SourceMapDevToolPlugin {
131
228
  /**
132
229
  * Creates an instance of SourceMapDevToolPlugin.
@@ -136,7 +233,7 @@ class SourceMapDevToolPlugin {
136
233
  constructor(options = {}) {
137
234
  /** @type {undefined | null | false | string} */
138
235
  this.sourceMapFilename = options.filename;
139
- /** @type {false | TemplatePath} */
236
+ /** @type {false | SourceMappingURLComment} */
140
237
  this.sourceMappingURLComment =
141
238
  options.append === false
142
239
  ? false
@@ -153,6 +250,28 @@ class SourceMapDevToolPlugin {
153
250
  this.namespace = options.namespace || "";
154
251
  /** @type {SourceMapDevToolPluginOptions} */
155
252
  this.options = options;
253
+ // Cache salt derived from output-affecting options, so that two
254
+ // SourceMapDevToolPlugin instances (or `devtool` + a plugin) operating
255
+ // on the same asset don't share a cache entry. We serialize via
256
+ // `JSON.stringify` rather than a homemade separator so that any
257
+ // special characters (e.g. `|` inside a publicPath or sourceRoot)
258
+ // can't accidentally make two different option sets collide.
259
+ /** @type {string} */
260
+ this._cacheSalt = JSON.stringify([
261
+ toCacheKeyValue(options.filename),
262
+ toCacheKeyValue(options.append),
263
+ toCacheKeyValue(this.moduleFilenameTemplate),
264
+ toCacheKeyValue(this.fallbackModuleFilenameTemplate),
265
+ toCacheKeyValue(this.namespace),
266
+ options.module !== false,
267
+ options.columns !== false,
268
+ Boolean(options.noSources),
269
+ Boolean(options.debugIds),
270
+ options.sourceRoot || "",
271
+ toCacheKeyValue(options.ignoreList),
272
+ options.publicPath || "",
273
+ options.fileContext || ""
274
+ ]);
156
275
  }
157
276
 
158
277
  /**
@@ -195,6 +314,14 @@ class SourceMapDevToolPlugin {
195
314
  compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
196
315
  new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation);
197
316
 
317
+ // All SourceMapDevToolPlugin instances on the same compilation share
318
+ // a registry of pristine asset sources, so the second instance to
319
+ // run can still recover the original map after the first instance
320
+ // has replaced the asset with a `RawSource`. The registry lives on a
321
+ // module-scoped `WeakMap` keyed by compilation so it is released
322
+ // automatically and never pollutes the compilation object.
323
+ const originalSources = getOriginalSourceRegistry(compilation);
324
+
198
325
  compilation.hooks.processAssets.tapAsync(
199
326
  {
200
327
  name: PLUGIN_NAME,
@@ -239,18 +366,22 @@ class SourceMapDevToolPlugin {
239
366
  const asset =
240
367
  /** @type {Readonly<Asset>} */
241
368
  (compilation.getAsset(file));
242
- if (asset.info.related && asset.info.related.sourceMap) {
243
- fileIndex++;
244
- return callback();
245
- }
246
369
 
247
370
  const chunk = fileToChunk.get(file);
248
371
  const sourceMapNamespace = compilation.getPath(this.namespace, {
249
372
  chunk
250
373
  });
251
374
 
375
+ // The cache item identifier must include the per-instance
376
+ // salt so two SourceMapDevToolPlugin instances that target
377
+ // the same `file` don't collide in the persistent cache —
378
+ // they'd otherwise write different content to the same key
379
+ // and invalidate every pack on each build. We encode via
380
+ // `JSON.stringify` so that special characters (e.g. `|`)
381
+ // in an asset filename can't be spoofed to collide with the
382
+ // salt portion of the identifier.
252
383
  const cacheItem = cache.getItemCache(
253
- file,
384
+ JSON.stringify([file, this._cacheSalt]),
254
385
  cache.mergeEtags(
255
386
  cache.getLazyHashedEtag(asset.source),
256
387
  sourceMapNamespace
@@ -265,6 +396,16 @@ class SourceMapDevToolPlugin {
265
396
  * If presented in cache, reassigns assets. Cache assets already have source maps.
266
397
  */
267
398
  if (cacheEntry) {
399
+ // Pin the still-unwrapped asset source in the registry
400
+ // before `compilation.updateAsset` replaces it. This is a
401
+ // pointer assignment — no source-map extraction work — and
402
+ // it lets a subsequent SourceMapDevToolPlugin instance
403
+ // extract the original map on demand even though the
404
+ // persistent cache hit lets us skip processing here.
405
+ if (!originalSources.has(file)) {
406
+ originalSources.set(file, asset.source);
407
+ }
408
+
268
409
  const { assets, assetsInfo } = cacheEntry;
269
410
  for (const cachedFile of Object.keys(assets)) {
270
411
  if (cachedFile === file) {
@@ -313,7 +454,8 @@ class SourceMapDevToolPlugin {
313
454
  columns: options.columns
314
455
  },
315
456
  compilation,
316
- cacheItem
457
+ cacheItem,
458
+ originalSources
317
459
  );
318
460
 
319
461
  if (task) {
@@ -446,12 +588,21 @@ class SourceMapDevToolPlugin {
446
588
  "attach SourceMap"
447
589
  );
448
590
 
449
- const moduleFilenames = modules.map((m) =>
450
- moduleToSourceNameMapping.get(m)
451
- );
452
- sourceMap.sources = /** @type {string[]} */ (moduleFilenames);
591
+ const moduleFilenames =
592
+ /** @type {string[]} */
593
+ (modules.map((m) => moduleToSourceNameMapping.get(m)));
594
+ // We deliberately do NOT mutate `sourceMap` in place: the
595
+ // task's `sourceMap` reference may be shared with a
596
+ // `SourceMapSource` whose internal map cache is the same
597
+ // object (webpack-sources keeps it cached). A second
598
+ // `SourceMapDevToolPlugin` instance that reads the original
599
+ // source through the registry would otherwise see our
600
+ // rewrites. Instead we build a fresh `outputSourceMap` for
601
+ // the .map file and leave the original alone.
602
+ /** @type {number[] | undefined} */
603
+ let ignoreList;
453
604
  if (options.ignoreList) {
454
- const ignoreList = sourceMap.sources.reduce(
605
+ const list = moduleFilenames.reduce(
455
606
  /** @type {(acc: number[], sourceName: string, idx: number) => number[]} */ (
456
607
  (acc, sourceName, idx) => {
457
608
  const rule = /** @type {Rules} */ (
@@ -467,35 +618,29 @@ class SourceMapDevToolPlugin {
467
618
  ),
468
619
  []
469
620
  );
470
- if (ignoreList.length > 0) {
471
- sourceMap.ignoreList = ignoreList;
472
- }
621
+ if (list.length > 0) ignoreList = list;
473
622
  }
474
623
 
475
- if (options.noSources) {
476
- sourceMap.sourcesContent = undefined;
477
- }
478
- sourceMap.sourceRoot = options.sourceRoot || "";
479
- sourceMap.file = file;
480
624
  const usesContentHash =
481
625
  sourceMapFilename &&
482
626
  CONTENT_HASH_DETECT_REGEXP.test(sourceMapFilename);
483
627
 
484
628
  resetRegexpState(CONTENT_HASH_DETECT_REGEXP);
485
629
 
630
+ let outputFile = file;
486
631
  // If SourceMap and asset uses contenthash, avoid a circular dependency by hiding hash in `file`
487
632
  if (usesContentHash && task.assetInfo.contenthash) {
488
633
  const contenthash = task.assetInfo.contenthash;
489
634
  const pattern = Array.isArray(contenthash)
490
635
  ? contenthash.map(quoteMeta).join("|")
491
636
  : quoteMeta(contenthash);
492
- sourceMap.file = sourceMap.file.replace(
637
+ outputFile = outputFile.replace(
493
638
  new RegExp(pattern, "g"),
494
639
  (m) => "x".repeat(m.length)
495
640
  );
496
641
  }
497
642
 
498
- /** @type {false | TemplatePath} */
643
+ /** @type {false | SourceMappingURLComment} */
499
644
  let currentSourceMappingURLComment = sourceMappingURLComment;
500
645
  const cssExtensionDetected =
501
646
  CSS_EXTENSION_DETECT_REGEXP.test(file);
@@ -512,18 +657,48 @@ class SourceMapDevToolPlugin {
512
657
  );
513
658
  }
514
659
 
660
+ /** @type {string | undefined} */
661
+ let debugIdValue;
515
662
  if (options.debugIds) {
516
- const debugId = generateDebugId(source, sourceMap.file);
517
- sourceMap.debugId = debugId;
663
+ const debugId = generateDebugId(source, outputFile);
664
+ debugIdValue = debugId;
518
665
 
519
666
  const debugIdComment = `\n//# debugId=${debugId}`;
520
- currentSourceMappingURLComment =
521
- currentSourceMappingURLComment
522
- ? `${debugIdComment}${currentSourceMappingURLComment}`
523
- : debugIdComment;
667
+ if (currentSourceMappingURLComment === false) {
668
+ currentSourceMappingURLComment = debugIdComment;
669
+ } else if (
670
+ typeof currentSourceMappingURLComment === "function"
671
+ ) {
672
+ // Wrap the user's append function so the debug-id
673
+ // comment is prepended at call time. Template-string
674
+ // concatenation would coerce the function to a string
675
+ // and lose its dynamic behavior.
676
+ const wrappedFn = currentSourceMappingURLComment;
677
+ currentSourceMappingURLComment = (pathData, assetInfo) =>
678
+ `${debugIdComment}${wrappedFn(pathData, assetInfo)}`;
679
+ } else {
680
+ currentSourceMappingURLComment = `${debugIdComment}${currentSourceMappingURLComment}`;
681
+ }
524
682
  }
525
683
 
526
- const sourceMapString = JSON.stringify(sourceMap);
684
+ /** @type {RawSourceMap} */
685
+ const outputSourceMap = {
686
+ ...sourceMap,
687
+ sources: moduleFilenames,
688
+ sourceRoot: options.sourceRoot || "",
689
+ file: outputFile
690
+ };
691
+ if (ignoreList !== undefined) {
692
+ outputSourceMap.ignoreList = ignoreList;
693
+ }
694
+ if (options.noSources) {
695
+ outputSourceMap.sourcesContent = undefined;
696
+ }
697
+ if (debugIdValue !== undefined) {
698
+ outputSourceMap.debugId = debugIdValue;
699
+ }
700
+
701
+ const sourceMapString = JSON.stringify(outputSourceMap);
527
702
  if (sourceMapFilename) {
528
703
  const filename = file;
529
704
  const sourceMapContentHash = usesContentHash
@@ -567,8 +742,34 @@ class SourceMapDevToolPlugin {
567
742
  })
568
743
  );
569
744
  }
745
+ // Preserve any existing related.sourceMap entries from
746
+ // earlier SourceMapDevToolPlugin runs on the same asset so
747
+ // that all generated maps remain discoverable via asset
748
+ // info (the schema allows string or string[]).
749
+ const existingSourceMap =
750
+ task.assetInfo.related &&
751
+ task.assetInfo.related.sourceMap;
752
+ /** @type {string | string[]} */
753
+ let relatedSourceMap;
754
+ if (
755
+ existingSourceMap === undefined ||
756
+ existingSourceMap === null
757
+ ) {
758
+ relatedSourceMap = sourceMapFile;
759
+ } else if (Array.isArray(existingSourceMap)) {
760
+ relatedSourceMap = existingSourceMap.includes(
761
+ sourceMapFile
762
+ )
763
+ ? existingSourceMap
764
+ : [...existingSourceMap, sourceMapFile];
765
+ } else {
766
+ relatedSourceMap =
767
+ existingSourceMap === sourceMapFile
768
+ ? existingSourceMap
769
+ : [existingSourceMap, sourceMapFile];
770
+ }
570
771
  const assetInfo = {
571
- related: { sourceMap: sourceMapFile }
772
+ related: { sourceMap: relatedSourceMap }
572
773
  };
573
774
  assets[file] = asset;
574
775
  assetsInfo[file] = assetInfo;
package/lib/Template.js CHANGED
@@ -63,7 +63,7 @@ const MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g;
63
63
  * Defines the render manifest entry templated type used by this module.
64
64
  * @typedef {object} RenderManifestEntryTemplated
65
65
  * @property {() => Source} render
66
- * @property {TemplatePath} filenameTemplate
66
+ * @property {string | import("./TemplatedPathPlugin").TemplatePathFn<EXPECTED_ANY>} filenameTemplate
67
67
  * @property {PathData=} pathOptions
68
68
  * @property {AssetInfo=} info
69
69
  * @property {string} identifier
@@ -18,6 +18,8 @@ const getMimeTypes = memoize(() => require("./util/mimeTypes"));
18
18
  /** @typedef {import("./ChunkGraph").ModuleId} ModuleId */
19
19
  /** @typedef {import("./Compilation").AssetInfo} AssetInfo */
20
20
  /** @typedef {import("./Compilation").PathData} PathData */
21
+ /** @typedef {import("./Compilation").PathDataChunk} PathDataChunk */
22
+ /** @typedef {import("./Compilation").PathDataModule} PathDataModule */
21
23
  /** @typedef {import("./Compiler")} Compiler */
22
24
 
23
25
  const REGEXP = /\[\\*([\w:]+)\\*\]/g;
@@ -138,13 +140,29 @@ const deprecated = (fn, message, code) => {
138
140
  );
139
141
  };
140
142
 
141
- /** @typedef {(pathData: PathData, assetInfo?: AssetInfo) => string} TemplatePathFn */
142
- /** @typedef {string | TemplatePathFn} TemplatePath */
143
+ /**
144
+ * Callback used to compute a path from contextual data. The type parameter
145
+ * narrows the `pathData` shape when the caller knows it operates in a chunk
146
+ * (`PathDataChunk`) or module (`PathDataModule`) context — defaults to the
147
+ * fully-optional `PathData` for backward compatibility.
148
+ * @template {PathData} [T=PathData]
149
+ * @typedef {(pathData: T, assetInfo?: AssetInfo) => string} TemplatePathFn
150
+ */
151
+
152
+ /**
153
+ * Either a raw template string (e.g. `"[name].[contenthash].js"`) or a
154
+ * generic `TemplatePathFn`. Method signatures that need to thread a narrowed
155
+ * `PathData` shape spell the function side out as `TemplatePathFn<T>`
156
+ * directly — `TemplatePath` itself stays a plain alias so local JSDoc
157
+ * re-imports keep a single shared identity.
158
+ * @typedef {string | TemplatePathFn} TemplatePath
159
+ */
143
160
 
144
161
  /**
145
162
  * Returns the interpolated path.
146
- * @param {TemplatePath} path the raw path
147
- * @param {PathData} data context data
163
+ * @template {PathData} [T=PathData]
164
+ * @param {string | TemplatePathFn<T>} path the raw path
165
+ * @param {T} data context data
148
166
  * @param {AssetInfo=} assetInfo extra info about the asset (will be written to)
149
167
  * @returns {string} the interpolated path
150
168
  */
@@ -9,11 +9,11 @@ const { RawSource } = require("webpack-sources");
9
9
  const ConcatenationScope = require("../ConcatenationScope");
10
10
  const Generator = require("../Generator");
11
11
  const {
12
+ ASSET_URL_TYPE,
13
+ ASSET_URL_TYPES,
12
14
  CSS_TYPE,
13
- CSS_URL_TYPE,
14
- CSS_URL_TYPES,
15
15
  HTML_TYPE,
16
- JAVASCRIPT_AND_CSS_URL_TYPES,
16
+ JAVASCRIPT_AND_ASSET_URL_TYPES,
17
17
  JAVASCRIPT_TYPE,
18
18
  JAVASCRIPT_TYPES,
19
19
  NO_TYPES
@@ -80,7 +80,7 @@ class AssetSourceGenerator extends Generator {
80
80
  }
81
81
  return new RawSource(sourceContent);
82
82
  }
83
- case CSS_URL_TYPE: {
83
+ case ASSET_URL_TYPE: {
84
84
  if (!originalSource) {
85
85
  return null;
86
86
  }
@@ -151,9 +151,9 @@ class AssetSourceGenerator extends Generator {
151
151
  sourceTypes.has(JAVASCRIPT_TYPE) &&
152
152
  (sourceTypes.has(CSS_TYPE) || sourceTypes.has(HTML_TYPE))
153
153
  ) {
154
- return JAVASCRIPT_AND_CSS_URL_TYPES;
154
+ return JAVASCRIPT_AND_ASSET_URL_TYPES;
155
155
  } else if (sourceTypes.has(CSS_TYPE) || sourceTypes.has(HTML_TYPE)) {
156
- return CSS_URL_TYPES;
156
+ return ASSET_URL_TYPES;
157
157
  }
158
158
  return JAVASCRIPT_TYPES;
159
159
  }
@@ -10,15 +10,15 @@ const { RawSource } = require("webpack-sources");
10
10
  const ConcatenationScope = require("../ConcatenationScope");
11
11
  const Generator = require("../Generator");
12
12
  const {
13
- ASSET_AND_CSS_URL_TYPES,
14
- ASSET_AND_JAVASCRIPT_AND_CSS_URL_TYPES,
13
+ ASSET_AND_ASSET_URL_TYPES,
14
+ ASSET_AND_JAVASCRIPT_AND_ASSET_URL_TYPES,
15
15
  ASSET_AND_JAVASCRIPT_TYPES,
16
16
  ASSET_TYPES,
17
+ ASSET_URL_TYPE,
18
+ ASSET_URL_TYPES,
17
19
  CSS_TYPE,
18
- CSS_URL_TYPE,
19
- CSS_URL_TYPES,
20
20
  HTML_TYPE,
21
- JAVASCRIPT_AND_CSS_URL_TYPES,
21
+ JAVASCRIPT_AND_ASSET_URL_TYPES,
22
22
  JAVASCRIPT_TYPE,
23
23
  JAVASCRIPT_TYPES,
24
24
  NO_TYPES
@@ -373,7 +373,7 @@ class AssetGenerator extends Generator {
373
373
  assetPath = JSON.stringify(path + filename);
374
374
  } else if (
375
375
  generatorOptions.publicPath !== undefined &&
376
- type === CSS_URL_TYPE
376
+ type === ASSET_URL_TYPE
377
377
  ) {
378
378
  const { path, info } = runtimeTemplate.compilation.getAssetPathWithInfo(
379
379
  generatorOptions.publicPath,
@@ -394,7 +394,7 @@ class AssetGenerator extends Generator {
394
394
  { expr: RuntimeGlobals.publicPath },
395
395
  filename
396
396
  );
397
- } else if (type === CSS_URL_TYPE) {
397
+ } else if (type === ASSET_URL_TYPE) {
398
398
  const compilation = runtimeTemplate.compilation;
399
399
  const path =
400
400
  compilation.outputOptions.publicPath === "auto"
@@ -560,7 +560,7 @@ class AssetGenerator extends Generator {
560
560
  /** @type {string} */
561
561
  let content;
562
562
 
563
- const needContent = type === JAVASCRIPT_TYPE || type === CSS_URL_TYPE;
563
+ const needContent = type === JAVASCRIPT_TYPE || type === ASSET_URL_TYPE;
564
564
  const data = getData ? getData() : undefined;
565
565
 
566
566
  if (
@@ -613,7 +613,7 @@ class AssetGenerator extends Generator {
613
613
  contentHash
614
614
  );
615
615
 
616
- if (data && (type === JAVASCRIPT_TYPE || type === CSS_URL_TYPE)) {
616
+ if (data && (type === JAVASCRIPT_TYPE || type === ASSET_URL_TYPE)) {
617
617
  data.set("url", { ...data.get("url"), [type]: assetPath });
618
618
  }
619
619
 
@@ -657,7 +657,7 @@ class AssetGenerator extends Generator {
657
657
  runtimeRequirements.add(RuntimeGlobals.module);
658
658
 
659
659
  return new RawSource(`${module.moduleArgument}.exports = ${content};`);
660
- } else if (type === CSS_URL_TYPE) {
660
+ } else if (type === ASSET_URL_TYPE) {
661
661
  return null;
662
662
  }
663
663
 
@@ -710,9 +710,9 @@ class AssetGenerator extends Generator {
710
710
  sourceTypes.has(JAVASCRIPT_TYPE) &&
711
711
  (sourceTypes.has(CSS_TYPE) || sourceTypes.has(HTML_TYPE))
712
712
  ) {
713
- return JAVASCRIPT_AND_CSS_URL_TYPES;
713
+ return JAVASCRIPT_AND_ASSET_URL_TYPES;
714
714
  } else if (sourceTypes.has(CSS_TYPE) || sourceTypes.has(HTML_TYPE)) {
715
- return CSS_URL_TYPES;
715
+ return ASSET_URL_TYPES;
716
716
  }
717
717
  return JAVASCRIPT_TYPES;
718
718
  }
@@ -725,9 +725,9 @@ class AssetGenerator extends Generator {
725
725
  sourceTypes.has(JAVASCRIPT_TYPE) &&
726
726
  (sourceTypes.has(CSS_TYPE) || sourceTypes.has(HTML_TYPE))
727
727
  ) {
728
- return ASSET_AND_JAVASCRIPT_AND_CSS_URL_TYPES;
728
+ return ASSET_AND_JAVASCRIPT_AND_ASSET_URL_TYPES;
729
729
  } else if (sourceTypes.has(CSS_TYPE) || sourceTypes.has(HTML_TYPE)) {
730
- return ASSET_AND_CSS_URL_TYPES;
730
+ return ASSET_AND_ASSET_URL_TYPES;
731
731
  }
732
732
  return ASSET_AND_JAVASCRIPT_TYPES;
733
733
  }
@@ -20,13 +20,12 @@ const memoize = require("../util/memoize");
20
20
  /** @typedef {import("../../declarations/WebpackOptions").AssetGeneratorDataUrl} AssetGeneratorDataUrl */
21
21
  /** @typedef {import("../../declarations/WebpackOptions").AssetModuleOutputPath} AssetModuleOutputPath */
22
22
  /** @typedef {import("../../declarations/WebpackOptions").RawPublicPath} RawPublicPath */
23
- /** @typedef {import("../../declarations/WebpackOptions").FilenameTemplate} FilenameTemplate */
23
+ /** @typedef {import("../../declarations/WebpackOptions").AssetModuleFilename} AssetModuleFilename */
24
24
  /** @typedef {import("../Compilation").AssetInfo} AssetInfo */
25
25
  /** @typedef {import("../Compiler")} Compiler */
26
26
  /** @typedef {import("../Module").BuildInfo} BuildInfo */
27
27
  /** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
28
28
  /** @typedef {import("../NormalModule")} NormalModule */
29
- /** @typedef {import("../NormalModule").NormalModuleCreateData} NormalModuleCreateData */
30
29
 
31
30
  /**
32
31
  * Returns definition.
@@ -98,10 +97,7 @@ class AssetModulesPlugin {
98
97
  .for(type)
99
98
  .tap(PLUGIN_NAME, (createData, _resolveData) => {
100
99
  // TODO create the module via new AssetModule with its own properties
101
- const module = new NormalModule(
102
- /** @type {NormalModuleCreateData} */
103
- (createData)
104
- );
100
+ const module = new NormalModule(createData);
105
101
  if (this.options.sideEffectFree) {
106
102
  module.factoryMeta = { sideEffectFree: true };
107
103
  }
@@ -227,7 +223,7 @@ class AssetModulesPlugin {
227
223
  }
228
224
  }
229
225
 
230
- /** @type {undefined | FilenameTemplate} */
226
+ /** @type {undefined | AssetModuleFilename} */
231
227
  let filename;
232
228
  /** @type {undefined | RawPublicPath} */
233
229
  let publicPath;