webpack 5.51.2 → 5.54.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.

Files changed (62) hide show
  1. package/lib/AsyncDependenciesBlock.js +9 -2
  2. package/lib/CacheFacade.js +10 -3
  3. package/lib/ChunkGraph.js +19 -8
  4. package/lib/CodeGenerationResults.js +7 -2
  5. package/lib/Compilation.js +207 -16
  6. package/lib/Compiler.js +9 -1
  7. package/lib/DependencyTemplates.js +8 -2
  8. package/lib/EvalDevToolModulePlugin.js +2 -1
  9. package/lib/EvalSourceMapDevToolPlugin.js +2 -1
  10. package/lib/ExternalModule.js +36 -18
  11. package/lib/FileSystemInfo.js +101 -170
  12. package/lib/FlagDependencyExportsPlugin.js +43 -16
  13. package/lib/InitFragment.js +23 -0
  14. package/lib/JavascriptMetaInfoPlugin.js +6 -1
  15. package/lib/MemCache.js +45 -0
  16. package/lib/ModuleFilenameHelpers.js +21 -7
  17. package/lib/NodeStuffInWebError.js +34 -0
  18. package/lib/NodeStuffPlugin.js +59 -16
  19. package/lib/NormalModuleFactory.js +7 -4
  20. package/lib/SourceMapDevToolPlugin.js +7 -3
  21. package/lib/WebpackOptionsApply.js +20 -4
  22. package/lib/cache/PackFileCacheStrategy.js +183 -53
  23. package/lib/cache/getLazyHashedEtag.js +35 -8
  24. package/lib/config/defaults.js +32 -13
  25. package/lib/dependencies/CachedConstDependency.js +4 -3
  26. package/lib/dependencies/ConstDependency.js +12 -4
  27. package/lib/dependencies/JsonExportsDependency.js +7 -1
  28. package/lib/dependencies/LoaderPlugin.js +94 -98
  29. package/lib/dependencies/ModuleDecoratorDependency.js +5 -2
  30. package/lib/dependencies/ProvidedDependency.js +6 -2
  31. package/lib/dependencies/PureExpressionDependency.js +5 -1
  32. package/lib/dependencies/RuntimeRequirementsDependency.js +5 -1
  33. package/lib/ids/IdHelpers.js +21 -8
  34. package/lib/ids/NamedChunkIdsPlugin.js +3 -0
  35. package/lib/ids/NamedModuleIdsPlugin.js +3 -1
  36. package/lib/index.js +6 -0
  37. package/lib/javascript/BasicEvaluatedExpression.js +3 -0
  38. package/lib/javascript/JavascriptParser.js +22 -4
  39. package/lib/javascript/JavascriptParserHelpers.js +0 -2
  40. package/lib/node/NodeTargetPlugin.js +1 -0
  41. package/lib/optimize/ConcatenatedModule.js +25 -4
  42. package/lib/optimize/InnerGraph.js +22 -2
  43. package/lib/optimize/MangleExportsPlugin.js +21 -4
  44. package/lib/optimize/ModuleConcatenationPlugin.js +2 -1
  45. package/lib/runtime/RelativeUrlRuntimeModule.js +1 -1
  46. package/lib/schemes/HttpUriPlugin.js +1 -2
  47. package/lib/serialization/BinaryMiddleware.js +11 -2
  48. package/lib/serialization/FileMiddleware.js +24 -7
  49. package/lib/serialization/ObjectMiddleware.js +23 -12
  50. package/lib/util/createHash.js +10 -0
  51. package/lib/util/hash/BatchedHash.js +65 -0
  52. package/lib/util/hash/xxhash64.js +154 -0
  53. package/lib/util/internalSerializables.js +2 -0
  54. package/lib/util/serialization.js +10 -6
  55. package/package.json +13 -9
  56. package/schemas/WebpackOptions.check.js +1 -1
  57. package/schemas/WebpackOptions.json +17 -5
  58. package/schemas/plugins/HashedModuleIdsPlugin.check.js +1 -1
  59. package/schemas/plugins/HashedModuleIdsPlugin.json +20 -2
  60. package/schemas/plugins/IgnorePlugin.check.js +1 -1
  61. package/schemas/plugins/IgnorePlugin.json +4 -2
  62. package/types.d.ts +166 -17
@@ -35,6 +35,7 @@ class AsyncDependenciesBlock extends DependenciesBlock {
35
35
  this.request = request;
36
36
  /** @type {DependenciesBlock} */
37
37
  this.parent = undefined;
38
+ this._stringifiedGroupOptions = undefined;
38
39
  }
39
40
 
40
41
  /**
@@ -49,7 +50,10 @@ class AsyncDependenciesBlock extends DependenciesBlock {
49
50
  * @returns {void}
50
51
  */
51
52
  set chunkName(value) {
52
- this.groupOptions.name = value;
53
+ if (this.groupOptions.name !== value) {
54
+ this.groupOptions.name = value;
55
+ this._stringifiedGroupOptions = undefined;
56
+ }
53
57
  }
54
58
 
55
59
  /**
@@ -59,7 +63,10 @@ class AsyncDependenciesBlock extends DependenciesBlock {
59
63
  */
60
64
  updateHash(hash, context) {
61
65
  const { chunkGraph } = context;
62
- hash.update(JSON.stringify(this.groupOptions));
66
+ if (this._stringifiedGroupOptions === undefined) {
67
+ this._stringifiedGroupOptions = JSON.stringify(this.groupOptions);
68
+ }
69
+ hash.update(this._stringifiedGroupOptions);
63
70
  const chunkGroup = chunkGraph.getBlockChunkGroup(this);
64
71
  hash.update(chunkGroup ? chunkGroup.id : "");
65
72
  super.updateHash(hash, context);
@@ -13,6 +13,7 @@ const mergeEtags = require("./cache/mergeEtags");
13
13
  /** @typedef {import("./Cache").Etag} Etag */
14
14
  /** @typedef {import("./WebpackError")} WebpackError */
15
15
  /** @typedef {import("./cache/getLazyHashedEtag").HashableObject} HashableObject */
16
+ /** @typedef {typeof import("./util/Hash")} HashConstructor */
16
17
 
17
18
  /**
18
19
  * @template T
@@ -198,10 +199,12 @@ class CacheFacade {
198
199
  /**
199
200
  * @param {Cache} cache the root cache
200
201
  * @param {string} name the child cache name
202
+ * @param {string | HashConstructor} hashFunction the hash function to use
201
203
  */
202
- constructor(cache, name) {
204
+ constructor(cache, name, hashFunction) {
203
205
  this._cache = cache;
204
206
  this._name = name;
207
+ this._hashFunction = hashFunction;
205
208
  }
206
209
 
207
210
  /**
@@ -209,7 +212,11 @@ class CacheFacade {
209
212
  * @returns {CacheFacade} child cache
210
213
  */
211
214
  getChildCache(name) {
212
- return new CacheFacade(this._cache, `${this._name}|${name}`);
215
+ return new CacheFacade(
216
+ this._cache,
217
+ `${this._name}|${name}`,
218
+ this._hashFunction
219
+ );
213
220
  }
214
221
 
215
222
  /**
@@ -230,7 +237,7 @@ class CacheFacade {
230
237
  * @returns {Etag} an etag that is lazy hashed
231
238
  */
232
239
  getLazyHashedEtag(obj) {
233
- return getLazyHashedEtag(obj);
240
+ return getLazyHashedEtag(obj, this._hashFunction);
234
241
  }
235
242
 
236
243
  /**
package/lib/ChunkGraph.js CHANGED
@@ -34,6 +34,7 @@ const {
34
34
  /** @typedef {import("./Module")} Module */
35
35
  /** @typedef {import("./ModuleGraph")} ModuleGraph */
36
36
  /** @typedef {import("./RuntimeModule")} RuntimeModule */
37
+ /** @typedef {typeof import("./util/Hash")} Hash */
37
38
  /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
38
39
 
39
40
  /** @type {ReadonlySet<string>} */
@@ -217,8 +218,9 @@ class ChunkGraphChunk {
217
218
  class ChunkGraph {
218
219
  /**
219
220
  * @param {ModuleGraph} moduleGraph the module graph
221
+ * @param {string | Hash} hashFunction the hash function to use
220
222
  */
221
- constructor(moduleGraph) {
223
+ constructor(moduleGraph, hashFunction = "md4") {
222
224
  /** @private @type {WeakMap<Module, ChunkGraphModule>} */
223
225
  this._modules = new WeakMap();
224
226
  /** @private @type {WeakMap<Chunk, ChunkGraphChunk>} */
@@ -230,6 +232,8 @@ class ChunkGraph {
230
232
  /** @type {ModuleGraph} */
231
233
  this.moduleGraph = moduleGraph;
232
234
 
235
+ this._hashFunction = hashFunction;
236
+
233
237
  this._getGraphRoots = this._getGraphRoots.bind(this);
234
238
 
235
239
  // Caching
@@ -1372,22 +1376,29 @@ Caller might not support runtime-dependent code generation (opt-out via optimiza
1372
1376
  /**
1373
1377
  * @param {Module} module the module
1374
1378
  * @param {RuntimeSpec} runtime the runtime
1375
- * @param {Set<string>} items runtime requirements to be added (ownership of this Set is given to ChunkGraph)
1379
+ * @param {Set<string>} items runtime requirements to be added (ownership of this Set is given to ChunkGraph when transferOwnership not false)
1380
+ * @param {boolean} transferOwnership true: transfer ownership of the items object, false: items is immutable and shared and won't be modified
1376
1381
  * @returns {void}
1377
1382
  */
1378
- addModuleRuntimeRequirements(module, runtime, items) {
1383
+ addModuleRuntimeRequirements(
1384
+ module,
1385
+ runtime,
1386
+ items,
1387
+ transferOwnership = true
1388
+ ) {
1379
1389
  const cgm = this._getChunkGraphModule(module);
1380
1390
  const runtimeRequirementsMap = cgm.runtimeRequirements;
1381
1391
  if (runtimeRequirementsMap === undefined) {
1382
1392
  const map = new RuntimeSpecMap();
1383
- map.set(runtime, items);
1393
+ // TODO avoid cloning item and track ownership instead
1394
+ map.set(runtime, transferOwnership ? items : new Set(items));
1384
1395
  cgm.runtimeRequirements = map;
1385
1396
  return;
1386
1397
  }
1387
1398
  runtimeRequirementsMap.update(runtime, runtimeRequirements => {
1388
1399
  if (runtimeRequirements === undefined) {
1389
- return items;
1390
- } else if (runtimeRequirements.size >= items.size) {
1400
+ return transferOwnership ? items : new Set(items);
1401
+ } else if (!transferOwnership || runtimeRequirements.size >= items.size) {
1391
1402
  for (const item of items) runtimeRequirements.add(item);
1392
1403
  return runtimeRequirements;
1393
1404
  } else {
@@ -1487,7 +1498,7 @@ Caller might not support runtime-dependent code generation (opt-out via optimiza
1487
1498
  cgm.graphHashes = new RuntimeSpecMap();
1488
1499
  }
1489
1500
  const graphHash = cgm.graphHashes.provide(runtime, () => {
1490
- const hash = createHash("md4");
1501
+ const hash = createHash(this._hashFunction);
1491
1502
  hash.update(`${cgm.id}`);
1492
1503
  hash.update(`${this.moduleGraph.isAsync(module)}`);
1493
1504
  this.moduleGraph.getExportsInfo(module).updateHash(hash, runtime);
@@ -1575,7 +1586,7 @@ Caller might not support runtime-dependent code generation (opt-out via optimiza
1575
1586
  connectedModules.size > 1
1576
1587
  ? Array.from(connectedModules).sort(([a], [b]) => (a < b ? -1 : 1))
1577
1588
  : connectedModules;
1578
- const hash = createHash("md4");
1589
+ const hash = createHash(this._hashFunction);
1579
1590
  const addModuleToHash = module => {
1580
1591
  hash.update(
1581
1592
  this._getModuleGraphHashBigInt(
@@ -13,12 +13,17 @@ const { runtimeToString, RuntimeSpecMap } = require("./util/runtime");
13
13
  /** @typedef {import("webpack-sources").Source} Source */
14
14
  /** @typedef {import("./Module")} Module */
15
15
  /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
16
+ /** @typedef {typeof import("./util/Hash")} Hash */
16
17
  /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
17
18
 
18
19
  class CodeGenerationResults {
19
- constructor() {
20
+ /**
21
+ * @param {string | Hash} hashFunction the hash function to use
22
+ */
23
+ constructor(hashFunction = "md4") {
20
24
  /** @type {Map<Module, RuntimeSpecMap<CodeGenerationResult>>} */
21
25
  this.map = new Map();
26
+ this._hashFunction = hashFunction;
22
27
  }
23
28
 
24
29
  /**
@@ -124,7 +129,7 @@ Caller might not support runtime-dependent code generation (opt-out via optimiza
124
129
  getHash(module, runtime) {
125
130
  const info = this.get(module, runtime);
126
131
  if (info.hash !== undefined) return info.hash;
127
- const hash = createHash("md4");
132
+ const hash = createHash(this._hashFunction);
128
133
  for (const [type, source] of info.sources) {
129
134
  hash.update(type);
130
135
  source.updateHash(hash);
@@ -38,6 +38,7 @@ const {
38
38
  tryRunOrWebpackError
39
39
  } = require("./HookWebpackError");
40
40
  const MainTemplate = require("./MainTemplate");
41
+ const MemCache = require("./MemCache");
41
42
  const Module = require("./Module");
42
43
  const ModuleDependencyError = require("./ModuleDependencyError");
43
44
  const ModuleDependencyWarning = require("./ModuleDependencyWarning");
@@ -76,7 +77,7 @@ const {
76
77
  createFakeHook
77
78
  } = require("./util/deprecation");
78
79
  const processAsyncTree = require("./util/processAsyncTree");
79
- const { getRuntimeKey } = require("./util/runtime");
80
+ const { getRuntimeKey, RuntimeSpecMap } = require("./util/runtime");
80
81
  const { isSourceEqual } = require("./util/source");
81
82
 
82
83
  /** @template T @typedef {import("tapable").AsArray<T>} AsArray<T> */
@@ -852,7 +853,8 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
852
853
  this.fileSystemInfo = new FileSystemInfo(this.inputFileSystem, {
853
854
  managedPaths: compiler.managedPaths,
854
855
  immutablePaths: compiler.immutablePaths,
855
- logger: this.getLogger("webpack.FileSystemInfo")
856
+ logger: this.getLogger("webpack.FileSystemInfo"),
857
+ hashFunction: compiler.options.output.hashFunction
856
858
  });
857
859
  if (compiler.fileTimestamps) {
858
860
  this.fileSystemInfo.addFileTimestamps(compiler.fileTimestamps, true);
@@ -891,6 +893,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
891
893
  };
892
894
  defineRemovedModuleTemplates(this.moduleTemplates);
893
895
 
896
+ /** @type {MemCache | undefined} */
897
+ this.memCache = undefined;
898
+ /** @type {WeakMap<Module, MemCache> | undefined} */
899
+ this.moduleMemCaches = undefined;
894
900
  this.moduleGraph = new ModuleGraph();
895
901
  /** @type {ChunkGraph} */
896
902
  this.chunkGraph = undefined;
@@ -2011,6 +2017,79 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2011
2017
  });
2012
2018
  }
2013
2019
 
2020
+ _computeAffectedModules(modules) {
2021
+ const moduleMemCacheCache = this.compiler.moduleMemCaches;
2022
+ if (!moduleMemCacheCache) return;
2023
+ if (!this.moduleMemCaches) this.moduleMemCaches = new WeakMap();
2024
+ if (!this.memCache) this.memCache = new MemCache();
2025
+ const { moduleGraph, memCache, moduleMemCaches } = this;
2026
+ const affectedModules = new Set();
2027
+ const infectedModules = new Set();
2028
+ let statNew = 0;
2029
+ let statChanged = 0;
2030
+ let statUnchanged = 0;
2031
+ let statWithoutHash = 0;
2032
+ for (const module of modules) {
2033
+ const hash = module.buildInfo && module.buildInfo.hash;
2034
+ if (typeof hash === "string") {
2035
+ const cachedMemCache = moduleMemCacheCache.get(module);
2036
+ if (cachedMemCache === undefined) {
2037
+ // create a new entry
2038
+ moduleMemCacheCache.set(module, {
2039
+ hash: hash,
2040
+ memCache
2041
+ });
2042
+ moduleMemCaches.set(module, memCache);
2043
+ affectedModules.add(module);
2044
+ statNew++;
2045
+ } else if (cachedMemCache.hash === hash) {
2046
+ // keep the old mem cache
2047
+ moduleMemCaches.set(module, cachedMemCache.memCache);
2048
+ statUnchanged++;
2049
+ } else {
2050
+ // use a new one
2051
+ moduleMemCaches.set(module, memCache);
2052
+ affectedModules.add(module);
2053
+ cachedMemCache.hash = hash;
2054
+ cachedMemCache.memCache = memCache;
2055
+ statChanged++;
2056
+ }
2057
+ } else {
2058
+ infectedModules.add(module);
2059
+ statWithoutHash++;
2060
+ }
2061
+ }
2062
+ for (const module of infectedModules) {
2063
+ for (const referencingModule of moduleGraph
2064
+ .getIncomingConnectionsByOriginModule(module)
2065
+ .keys()) {
2066
+ if (infectedModules.has(referencingModule)) continue;
2067
+ infectedModules.add(referencingModule);
2068
+ }
2069
+ }
2070
+ for (const module of affectedModules) {
2071
+ for (const referencingModule of moduleGraph
2072
+ .getIncomingConnectionsByOriginModule(module)
2073
+ .keys()) {
2074
+ if (!referencingModule) continue;
2075
+ if (infectedModules.has(referencingModule)) continue;
2076
+ if (affectedModules.has(referencingModule)) continue;
2077
+ affectedModules.add(referencingModule);
2078
+ moduleMemCaches.set(referencingModule, memCache);
2079
+ }
2080
+ }
2081
+ this.logger.log(
2082
+ `${Math.round(
2083
+ (100 * (affectedModules.size + infectedModules.size)) /
2084
+ this.modules.size
2085
+ )}% (${affectedModules.size} affected + ${
2086
+ infectedModules.size
2087
+ } infected of ${
2088
+ this.modules.size
2089
+ }) modules flagged as affected (${statNew} new modules, ${statChanged} changed, ${statUnchanged} unchanged, ${statWithoutHash} without hash)`
2090
+ );
2091
+ }
2092
+
2014
2093
  finish(callback) {
2015
2094
  this.factorizeQueue.clear();
2016
2095
  if (this.profile) {
@@ -2191,17 +2270,29 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2191
2270
  );
2192
2271
  this.logger.timeEnd("finish module profiles");
2193
2272
  }
2273
+ this.logger.time("compute affected modules");
2274
+ this._computeAffectedModules(this.modules);
2275
+ this.logger.timeEnd("compute affected modules");
2194
2276
  this.logger.time("finish modules");
2195
- const { modules } = this;
2277
+ const { modules, moduleMemCaches } = this;
2196
2278
  this.hooks.finishModules.callAsync(modules, err => {
2197
2279
  this.logger.timeEnd("finish modules");
2198
2280
  if (err) return callback(err);
2199
2281
 
2200
2282
  // extract warnings and errors from modules
2201
- this.logger.time("report dependency errors and warnings");
2202
2283
  this.moduleGraph.freeze();
2284
+ // TODO keep a cacheToken (= {}) for each module in the graph
2285
+ // create a new one per compilation and flag all updated files
2286
+ // and parents with it
2287
+ this.logger.time("report dependency errors and warnings");
2203
2288
  for (const module of modules) {
2204
- this.reportDependencyErrorsAndWarnings(module, [module]);
2289
+ // TODO only run for modules with changed cacheToken
2290
+ // global WeakMap<CacheToken, WeakSet<Module>> to keep modules without errors/warnings
2291
+ const memCache = moduleMemCaches && moduleMemCaches.get(module);
2292
+ if (memCache && memCache.get(module, "noWarningsOrErrors")) continue;
2293
+ let hasProblems = this.reportDependencyErrorsAndWarnings(module, [
2294
+ module
2295
+ ]);
2205
2296
  const errors = module.getErrors();
2206
2297
  if (errors !== undefined) {
2207
2298
  for (const error of errors) {
@@ -2209,6 +2300,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2209
2300
  error.module = module;
2210
2301
  }
2211
2302
  this.errors.push(error);
2303
+ hasProblems = true;
2212
2304
  }
2213
2305
  }
2214
2306
  const warnings = module.getWarnings();
@@ -2218,8 +2310,11 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2218
2310
  warning.module = module;
2219
2311
  }
2220
2312
  this.warnings.push(warning);
2313
+ hasProblems = true;
2221
2314
  }
2222
2315
  }
2316
+ if (!hasProblems && memCache)
2317
+ memCache.set(module, "noWarningsOrErrors", true);
2223
2318
  }
2224
2319
  this.moduleGraph.unfreeze();
2225
2320
  this.logger.timeEnd("report dependency errors and warnings");
@@ -2255,7 +2350,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2255
2350
  this.addModuleQueue.clear();
2256
2351
  return callback(err);
2257
2352
  };
2258
- const chunkGraph = new ChunkGraph(this.moduleGraph);
2353
+ const chunkGraph = new ChunkGraph(
2354
+ this.moduleGraph,
2355
+ this.outputOptions.hashFunction
2356
+ );
2259
2357
  this.chunkGraph = chunkGraph;
2260
2358
 
2261
2359
  for (const module of this.modules) {
@@ -2573,9 +2671,10 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2573
2671
  /**
2574
2672
  * @param {Module} module module to report from
2575
2673
  * @param {DependenciesBlock[]} blocks blocks to report from
2576
- * @returns {void}
2674
+ * @returns {boolean} true, when it has warnings or errors
2577
2675
  */
2578
2676
  reportDependencyErrorsAndWarnings(module, blocks) {
2677
+ let hasProblems = false;
2579
2678
  for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
2580
2679
  const block = blocks[indexBlock];
2581
2680
  const dependencies = block.dependencies;
@@ -2590,6 +2689,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2590
2689
 
2591
2690
  const warning = new ModuleDependencyWarning(module, w, d.loc);
2592
2691
  this.warnings.push(warning);
2692
+ hasProblems = true;
2593
2693
  }
2594
2694
  }
2595
2695
  const errors = d.getErrors(this.moduleGraph);
@@ -2599,17 +2699,22 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2599
2699
 
2600
2700
  const error = new ModuleDependencyError(module, e, d.loc);
2601
2701
  this.errors.push(error);
2702
+ hasProblems = true;
2602
2703
  }
2603
2704
  }
2604
2705
  }
2605
2706
 
2606
- this.reportDependencyErrorsAndWarnings(module, block.blocks);
2707
+ if (this.reportDependencyErrorsAndWarnings(module, block.blocks))
2708
+ hasProblems = true;
2607
2709
  }
2710
+ return hasProblems;
2608
2711
  }
2609
2712
 
2610
2713
  codeGeneration(callback) {
2611
2714
  const { chunkGraph } = this;
2612
- this.codeGenerationResults = new CodeGenerationResults();
2715
+ this.codeGenerationResults = new CodeGenerationResults(
2716
+ this.outputOptions.hashFunction
2717
+ );
2613
2718
  /** @type {{module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}[]} */
2614
2719
  const jobs = [];
2615
2720
  for (const module of this.modules) {
@@ -2790,12 +2895,41 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2790
2895
  chunkGraphEntries = this._getChunkGraphEntries()
2791
2896
  } = {}) {
2792
2897
  const context = { chunkGraph, codeGenerationResults };
2898
+ const { moduleMemCaches } = this;
2899
+ this.logger.time("runtime requirements.modules");
2793
2900
  const additionalModuleRuntimeRequirements =
2794
2901
  this.hooks.additionalModuleRuntimeRequirements;
2795
2902
  const runtimeRequirementInModule = this.hooks.runtimeRequirementInModule;
2796
2903
  for (const module of modules) {
2797
2904
  if (chunkGraph.getNumberOfModuleChunks(module) > 0) {
2905
+ const memCache =
2906
+ moduleMemCaches &&
2907
+ // modules with async blocks depend on the chunk graph and can't be cached that way
2908
+ module.blocks.length === 0 &&
2909
+ moduleMemCaches.get(module);
2910
+ /** @type {RuntimeSpecMap<Set<string>>} */
2911
+ const moduleRuntimeRequirementsMemCache =
2912
+ memCache &&
2913
+ memCache.provide(
2914
+ module,
2915
+ "moduleRuntimeRequirements",
2916
+ () => new RuntimeSpecMap()
2917
+ );
2798
2918
  for (const runtime of chunkGraph.getModuleRuntimes(module)) {
2919
+ if (moduleRuntimeRequirementsMemCache) {
2920
+ const cached = moduleRuntimeRequirementsMemCache.get(runtime);
2921
+ if (cached !== undefined) {
2922
+ if (cached !== null) {
2923
+ chunkGraph.addModuleRuntimeRequirements(
2924
+ module,
2925
+ runtime,
2926
+ cached,
2927
+ false
2928
+ );
2929
+ }
2930
+ continue;
2931
+ }
2932
+ }
2799
2933
  let set;
2800
2934
  const runtimeRequirements =
2801
2935
  codeGenerationResults.getRuntimeRequirements(module, runtime);
@@ -2804,6 +2938,9 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2804
2938
  } else if (additionalModuleRuntimeRequirements.isUsed()) {
2805
2939
  set = new Set();
2806
2940
  } else {
2941
+ if (moduleRuntimeRequirementsMemCache) {
2942
+ moduleRuntimeRequirementsMemCache.set(runtime, null);
2943
+ }
2807
2944
  continue;
2808
2945
  }
2809
2946
  additionalModuleRuntimeRequirements.call(module, set, context);
@@ -2812,11 +2949,29 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2812
2949
  const hook = runtimeRequirementInModule.get(r);
2813
2950
  if (hook !== undefined) hook.call(module, set, context);
2814
2951
  }
2815
- chunkGraph.addModuleRuntimeRequirements(module, runtime, set);
2952
+ if (set.size === 0) {
2953
+ if (moduleRuntimeRequirementsMemCache) {
2954
+ moduleRuntimeRequirementsMemCache.set(runtime, null);
2955
+ }
2956
+ } else {
2957
+ if (moduleRuntimeRequirementsMemCache) {
2958
+ moduleRuntimeRequirementsMemCache.set(runtime, set);
2959
+ chunkGraph.addModuleRuntimeRequirements(
2960
+ module,
2961
+ runtime,
2962
+ set,
2963
+ false
2964
+ );
2965
+ } else {
2966
+ chunkGraph.addModuleRuntimeRequirements(module, runtime, set);
2967
+ }
2968
+ }
2816
2969
  }
2817
2970
  }
2818
2971
  }
2972
+ this.logger.timeEnd("runtime requirements.modules");
2819
2973
 
2974
+ this.logger.time("runtime requirements.chunks");
2820
2975
  for (const chunk of chunks) {
2821
2976
  const set = new Set();
2822
2977
  for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
@@ -2834,7 +2989,9 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2834
2989
 
2835
2990
  chunkGraph.addChunkRuntimeRequirements(chunk, set);
2836
2991
  }
2992
+ this.logger.timeEnd("runtime requirements.chunks");
2837
2993
 
2994
+ this.logger.time("runtime requirements.entries");
2838
2995
  for (const treeEntry of chunkGraphEntries) {
2839
2996
  const set = new Set();
2840
2997
  for (const chunk of treeEntry.getAllReferencedChunks()) {
@@ -2857,6 +3014,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2857
3014
 
2858
3015
  chunkGraph.addTreeRuntimeRequirements(treeEntry, set);
2859
3016
  }
3017
+ this.logger.timeEnd("runtime requirements.entries");
2860
3018
  }
2861
3019
 
2862
3020
  // TODO webpack 6 make chunkGraph argument non-optional
@@ -3201,12 +3359,35 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
3201
3359
 
3202
3360
  createModuleHashes() {
3203
3361
  let statModulesHashed = 0;
3204
- const { chunkGraph, runtimeTemplate } = this;
3362
+ let statModulesFromCache = 0;
3363
+ const { chunkGraph, runtimeTemplate, moduleMemCaches } = this;
3205
3364
  const { hashFunction, hashDigest, hashDigestLength } = this.outputOptions;
3206
3365
  for (const module of this.modules) {
3366
+ const memCache =
3367
+ moduleMemCaches &&
3368
+ // modules with async blocks depend on the chunk graph and can't be cached that way
3369
+ module.blocks.length === 0 &&
3370
+ moduleMemCaches.get(module);
3371
+ /** @type {RuntimeSpecMap<string>} */
3372
+ const moduleHashesMemCache =
3373
+ memCache &&
3374
+ memCache.provide(module, "moduleHashes", () => new RuntimeSpecMap());
3207
3375
  for (const runtime of chunkGraph.getModuleRuntimes(module)) {
3376
+ if (moduleHashesMemCache) {
3377
+ const digest = moduleHashesMemCache.get(runtime);
3378
+ if (digest !== undefined) {
3379
+ chunkGraph.setModuleHashes(
3380
+ module,
3381
+ runtime,
3382
+ digest,
3383
+ digest.substr(0, hashDigestLength)
3384
+ );
3385
+ statModulesFromCache++;
3386
+ continue;
3387
+ }
3388
+ }
3208
3389
  statModulesHashed++;
3209
- this._createModuleHash(
3390
+ const digest = this._createModuleHash(
3210
3391
  module,
3211
3392
  chunkGraph,
3212
3393
  runtime,
@@ -3215,11 +3396,16 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
3215
3396
  hashDigest,
3216
3397
  hashDigestLength
3217
3398
  );
3399
+ if (moduleHashesMemCache) {
3400
+ moduleHashesMemCache.set(runtime, digest);
3401
+ }
3218
3402
  }
3219
3403
  }
3220
3404
  this.logger.log(
3221
- `${statModulesHashed} modules hashed (${
3222
- Math.round((100 * statModulesHashed) / this.modules.size) / 100
3405
+ `${statModulesHashed} modules hashed, ${statModulesFromCache} from cache (${
3406
+ Math.round(
3407
+ (100 * (statModulesHashed + statModulesFromCache)) / this.modules.size
3408
+ ) / 100
3223
3409
  } variants per module in average)`
3224
3410
  );
3225
3411
  }
@@ -4071,7 +4257,10 @@ This prevents using hashes of each other and should be avoided.`);
4071
4257
  if (err) return callback(err);
4072
4258
 
4073
4259
  // Create new chunk graph, chunk and entrypoint for the build time execution
4074
- const chunkGraph = new ChunkGraph(this.moduleGraph);
4260
+ const chunkGraph = new ChunkGraph(
4261
+ this.moduleGraph,
4262
+ this.outputOptions.hashFunction
4263
+ );
4075
4264
  const runtime = "build time";
4076
4265
  const { hashFunction, hashDigest, hashDigestLength } =
4077
4266
  this.outputOptions;
@@ -4114,7 +4303,9 @@ This prevents using hashes of each other and should be avoided.`);
4114
4303
  );
4115
4304
  }
4116
4305
 
4117
- const codeGenerationResults = new CodeGenerationResults();
4306
+ const codeGenerationResults = new CodeGenerationResults(
4307
+ this.outputOptions.hashFunction
4308
+ );
4118
4309
  /** @type {WebpackError[]} */
4119
4310
  const errors = [];
4120
4311
  /**
package/lib/Compiler.js CHANGED
@@ -41,6 +41,7 @@ const { isSourceEqual } = require("./util/source");
41
41
  /** @typedef {import("../declarations/WebpackOptions").WebpackPluginInstance} WebpackPluginInstance */
42
42
  /** @typedef {import("./Chunk")} Chunk */
43
43
  /** @typedef {import("./FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
44
+ /** @typedef {import("./MemCache")} MemCache */
44
45
  /** @typedef {import("./Module")} Module */
45
46
  /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
46
47
  /** @typedef {import("./util/fs").IntermediateFileSystem} IntermediateFileSystem */
@@ -247,6 +248,9 @@ class Compiler {
247
248
 
248
249
  this.cache = new Cache();
249
250
 
251
+ /** @type {WeakMap<Module, { hash: string, memCache: MemCache }> | undefined} */
252
+ this.moduleMemCaches = undefined;
253
+
250
254
  this.compilerPath = "";
251
255
 
252
256
  /** @type {boolean} */
@@ -276,7 +280,11 @@ class Compiler {
276
280
  * @returns {CacheFacade} the cache facade instance
277
281
  */
278
282
  getCache(name) {
279
- return new CacheFacade(this.cache, `${this.compilerPath}${name}`);
283
+ return new CacheFacade(
284
+ this.cache,
285
+ `${this.compilerPath}${name}`,
286
+ this.options.output.hashFunction
287
+ );
280
288
  }
281
289
 
282
290
  /**
@@ -9,14 +9,20 @@ const createHash = require("./util/createHash");
9
9
 
10
10
  /** @typedef {import("./Dependency")} Dependency */
11
11
  /** @typedef {import("./DependencyTemplate")} DependencyTemplate */
12
+ /** @typedef {typeof import("./util/Hash")} Hash */
13
+
12
14
  /** @typedef {new (...args: any[]) => Dependency} DependencyConstructor */
13
15
 
14
16
  class DependencyTemplates {
15
- constructor() {
17
+ /**
18
+ * @param {string | Hash} hashFunction the hash function to use
19
+ */
20
+ constructor(hashFunction = "md4") {
16
21
  /** @type {Map<Function, DependencyTemplate>} */
17
22
  this._map = new Map();
18
23
  /** @type {string} */
19
24
  this._hash = "31d6cfe0d16ae931b73c59d7e0c089c0";
25
+ this._hashFunction = hashFunction;
20
26
  }
21
27
 
22
28
  /**
@@ -41,7 +47,7 @@ class DependencyTemplates {
41
47
  * @returns {void}
42
48
  */
43
49
  updateHash(part) {
44
- const hash = createHash("md4");
50
+ const hash = createHash(this._hashFunction);
45
51
  hash.update(this._hash);
46
52
  hash.update(part);
47
53
  this._hash = /** @type {string} */ (hash.digest("hex"));
@@ -61,7 +61,8 @@ class EvalDevToolModulePlugin {
61
61
  },
62
62
  {
63
63
  requestShortener: runtimeTemplate.requestShortener,
64
- chunkGraph
64
+ chunkGraph,
65
+ hashFunction: compilation.outputOptions.hashFunction
65
66
  }
66
67
  );
67
68
  const footer =
@@ -138,7 +138,8 @@ class EvalSourceMapDevToolPlugin {
138
138
  },
139
139
  {
140
140
  requestShortener: runtimeTemplate.requestShortener,
141
- chunkGraph
141
+ chunkGraph,
142
+ hashFunction: compilation.outputOptions.hashFunction
142
143
  }
143
144
  );
144
145
  });