webpack 5.68.0 → 5.69.0

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

Potentially problematic release.


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

package/lib/ChunkGraph.js CHANGED
@@ -46,6 +46,7 @@ const compareModuleIterables = compareIterables(compareModulesByIdentifier);
46
46
 
47
47
  /** @typedef {(c: Chunk, chunkGraph: ChunkGraph) => boolean} ChunkFilterPredicate */
48
48
  /** @typedef {(m: Module) => boolean} ModuleFilterPredicate */
49
+ /** @typedef {[Module, Entrypoint | undefined]} EntryModuleWithChunkGroup */
49
50
 
50
51
  /**
51
52
  * @typedef {Object} ChunkSizeOptions
@@ -1180,8 +1181,6 @@ class ChunkGraph {
1180
1181
  return cgc.dependentHashModules;
1181
1182
  }
1182
1183
 
1183
- /** @typedef {[Module, Entrypoint | undefined]} EntryModuleWithChunkGroup */
1184
-
1185
1184
  /**
1186
1185
  * @param {Chunk} chunk the chunk
1187
1186
  * @returns {Iterable<EntryModuleWithChunkGroup>} iterable of modules (do not modify)
@@ -182,6 +182,7 @@ const { isSourceEqual } = require("./util/source");
182
182
 
183
183
  /**
184
184
  * @typedef {Object} ChunkHashContext
185
+ * @property {CodeGenerationResults} codeGenerationResults results of code generation
185
186
  * @property {RuntimeTemplate} runtimeTemplate the runtime template
186
187
  * @property {ModuleGraph} moduleGraph the module graph
187
188
  * @property {ChunkGraph} chunkGraph the chunk graph
@@ -4137,6 +4138,7 @@ This prevents using hashes of each other and should be avoided.`);
4137
4138
  chunk.updateHash(chunkHash, chunkGraph);
4138
4139
  this.hooks.chunkHash.call(chunk, chunkHash, {
4139
4140
  chunkGraph,
4141
+ codeGenerationResults: this.codeGenerationResults,
4140
4142
  moduleGraph: this.moduleGraph,
4141
4143
  runtimeTemplate: this.runtimeTemplate
4142
4144
  });
@@ -61,7 +61,7 @@ const makeSerializable = require("./util/makeSerializable");
61
61
 
62
62
  /**
63
63
  * @typedef {Object} ContextModuleOptionsExtras
64
- * @property {string} resource
64
+ * @property {string|string[]} resource
65
65
  * @property {string=} resourceQuery
66
66
  * @property {string=} resourceFragment
67
67
  * @property {TODO} resolveOptions
@@ -92,23 +92,36 @@ class ContextModule extends Module {
92
92
  * @param {ContextModuleOptions} options options object
93
93
  */
94
94
  constructor(resolveDependencies, options) {
95
- const parsed = parseResource(options ? options.resource : "");
96
- const resource = parsed.path;
97
- const resourceQuery = (options && options.resourceQuery) || parsed.query;
98
- const resourceFragment =
99
- (options && options.resourceFragment) || parsed.fragment;
100
-
101
- super("javascript/dynamic", resource);
95
+ if (!options || typeof options.resource === "string") {
96
+ const parsed = parseResource(
97
+ options ? /** @type {string} */ (options.resource) : ""
98
+ );
99
+ const resource = parsed.path;
100
+ const resourceQuery = (options && options.resourceQuery) || parsed.query;
101
+ const resourceFragment =
102
+ (options && options.resourceFragment) || parsed.fragment;
103
+
104
+ super("javascript/dynamic", resource);
105
+ /** @type {ContextModuleOptions} */
106
+ this.options = {
107
+ ...options,
108
+ resource,
109
+ resourceQuery,
110
+ resourceFragment
111
+ };
112
+ } else {
113
+ super("javascript/dynamic");
114
+ /** @type {ContextModuleOptions} */
115
+ this.options = {
116
+ ...options,
117
+ resource: options.resource,
118
+ resourceQuery: options.resourceQuery || "",
119
+ resourceFragment: options.resourceFragment || ""
120
+ };
121
+ }
102
122
 
103
123
  // Info from Factory
104
124
  this.resolveDependencies = resolveDependencies;
105
- /** @type {ContextModuleOptions} */
106
- this.options = {
107
- ...options,
108
- resource,
109
- resourceQuery,
110
- resourceFragment
111
- };
112
125
  if (options && options.resolveOptions !== undefined) {
113
126
  this.resolveOptions = options.resolveOptions;
114
127
  }
@@ -155,7 +168,11 @@ class ContextModule extends Module {
155
168
  }
156
169
 
157
170
  _createIdentifier() {
158
- let identifier = this.context;
171
+ let identifier =
172
+ this.context ||
173
+ (typeof this.options.resource === "string"
174
+ ? this.options.resource
175
+ : this.options.resource.join("|"));
159
176
  if (this.options.resourceQuery) {
160
177
  identifier += `|${this.options.resourceQuery}`;
161
178
  }
@@ -220,7 +237,16 @@ class ContextModule extends Module {
220
237
  * @returns {string} a user readable identifier of the module
221
238
  */
222
239
  readableIdentifier(requestShortener) {
223
- let identifier = requestShortener.shorten(this.context) + "/";
240
+ let identifier;
241
+ if (this.context) {
242
+ identifier = requestShortener.shorten(this.context) + "/";
243
+ } else if (typeof this.options.resource === "string") {
244
+ identifier = requestShortener.shorten(this.options.resource) + "/";
245
+ } else {
246
+ identifier = this.options.resource
247
+ .map(r => requestShortener.shorten(r) + "/")
248
+ .join(" ");
249
+ }
224
250
  if (this.options.resourceQuery) {
225
251
  identifier += ` ${this.options.resourceQuery}`;
226
252
  }
@@ -270,11 +296,30 @@ class ContextModule extends Module {
270
296
  * @returns {string | null} an identifier for library inclusion
271
297
  */
272
298
  libIdent(options) {
273
- let identifier = contextify(
274
- options.context,
275
- this.context,
276
- options.associatedObjectForCache
277
- );
299
+ let identifier;
300
+
301
+ if (this.context) {
302
+ identifier = contextify(
303
+ options.context,
304
+ this.context,
305
+ options.associatedObjectForCache
306
+ );
307
+ } else if (typeof this.options.resource === "string") {
308
+ identifier = contextify(
309
+ options.context,
310
+ this.options.resource,
311
+ options.associatedObjectForCache
312
+ );
313
+ } else {
314
+ const arr = [];
315
+ for (const res of this.options.resource) {
316
+ arr.push(
317
+ contextify(options.context, res, options.associatedObjectForCache)
318
+ );
319
+ }
320
+ identifier = arr.join(" ");
321
+ }
322
+
278
323
  if (this.layer) identifier = `(${this.layer})/${identifier}`;
279
324
  if (this.options.mode) {
280
325
  identifier += ` ${this.options.mode}`;
@@ -442,7 +487,11 @@ class ContextModule extends Module {
442
487
  compilation.fileSystemInfo.createSnapshot(
443
488
  startTime,
444
489
  null,
445
- [this.context],
490
+ this.context
491
+ ? [this.context]
492
+ : typeof this.options.resource === "string"
493
+ ? [this.options.resource]
494
+ : this.options.resource,
446
495
  null,
447
496
  SNAPSHOT_OPTIONS,
448
497
  (err, snapshot) => {
@@ -466,7 +515,13 @@ class ContextModule extends Module {
466
515
  missingDependencies,
467
516
  buildDependencies
468
517
  ) {
469
- contextDependencies.add(this.context);
518
+ if (this.context) {
519
+ contextDependencies.add(this.context);
520
+ } else if (typeof this.options.resource === "string") {
521
+ contextDependencies.add(this.options.resource);
522
+ } else {
523
+ for (const res of this.options.resource) contextDependencies.add(res);
524
+ }
470
525
  }
471
526
 
472
527
  /**
@@ -167,6 +167,9 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
167
167
  asyncLib.parallel(
168
168
  [
169
169
  callback => {
170
+ const results = [];
171
+ const yield_ = obj => results.push(obj);
172
+
170
173
  contextResolver.resolve(
171
174
  {},
172
175
  context,
@@ -174,11 +177,12 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
174
177
  {
175
178
  fileDependencies,
176
179
  missingDependencies,
177
- contextDependencies
180
+ contextDependencies,
181
+ yield: yield_
178
182
  },
179
- (err, result) => {
183
+ err => {
180
184
  if (err) return callback(err);
181
- callback(null, result);
185
+ callback(null, results);
182
186
  }
183
187
  );
184
188
  },
@@ -213,15 +217,20 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
213
217
  contextDependencies
214
218
  });
215
219
  }
216
-
220
+ const [contextResult, loaderResult] = result;
217
221
  this.hooks.afterResolve.callAsync(
218
222
  {
219
223
  addon:
220
224
  loadersPrefix +
221
- result[1].join("!") +
222
- (result[1].length > 0 ? "!" : ""),
223
- resource: result[0],
225
+ loaderResult.join("!") +
226
+ (loaderResult.length > 0 ? "!" : ""),
227
+ resource:
228
+ contextResult.length > 1
229
+ ? contextResult.map(r => r.path)
230
+ : contextResult[0].path,
224
231
  resolveDependencies: this.resolveDependencies.bind(this),
232
+ resourceQuery: contextResult[0].query,
233
+ resourceFragment: contextResult[0].fragment,
225
234
  ...beforeResolveResult
226
235
  },
227
236
  (err, result) => {
@@ -278,26 +287,28 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
278
287
  } = options;
279
288
  if (!regExp || !resource) return callback(null, []);
280
289
 
281
- const addDirectoryChecked = (directory, visited, callback) => {
290
+ let severalContexts = false;
291
+ const addDirectoryChecked = (ctx, directory, visited, callback) => {
282
292
  fs.realpath(directory, (err, realPath) => {
283
293
  if (err) return callback(err);
284
294
  if (visited.has(realPath)) return callback(null, []);
285
295
  let recursionStack;
286
296
  addDirectory(
297
+ ctx,
287
298
  directory,
288
- (dir, callback) => {
299
+ (_, dir, callback) => {
289
300
  if (recursionStack === undefined) {
290
301
  recursionStack = new Set(visited);
291
302
  recursionStack.add(realPath);
292
303
  }
293
- addDirectoryChecked(dir, recursionStack, callback);
304
+ addDirectoryChecked(ctx, dir, recursionStack, callback);
294
305
  },
295
306
  callback
296
307
  );
297
308
  });
298
309
  };
299
310
 
300
- const addDirectory = (directory, addSubDirectory, callback) => {
311
+ const addDirectory = (ctx, directory, addSubDirectory, callback) => {
301
312
  fs.readdir(directory, (err, files) => {
302
313
  if (err) return callback(err);
303
314
  const processedFiles = cmf.hooks.contextModuleFiles.call(
@@ -324,16 +335,15 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
324
335
 
325
336
  if (stat.isDirectory()) {
326
337
  if (!recursive) return callback();
327
- addSubDirectory(subResource, callback);
338
+ addSubDirectory(ctx, subResource, callback);
328
339
  } else if (
329
340
  stat.isFile() &&
330
341
  (!include || subResource.match(include))
331
342
  ) {
332
343
  const obj = {
333
- context: resource,
344
+ context: ctx,
334
345
  request:
335
- "." +
336
- subResource.substr(resource.length).replace(/\\/g, "/")
346
+ "." + subResource.substr(ctx.length).replace(/\\/g, "/")
337
347
  };
338
348
 
339
349
  this.hooks.alternativeRequests.callAsync(
@@ -344,8 +354,11 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
344
354
  alternatives = alternatives
345
355
  .filter(obj => regExp.test(obj.request))
346
356
  .map(obj => {
357
+ const request = severalContexts
358
+ ? join(fs, obj.context, obj.request)
359
+ : obj.request;
347
360
  const dep = new ContextElementDependency(
348
- obj.request + resourceQuery + resourceFragment,
361
+ request + resourceQuery + resourceFragment,
349
362
  obj.request,
350
363
  typePrefix,
351
364
  category,
@@ -382,12 +395,38 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
382
395
  });
383
396
  };
384
397
 
385
- if (typeof fs.realpath === "function") {
386
- addDirectoryChecked(resource, new Set(), callback);
398
+ const addSubDirectory = (ctx, dir, callback) =>
399
+ addDirectory(ctx, dir, addSubDirectory, callback);
400
+
401
+ const visitResource = (resource, callback) => {
402
+ if (typeof fs.realpath === "function") {
403
+ addDirectoryChecked(resource, resource, new Set(), callback);
404
+ } else {
405
+ addDirectory(resource, resource, addSubDirectory, callback);
406
+ }
407
+ };
408
+
409
+ if (typeof resource === "string") {
410
+ visitResource(resource, callback);
387
411
  } else {
388
- const addSubDirectory = (dir, callback) =>
389
- addDirectory(dir, addSubDirectory, callback);
390
- addDirectory(resource, addSubDirectory, callback);
412
+ severalContexts = true;
413
+ asyncLib.map(resource, visitResource, (err, result) => {
414
+ if (err) return callback(err);
415
+
416
+ // result dependencies should have unique userRequest
417
+ // ordered by resolve result
418
+ const temp = new Set();
419
+ const res = [];
420
+ for (let i = 0; i < result.length; i++) {
421
+ const inner = result[i];
422
+ for (const el of inner) {
423
+ if (temp.has(el.userRequest)) continue;
424
+ res.push(el);
425
+ temp.add(el.userRequest);
426
+ }
427
+ }
428
+ callback(null, res);
429
+ });
391
430
  }
392
431
  }
393
432
  };
@@ -291,15 +291,15 @@ class ExportsInfo {
291
291
  }
292
292
  }
293
293
  for (const exportInfo of this._exports.values()) {
294
+ if (!canMangle && exportInfo.canMangleProvide !== false) {
295
+ exportInfo.canMangleProvide = false;
296
+ changed = true;
297
+ }
294
298
  if (excludeExports && excludeExports.has(exportInfo.name)) continue;
295
299
  if (exportInfo.provided !== true && exportInfo.provided !== null) {
296
300
  exportInfo.provided = null;
297
301
  changed = true;
298
302
  }
299
- if (!canMangle && exportInfo.canMangleProvide !== false) {
300
- exportInfo.canMangleProvide = false;
301
- changed = true;
302
- }
303
303
  if (targetKey) {
304
304
  exportInfo.setTarget(targetKey, targetModule, [exportInfo.name], -1);
305
305
  }
@@ -28,7 +28,10 @@ const LazySet = require("./util/LazySet");
28
28
  const { getScheme } = require("./util/URLAbsoluteSpecifier");
29
29
  const { cachedCleverMerge, cachedSetProperty } = require("./util/cleverMerge");
30
30
  const { join } = require("./util/fs");
31
- const { parseResource } = require("./util/identifier");
31
+ const {
32
+ parseResource,
33
+ parseResourceWithoutFragment
34
+ } = require("./util/identifier");
32
35
 
33
36
  /** @typedef {import("../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */
34
37
  /** @typedef {import("./Generator")} Generator */
@@ -66,6 +69,11 @@ const { parseResource } = require("./util/identifier");
66
69
 
67
70
  /** @typedef {ResourceData & { data: Record<string, any> }} ResourceDataWithData */
68
71
 
72
+ /** @typedef {Object} ParsedLoaderRequest
73
+ * @property {string} loader loader
74
+ * @property {string|undefined} options options
75
+ */
76
+
69
77
  const EMPTY_RESOLVE_OPTIONS = {};
70
78
  const EMPTY_PARSER_OPTIONS = {};
71
79
  const EMPTY_GENERATOR_OPTIONS = {};
@@ -97,27 +105,6 @@ const stringifyLoadersAndResource = (loaders, resource) => {
97
105
  return str + resource;
98
106
  };
99
107
 
100
- /**
101
- * @param {string} resultString resultString
102
- * @returns {{loader: string, options: string|undefined}} parsed loader request
103
- */
104
- const identToLoaderRequest = resultString => {
105
- const idx = resultString.indexOf("?");
106
- if (idx >= 0) {
107
- const loader = resultString.substr(0, idx);
108
- const options = resultString.substr(idx + 1);
109
- return {
110
- loader,
111
- options
112
- };
113
- } else {
114
- return {
115
- loader: resultString,
116
- options: undefined
117
- };
118
- }
119
- };
120
-
121
108
  const needCalls = (times, callback) => {
122
109
  return err => {
123
110
  if (--times === 0) {
@@ -264,6 +251,9 @@ class NormalModuleFactory extends ModuleFactory {
264
251
  const cacheParseResource = parseResource.bindCache(
265
252
  associatedObjectForCache
266
253
  );
254
+ const cachedParseResourceWithoutFragment =
255
+ parseResourceWithoutFragment.bindCache(associatedObjectForCache);
256
+ this._parseResourceWithoutFragment = cachedParseResourceWithoutFragment;
267
257
 
268
258
  this.hooks.factorize.tapAsync(
269
259
  {
@@ -351,7 +341,7 @@ class NormalModuleFactory extends ModuleFactory {
351
341
  let matchResourceData = undefined;
352
342
  /** @type {string} */
353
343
  let unresolvedResource;
354
- /** @type {{loader: string, options: string|undefined}[]} */
344
+ /** @type {ParsedLoaderRequest[]} */
355
345
  let elements;
356
346
  let noPreAutoLoaders = false;
357
347
  let noAutoLoaders = false;
@@ -405,7 +395,13 @@ class NormalModuleFactory extends ModuleFactory {
405
395
  )
406
396
  .split(/!+/);
407
397
  unresolvedResource = rawElements.pop();
408
- elements = rawElements.map(identToLoaderRequest);
398
+ elements = rawElements.map(el => {
399
+ const { path, query } = cachedParseResourceWithoutFragment(el);
400
+ return {
401
+ loader: path,
402
+ options: query ? query.slice(1) : undefined
403
+ };
404
+ });
409
405
  scheme = getScheme(unresolvedResource);
410
406
  } else {
411
407
  unresolvedResource = requestWithoutMatchResource;
@@ -1017,12 +1013,14 @@ If changing the source code is not an option there is also a resolve options cal
1017
1013
  }
1018
1014
  if (err) return callback(err);
1019
1015
 
1020
- const parsedResult = identToLoaderRequest(result);
1016
+ const parsedResult = this._parseResourceWithoutFragment(result);
1021
1017
  const resolved = {
1022
- loader: parsedResult.loader,
1018
+ loader: parsedResult.path,
1023
1019
  options:
1024
1020
  item.options === undefined
1025
- ? parsedResult.options
1021
+ ? parsedResult.query
1022
+ ? parsedResult.query.slice(1)
1023
+ : undefined
1026
1024
  : item.options,
1027
1025
  ident: item.options === undefined ? undefined : item.ident
1028
1026
  };
@@ -96,7 +96,7 @@ const createDefaultHandler = (profile, logger) => {
96
96
  /**
97
97
  * @callback ReportProgress
98
98
  * @param {number} p
99
- * @param {...string[]} [args]
99
+ * @param {...string} [args]
100
100
  * @returns {void}
101
101
  */
102
102
 
@@ -5,6 +5,7 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const mime = require("mime-types");
8
9
  const { basename, extname } = require("path");
9
10
  const util = require("util");
10
11
  const Chunk = require("./Chunk");
@@ -117,29 +118,53 @@ const replacePathVariables = (path, data, assetInfo) => {
117
118
  // [name] - file
118
119
  // [ext] - .js
119
120
  if (typeof data.filename === "string") {
120
- const { path: file, query, fragment } = parseResource(data.filename);
121
-
122
- const ext = extname(file);
123
- const base = basename(file);
124
- const name = base.slice(0, base.length - ext.length);
125
- const path = file.slice(0, file.length - base.length);
126
-
127
- replacements.set("file", replacer(file));
128
- replacements.set("query", replacer(query, true));
129
- replacements.set("fragment", replacer(fragment, true));
130
- replacements.set("path", replacer(path, true));
131
- replacements.set("base", replacer(base));
132
- replacements.set("name", replacer(name));
133
- replacements.set("ext", replacer(ext, true));
134
- // Legacy
135
- replacements.set(
136
- "filebase",
137
- deprecated(
138
- replacer(base),
139
- "[filebase] is now [base]",
140
- "DEP_WEBPACK_TEMPLATE_PATH_PLUGIN_REPLACE_PATH_VARIABLES_FILENAME"
141
- )
142
- );
121
+ // check that filename is data uri
122
+ let match = data.filename.match(/^data:([^;,]+)/);
123
+ if (match) {
124
+ const ext = mime.extension(match[1]);
125
+ const emptyReplacer = replacer("", true);
126
+
127
+ replacements.set("file", emptyReplacer);
128
+ replacements.set("query", emptyReplacer);
129
+ replacements.set("fragment", emptyReplacer);
130
+ replacements.set("path", emptyReplacer);
131
+ replacements.set("base", emptyReplacer);
132
+ replacements.set("name", emptyReplacer);
133
+ replacements.set("ext", replacer(ext ? `.${ext}` : "", true));
134
+ // Legacy
135
+ replacements.set(
136
+ "filebase",
137
+ deprecated(
138
+ emptyReplacer,
139
+ "[filebase] is now [base]",
140
+ "DEP_WEBPACK_TEMPLATE_PATH_PLUGIN_REPLACE_PATH_VARIABLES_FILENAME"
141
+ )
142
+ );
143
+ } else {
144
+ const { path: file, query, fragment } = parseResource(data.filename);
145
+
146
+ const ext = extname(file);
147
+ const base = basename(file);
148
+ const name = base.slice(0, base.length - ext.length);
149
+ const path = file.slice(0, file.length - base.length);
150
+
151
+ replacements.set("file", replacer(file));
152
+ replacements.set("query", replacer(query, true));
153
+ replacements.set("fragment", replacer(fragment, true));
154
+ replacements.set("path", replacer(path, true));
155
+ replacements.set("base", replacer(base));
156
+ replacements.set("name", replacer(name));
157
+ replacements.set("ext", replacer(ext, true));
158
+ // Legacy
159
+ replacements.set(
160
+ "filebase",
161
+ deprecated(
162
+ replacer(base),
163
+ "[filebase] is now [base]",
164
+ "DEP_WEBPACK_TEMPLATE_PATH_PLUGIN_REPLACE_PATH_VARIABLES_FILENAME"
165
+ )
166
+ );
167
+ }
143
168
  }
144
169
 
145
170
  // Compilation context
@@ -12,6 +12,7 @@ const Generator = require("../Generator");
12
12
  const RuntimeGlobals = require("../RuntimeGlobals");
13
13
  const createHash = require("../util/createHash");
14
14
  const { makePathsRelative } = require("../util/identifier");
15
+ const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
15
16
 
16
17
  /** @typedef {import("webpack-sources").Source} Source */
17
18
  /** @typedef {import("../../declarations/WebpackOptions").AssetGeneratorOptions} AssetGeneratorOptions */
@@ -232,8 +233,8 @@ class AssetGenerator extends Generator {
232
233
  const fullHash = /** @type {string} */ (
233
234
  hash.digest(runtimeTemplate.outputOptions.hashDigest)
234
235
  );
235
- const contentHash = fullHash.slice(
236
- 0,
236
+ const contentHash = nonNumericOnlyHash(
237
+ fullHash,
237
238
  runtimeTemplate.outputOptions.hashDigestLength
238
239
  );
239
240
  module.buildInfo.fullContentHash = fullHash;
@@ -905,7 +905,7 @@ const visitModules = (
905
905
  const module = it.value;
906
906
  if (
907
907
  availableModules.has(module) ||
908
- availableModules.plus.has(m)
908
+ availableModules.plus.has(module)
909
909
  ) {
910
910
  cachedMinAvailableModules.add(module);
911
911
  }