webpack 5.52.0 → 5.55.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 (71) hide show
  1. package/bin/webpack.js +0 -0
  2. package/lib/AsyncDependenciesBlock.js +9 -2
  3. package/lib/CacheFacade.js +10 -3
  4. package/lib/ChunkGraph.js +19 -8
  5. package/lib/CodeGenerationResults.js +7 -2
  6. package/lib/Compilation.js +549 -144
  7. package/lib/Compiler.js +12 -4
  8. package/lib/Dependency.js +11 -0
  9. package/lib/DependencyTemplates.js +8 -2
  10. package/lib/EvalDevToolModulePlugin.js +2 -1
  11. package/lib/EvalSourceMapDevToolPlugin.js +2 -1
  12. package/lib/ExternalModule.js +18 -9
  13. package/lib/FileSystemInfo.js +101 -170
  14. package/lib/FlagDependencyExportsPlugin.js +25 -16
  15. package/lib/JavascriptMetaInfoPlugin.js +6 -1
  16. package/lib/ModuleFactory.js +1 -0
  17. package/lib/ModuleFilenameHelpers.js +21 -7
  18. package/lib/ModuleGraph.js +90 -21
  19. package/lib/NodeStuffInWebError.js +34 -0
  20. package/lib/NodeStuffPlugin.js +59 -16
  21. package/lib/NormalModuleFactory.js +8 -43
  22. package/lib/SourceMapDevToolPlugin.js +7 -3
  23. package/lib/WebpackOptionsApply.js +19 -1
  24. package/lib/cache/PackFileCacheStrategy.js +183 -53
  25. package/lib/cache/getLazyHashedEtag.js +35 -8
  26. package/lib/config/defaults.js +32 -12
  27. package/lib/dependencies/CachedConstDependency.js +4 -3
  28. package/lib/dependencies/CommonJsExportRequireDependency.js +19 -9
  29. package/lib/dependencies/CommonJsFullRequireDependency.js +11 -9
  30. package/lib/dependencies/ConstDependency.js +12 -4
  31. package/lib/dependencies/ContextDependency.js +8 -0
  32. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +179 -163
  33. package/lib/dependencies/HarmonyImportDependency.js +4 -1
  34. package/lib/dependencies/JsonExportsDependency.js +7 -1
  35. package/lib/dependencies/ModuleDecoratorDependency.js +5 -2
  36. package/lib/dependencies/ModuleDependency.js +8 -0
  37. package/lib/dependencies/NullDependency.js +8 -4
  38. package/lib/dependencies/ProvidedDependency.js +6 -2
  39. package/lib/dependencies/PureExpressionDependency.js +5 -1
  40. package/lib/dependencies/RuntimeRequirementsDependency.js +5 -1
  41. package/lib/dependencies/WebAssemblyExportImportedDependency.js +9 -0
  42. package/lib/ids/IdHelpers.js +21 -8
  43. package/lib/ids/NamedChunkIdsPlugin.js +3 -0
  44. package/lib/ids/NamedModuleIdsPlugin.js +3 -1
  45. package/lib/index.js +6 -0
  46. package/lib/javascript/BasicEvaluatedExpression.js +3 -0
  47. package/lib/javascript/JavascriptParser.js +22 -4
  48. package/lib/javascript/JavascriptParserHelpers.js +0 -2
  49. package/lib/node/NodeTargetPlugin.js +1 -0
  50. package/lib/optimize/ConcatenatedModule.js +25 -4
  51. package/lib/optimize/InnerGraph.js +22 -2
  52. package/lib/optimize/ModuleConcatenationPlugin.js +2 -1
  53. package/lib/runtime/RelativeUrlRuntimeModule.js +1 -1
  54. package/lib/schemes/HttpUriPlugin.js +1 -2
  55. package/lib/serialization/BinaryMiddleware.js +11 -2
  56. package/lib/serialization/FileMiddleware.js +24 -7
  57. package/lib/serialization/ObjectMiddleware.js +23 -12
  58. package/lib/util/WeakTupleMap.js +95 -92
  59. package/lib/util/createHash.js +10 -0
  60. package/lib/util/hash/BatchedHash.js +65 -0
  61. package/lib/util/hash/xxhash64.js +154 -0
  62. package/lib/util/internalSerializables.js +1 -0
  63. package/lib/util/serialization.js +10 -6
  64. package/package.json +11 -7
  65. package/schemas/WebpackOptions.check.js +1 -1
  66. package/schemas/WebpackOptions.json +19 -3
  67. package/schemas/plugins/HashedModuleIdsPlugin.check.js +1 -1
  68. package/schemas/plugins/HashedModuleIdsPlugin.json +20 -2
  69. package/schemas/plugins/IgnorePlugin.check.js +1 -1
  70. package/schemas/plugins/IgnorePlugin.json +4 -2
  71. package/types.d.ts +211 -25
@@ -25,6 +25,7 @@ const ChunkRenderError = require("./ChunkRenderError");
25
25
  const ChunkTemplate = require("./ChunkTemplate");
26
26
  const CodeGenerationError = require("./CodeGenerationError");
27
27
  const CodeGenerationResults = require("./CodeGenerationResults");
28
+ const Dependency = require("./Dependency");
28
29
  const DependencyTemplates = require("./DependencyTemplates");
29
30
  const Entrypoint = require("./Entrypoint");
30
31
  const ErrorHelpers = require("./ErrorHelpers");
@@ -60,6 +61,7 @@ const { equals: arrayEquals } = require("./util/ArrayHelpers");
60
61
  const AsyncQueue = require("./util/AsyncQueue");
61
62
  const LazySet = require("./util/LazySet");
62
63
  const { provide } = require("./util/MapHelpers");
64
+ const WeakTupleMap = require("./util/WeakTupleMap");
63
65
  const { cachedCleverMerge } = require("./util/cleverMerge");
64
66
  const {
65
67
  compareLocations,
@@ -76,7 +78,7 @@ const {
76
78
  createFakeHook
77
79
  } = require("./util/deprecation");
78
80
  const processAsyncTree = require("./util/processAsyncTree");
79
- const { getRuntimeKey } = require("./util/runtime");
81
+ const { getRuntimeKey, RuntimeSpecMap } = require("./util/runtime");
80
82
  const { isSourceEqual } = require("./util/source");
81
83
 
82
84
  /** @template T @typedef {import("tapable").AsArray<T>} AsArray<T> */
@@ -91,8 +93,8 @@ const { isSourceEqual } = require("./util/source");
91
93
  /** @typedef {import("./CacheFacade")} CacheFacade */
92
94
  /** @typedef {import("./ChunkGroup").ChunkGroupOptions} ChunkGroupOptions */
93
95
  /** @typedef {import("./Compiler")} Compiler */
96
+ /** @typedef {import("./Compiler").CompilationParams} CompilationParams */
94
97
  /** @typedef {import("./DependenciesBlock")} DependenciesBlock */
95
- /** @typedef {import("./Dependency")} Dependency */
96
98
  /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
97
99
  /** @typedef {import("./Dependency").ReferencedExport} ReferencedExport */
98
100
  /** @typedef {import("./DependencyTemplate")} DependencyTemplate */
@@ -100,6 +102,7 @@ const { isSourceEqual } = require("./util/source");
100
102
  /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
101
103
  /** @typedef {import("./ModuleFactory")} ModuleFactory */
102
104
  /** @typedef {import("./ModuleFactory").ModuleFactoryCreateDataContextInfo} ModuleFactoryCreateDataContextInfo */
105
+ /** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
103
106
  /** @typedef {import("./RequestShortener")} RequestShortener */
104
107
  /** @typedef {import("./RuntimeModule")} RuntimeModule */
105
108
  /** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */
@@ -124,6 +127,20 @@ const { isSourceEqual } = require("./util/source");
124
127
  * @returns {void}
125
128
  */
126
129
 
130
+ /**
131
+ * @callback ModuleFactoryResultCallback
132
+ * @param {WebpackError=} err
133
+ * @param {ModuleFactoryResult=} result
134
+ * @returns {void}
135
+ */
136
+
137
+ /**
138
+ * @callback ModuleOrFactoryResultCallback
139
+ * @param {WebpackError=} err
140
+ * @param {Module | ModuleFactoryResult=} result
141
+ * @returns {void}
142
+ */
143
+
127
144
  /**
128
145
  * @callback ExecuteModuleCallback
129
146
  * @param {WebpackError=} err
@@ -399,12 +416,19 @@ const byLocation = compareSelect(err => err.loc, compareLocations);
399
416
 
400
417
  const compareErrors = concatComparators(byModule, byLocation, byMessage);
401
418
 
419
+ /** @type {WeakMap<Dependency, Module & { restoreFromUnsafeCache: Function }>} */
420
+ const unsafeCacheDependencies = new WeakMap();
421
+
422
+ /** @type {WeakMap<Module, object>} */
423
+ const unsafeCacheData = new WeakMap();
424
+
402
425
  class Compilation {
403
426
  /**
404
427
  * Creates an instance of Compilation.
405
428
  * @param {Compiler} compiler the compiler which created the compilation
429
+ * @param {CompilationParams} params the compilation parameters
406
430
  */
407
- constructor(compiler) {
431
+ constructor(compiler, params) {
408
432
  const getNormalModuleLoader = () => deprecatedNormalModuleLoaderHook(this);
409
433
  /** @typedef {{ additionalAssets?: true | Function }} ProcessAssetsAdditionalOptions */
410
434
  /** @type {AsyncSeriesHook<[CompilationAssets], ProcessAssetsAdditionalOptions>} */
@@ -852,7 +876,8 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
852
876
  this.fileSystemInfo = new FileSystemInfo(this.inputFileSystem, {
853
877
  managedPaths: compiler.managedPaths,
854
878
  immutablePaths: compiler.immutablePaths,
855
- logger: this.getLogger("webpack.FileSystemInfo")
879
+ logger: this.getLogger("webpack.FileSystemInfo"),
880
+ hashFunction: compiler.options.output.hashFunction
856
881
  });
857
882
  if (compiler.fileTimestamps) {
858
883
  this.fileSystemInfo.addFileTimestamps(compiler.fileTimestamps, true);
@@ -878,6 +903,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
878
903
  /** @type {boolean} */
879
904
  this.profile = (options && options.profile) || false;
880
905
 
906
+ this.params = params;
881
907
  this.mainTemplate = new MainTemplate(this.outputOptions, this);
882
908
  this.chunkTemplate = new ChunkTemplate(this.outputOptions, this);
883
909
  this.runtimeTemplate = new RuntimeTemplate(
@@ -891,6 +917,8 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
891
917
  };
892
918
  defineRemovedModuleTemplates(this.moduleTemplates);
893
919
 
920
+ /** @type {WeakMap<Module, WeakTupleMap<any, any>> | undefined} */
921
+ this.moduleMemCaches = undefined;
894
922
  this.moduleGraph = new ModuleGraph();
895
923
  /** @type {ChunkGraph} */
896
924
  this.chunkGraph = undefined;
@@ -910,7 +938,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
910
938
  getKey: module => module.identifier(),
911
939
  processor: this._addModule.bind(this)
912
940
  });
913
- /** @type {AsyncQueue<FactorizeModuleOptions, string, Module>} */
941
+ /** @type {AsyncQueue<FactorizeModuleOptions, string, Module | ModuleFactoryResult>} */
914
942
  this.factorizeQueue = new AsyncQueue({
915
943
  name: "factorize",
916
944
  parent: this.addModuleQueue,
@@ -993,6 +1021,8 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
993
1021
  this.usedModuleIds = null;
994
1022
  /** @type {boolean} */
995
1023
  this.needAdditionalPass = false;
1024
+ /** @type {Set<Module>} */
1025
+ this._restoredUnsafeCacheEntries = new Set();
996
1026
  /** @type {WeakSet<Module>} */
997
1027
  this.builtModules = new WeakSet();
998
1028
  /** @type {WeakSet<Module>} */
@@ -1025,6 +1055,11 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1025
1055
  this._modulesCache = this.getCache("Compilation/modules");
1026
1056
  this._assetsCache = this.getCache("Compilation/assets");
1027
1057
  this._codeGenerationCache = this.getCache("Compilation/codeGeneration");
1058
+
1059
+ const unsafeCache = options.module.unsafeCache;
1060
+ this._unsafeCache = !!unsafeCache;
1061
+ this._unsafeCachePredicate =
1062
+ typeof unsafeCache === "function" ? unsafeCache : () => true;
1028
1063
  }
1029
1064
 
1030
1065
  getStats() {
@@ -1409,12 +1444,44 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1409
1444
  /** @type {Dependency[]} */
1410
1445
  let listCacheValue;
1411
1446
 
1447
+ const unsafeRestoredModules = new Set();
1448
+
1412
1449
  /**
1413
1450
  * @param {Dependency} dep dependency
1414
1451
  * @returns {void}
1415
1452
  */
1416
1453
  const processDependency = dep => {
1417
1454
  this.moduleGraph.setParents(dep, currentBlock, module);
1455
+ if (this._unsafeCache) {
1456
+ try {
1457
+ const cachedModule = unsafeCacheDependencies.get(dep);
1458
+ if (cachedModule === null) return;
1459
+ if (cachedModule !== undefined) {
1460
+ if (!this._restoredUnsafeCacheEntries.has(cachedModule)) {
1461
+ const data = unsafeCacheData.get(cachedModule);
1462
+ cachedModule.restoreFromUnsafeCache(
1463
+ data,
1464
+ this.params.normalModuleFactory,
1465
+ this.params
1466
+ );
1467
+ this._restoredUnsafeCacheEntries.add(cachedModule);
1468
+ if (!this.modules.has(cachedModule)) {
1469
+ this._handleNewModuleFromUnsafeCache(module, dep, cachedModule);
1470
+ unsafeRestoredModules.add(cachedModule);
1471
+ return;
1472
+ }
1473
+ }
1474
+ this._handleExistingModuleFromUnsafeCache(
1475
+ module,
1476
+ dep,
1477
+ cachedModule
1478
+ );
1479
+ return;
1480
+ }
1481
+ } catch (e) {
1482
+ console.error(e);
1483
+ }
1484
+ }
1418
1485
  const resourceIdent = dep.getResourceIdentifier();
1419
1486
  if (resourceIdent !== undefined && resourceIdent !== null) {
1420
1487
  const category = dep.category;
@@ -1498,7 +1565,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1498
1565
  return callback(e);
1499
1566
  }
1500
1567
 
1501
- if (sortedDependencies.length === 0) {
1568
+ if (sortedDependencies.length === 0 && unsafeRestoredModules.size === 0) {
1502
1569
  callback();
1503
1570
  return;
1504
1571
  }
@@ -1506,27 +1573,78 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1506
1573
  // This is nested so we need to allow one additional task
1507
1574
  this.processDependenciesQueue.increaseParallelism();
1508
1575
 
1509
- asyncLib.forEach(
1510
- sortedDependencies,
1511
- (item, callback) => {
1512
- this.handleModuleCreation(item, err => {
1513
- // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
1514
- // errors are created inside closures that keep a reference to the Compilation, so errors are
1515
- // leaking the Compilation object.
1516
- if (err && this.bail) {
1517
- // eslint-disable-next-line no-self-assign
1518
- err.stack = err.stack;
1519
- return callback(err);
1520
- }
1521
- callback();
1522
- });
1523
- },
1524
- err => {
1525
- this.processDependenciesQueue.decreaseParallelism();
1576
+ const processSortedDependency = (item, callback) => {
1577
+ this.handleModuleCreation(item, err => {
1578
+ // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
1579
+ // errors are created inside closures that keep a reference to the Compilation, so errors are
1580
+ // leaking the Compilation object.
1581
+ if (err && this.bail) {
1582
+ // eslint-disable-next-line no-self-assign
1583
+ err.stack = err.stack;
1584
+ return callback(err);
1585
+ }
1586
+ callback();
1587
+ });
1588
+ };
1526
1589
 
1527
- return callback(err);
1528
- }
1590
+ const processUnsafeRestoredModule = (item, callback) => {
1591
+ this._handleModuleBuildAndDependencies(module, item, true, callback);
1592
+ };
1593
+
1594
+ const finalCallback = err => {
1595
+ this.processDependenciesQueue.decreaseParallelism();
1596
+
1597
+ return callback(err);
1598
+ };
1599
+
1600
+ if (sortedDependencies.length === 0) {
1601
+ asyncLib.forEach(
1602
+ unsafeRestoredModules,
1603
+ processUnsafeRestoredModule,
1604
+ finalCallback
1605
+ );
1606
+ } else if (unsafeRestoredModules.size === 0) {
1607
+ asyncLib.forEach(
1608
+ sortedDependencies,
1609
+ processSortedDependency,
1610
+ finalCallback
1611
+ );
1612
+ } else {
1613
+ asyncLib.parallel(
1614
+ [
1615
+ cb =>
1616
+ asyncLib.forEach(
1617
+ unsafeRestoredModules,
1618
+ processUnsafeRestoredModule,
1619
+ cb
1620
+ ),
1621
+ cb =>
1622
+ asyncLib.forEach(sortedDependencies, processSortedDependency, cb)
1623
+ ],
1624
+ finalCallback
1625
+ );
1626
+ }
1627
+ }
1628
+
1629
+ _handleNewModuleFromUnsafeCache(originModule, dependency, module) {
1630
+ const moduleGraph = this.moduleGraph;
1631
+
1632
+ moduleGraph.setResolvedModule(originModule, dependency, module);
1633
+
1634
+ moduleGraph.setIssuerIfUnset(
1635
+ module,
1636
+ originModule !== undefined ? originModule : null
1529
1637
  );
1638
+
1639
+ this._modules.set(module.identifier(), module);
1640
+ this.modules.add(module);
1641
+ ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);
1642
+ }
1643
+
1644
+ _handleExistingModuleFromUnsafeCache(originModule, dependency, module) {
1645
+ const moduleGraph = this.moduleGraph;
1646
+
1647
+ moduleGraph.setResolvedModule(originModule, dependency, module);
1530
1648
  }
1531
1649
 
1532
1650
  /**
@@ -1566,12 +1684,27 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1566
1684
  currentProfile,
1567
1685
  factory,
1568
1686
  dependencies,
1687
+ factoryResult: true,
1569
1688
  originModule,
1570
1689
  contextInfo,
1571
1690
  context
1572
1691
  },
1573
- (err, newModule) => {
1692
+ (err, factoryResult) => {
1693
+ const applyFactoryResultDependencies = () => {
1694
+ const { fileDependencies, contextDependencies, missingDependencies } =
1695
+ factoryResult;
1696
+ if (fileDependencies) {
1697
+ this.fileDependencies.addAll(fileDependencies);
1698
+ }
1699
+ if (contextDependencies) {
1700
+ this.contextDependencies.addAll(contextDependencies);
1701
+ }
1702
+ if (missingDependencies) {
1703
+ this.missingDependencies.addAll(missingDependencies);
1704
+ }
1705
+ };
1574
1706
  if (err) {
1707
+ if (factoryResult) applyFactoryResultDependencies();
1575
1708
  if (dependencies.every(d => d.optional)) {
1576
1709
  this.warnings.push(err);
1577
1710
  return callback();
@@ -1581,7 +1714,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1581
1714
  }
1582
1715
  }
1583
1716
 
1717
+ const newModule = factoryResult.module;
1718
+
1584
1719
  if (!newModule) {
1720
+ applyFactoryResultDependencies();
1585
1721
  return callback();
1586
1722
  }
1587
1723
 
@@ -1591,6 +1727,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1591
1727
 
1592
1728
  this.addModule(newModule, (err, module) => {
1593
1729
  if (err) {
1730
+ applyFactoryResultDependencies();
1594
1731
  if (!err.module) {
1595
1732
  err.module = module;
1596
1733
  }
@@ -1599,13 +1736,37 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1599
1736
  return callback(err);
1600
1737
  }
1601
1738
 
1602
- for (let i = 0; i < dependencies.length; i++) {
1603
- const dependency = dependencies[i];
1604
- moduleGraph.setResolvedModule(
1605
- connectOrigin ? originModule : null,
1606
- dependency,
1607
- module
1608
- );
1739
+ if (
1740
+ this._unsafeCache &&
1741
+ factoryResult.cacheable !== false &&
1742
+ /** @type {any} */ (module).restoreFromUnsafeCache &&
1743
+ this._unsafeCachePredicate(module)
1744
+ ) {
1745
+ for (let i = 0; i < dependencies.length; i++) {
1746
+ const dependency = dependencies[i];
1747
+ moduleGraph.setResolvedModule(
1748
+ connectOrigin ? originModule : null,
1749
+ dependency,
1750
+ module
1751
+ );
1752
+ unsafeCacheDependencies.set(
1753
+ dependency,
1754
+ /** @type {any} */ (module)
1755
+ );
1756
+ }
1757
+ if (!unsafeCacheData.has(module)) {
1758
+ unsafeCacheData.set(module, module.getUnsafeCacheData());
1759
+ }
1760
+ } else {
1761
+ applyFactoryResultDependencies();
1762
+ for (let i = 0; i < dependencies.length; i++) {
1763
+ const dependency = dependencies[i];
1764
+ moduleGraph.setResolvedModule(
1765
+ connectOrigin ? originModule : null,
1766
+ dependency,
1767
+ module
1768
+ );
1769
+ }
1609
1770
  }
1610
1771
 
1611
1772
  moduleGraph.setIssuerIfUnset(
@@ -1623,99 +1784,89 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1623
1784
  }
1624
1785
  }
1625
1786
 
1626
- // Check for cycles when build is trigger inside another build
1627
- let creatingModuleDuringBuildSet = undefined;
1628
- if (!recursive && this.buildQueue.isProcessing(originModule)) {
1629
- // Track build dependency
1630
- creatingModuleDuringBuildSet =
1631
- this.creatingModuleDuringBuild.get(originModule);
1632
- if (creatingModuleDuringBuildSet === undefined) {
1633
- creatingModuleDuringBuildSet = new Set();
1634
- this.creatingModuleDuringBuild.set(
1635
- originModule,
1636
- creatingModuleDuringBuildSet
1637
- );
1638
- }
1639
- creatingModuleDuringBuildSet.add(originModule);
1640
-
1641
- // When building is blocked by another module
1642
- // search for a cycle, cancel the cycle by throwing
1643
- // an error (otherwise this would deadlock)
1644
- const blockReasons = this.creatingModuleDuringBuild.get(module);
1645
- if (blockReasons !== undefined) {
1646
- const set = new Set(blockReasons);
1647
- for (const item of set) {
1648
- const blockReasons = this.creatingModuleDuringBuild.get(item);
1649
- if (blockReasons !== undefined) {
1650
- for (const m of blockReasons) {
1651
- if (m === module) {
1652
- return callback(new BuildCycleError(module));
1653
- }
1654
- set.add(m);
1655
- }
1656
- }
1657
- }
1658
- }
1659
- }
1787
+ this._handleModuleBuildAndDependencies(
1788
+ originModule,
1789
+ module,
1790
+ recursive,
1791
+ callback
1792
+ );
1793
+ });
1794
+ }
1795
+ );
1796
+ }
1660
1797
 
1661
- this.buildModule(module, err => {
1662
- if (creatingModuleDuringBuildSet !== undefined) {
1663
- creatingModuleDuringBuildSet.delete(module);
1664
- }
1665
- if (err) {
1666
- if (!err.module) {
1667
- err.module = module;
1798
+ _handleModuleBuildAndDependencies(originModule, module, recursive, callback) {
1799
+ // Check for cycles when build is trigger inside another build
1800
+ let creatingModuleDuringBuildSet = undefined;
1801
+ if (!recursive && this.buildQueue.isProcessing(originModule)) {
1802
+ // Track build dependency
1803
+ creatingModuleDuringBuildSet =
1804
+ this.creatingModuleDuringBuild.get(originModule);
1805
+ if (creatingModuleDuringBuildSet === undefined) {
1806
+ creatingModuleDuringBuildSet = new Set();
1807
+ this.creatingModuleDuringBuild.set(
1808
+ originModule,
1809
+ creatingModuleDuringBuildSet
1810
+ );
1811
+ }
1812
+ creatingModuleDuringBuildSet.add(originModule);
1813
+
1814
+ // When building is blocked by another module
1815
+ // search for a cycle, cancel the cycle by throwing
1816
+ // an error (otherwise this would deadlock)
1817
+ const blockReasons = this.creatingModuleDuringBuild.get(module);
1818
+ if (blockReasons !== undefined) {
1819
+ const set = new Set(blockReasons);
1820
+ for (const item of set) {
1821
+ const blockReasons = this.creatingModuleDuringBuild.get(item);
1822
+ if (blockReasons !== undefined) {
1823
+ for (const m of blockReasons) {
1824
+ if (m === module) {
1825
+ return callback(new BuildCycleError(module));
1668
1826
  }
1669
- this.errors.push(err);
1670
-
1671
- return callback(err);
1827
+ set.add(m);
1672
1828
  }
1829
+ }
1830
+ }
1831
+ }
1832
+ }
1673
1833
 
1674
- if (!recursive) {
1675
- this.processModuleDependenciesNonRecursive(module);
1676
- callback(null, module);
1677
- return;
1678
- }
1834
+ this.buildModule(module, err => {
1835
+ if (creatingModuleDuringBuildSet !== undefined) {
1836
+ creatingModuleDuringBuildSet.delete(module);
1837
+ }
1838
+ if (err) {
1839
+ if (!err.module) {
1840
+ err.module = module;
1841
+ }
1842
+ this.errors.push(err);
1679
1843
 
1680
- // This avoids deadlocks for circular dependencies
1681
- if (this.processDependenciesQueue.isProcessing(module)) {
1682
- return callback();
1683
- }
1844
+ return callback(err);
1845
+ }
1684
1846
 
1685
- this.processModuleDependencies(module, err => {
1686
- if (err) {
1687
- return callback(err);
1688
- }
1689
- callback(null, module);
1690
- });
1691
- });
1692
- });
1847
+ if (!recursive) {
1848
+ this.processModuleDependenciesNonRecursive(module);
1849
+ callback(null, module);
1850
+ return;
1693
1851
  }
1694
- );
1695
- }
1696
1852
 
1697
- /**
1698
- * @typedef {Object} FactorizeModuleOptions
1699
- * @property {ModuleProfile} currentProfile
1700
- * @property {ModuleFactory} factory
1701
- * @property {Dependency[]} dependencies
1702
- * @property {Module | null} originModule
1703
- * @property {Partial<ModuleFactoryCreateDataContextInfo>=} contextInfo
1704
- * @property {string=} context
1705
- */
1853
+ // This avoids deadlocks for circular dependencies
1854
+ if (this.processDependenciesQueue.isProcessing(module)) {
1855
+ return callback();
1856
+ }
1706
1857
 
1707
- /**
1708
- * @param {FactorizeModuleOptions} options options object
1709
- * @param {ModuleCallback} callback callback
1710
- * @returns {void}
1711
- */
1712
- factorizeModule(options, callback) {
1713
- this.factorizeQueue.add(options, callback);
1858
+ this.processModuleDependencies(module, err => {
1859
+ if (err) {
1860
+ return callback(err);
1861
+ }
1862
+ callback(null, module);
1863
+ });
1864
+ });
1714
1865
  }
1715
1866
 
1716
1867
  /**
1717
1868
  * @param {FactorizeModuleOptions} options options object
1718
- * @param {ModuleCallback} callback callback
1869
+ * @param {ModuleOrFactoryResultCallback} callback callback
1719
1870
  * @returns {void}
1720
1871
  */
1721
1872
  _factorizeModule(
@@ -1724,6 +1875,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1724
1875
  factory,
1725
1876
  dependencies,
1726
1877
  originModule,
1878
+ factoryResult,
1727
1879
  contextInfo,
1728
1880
  context
1729
1881
  },
@@ -1757,16 +1909,21 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1757
1909
  module: result
1758
1910
  };
1759
1911
  }
1760
- const { fileDependencies, contextDependencies, missingDependencies } =
1761
- result;
1762
- if (fileDependencies) {
1763
- this.fileDependencies.addAll(fileDependencies);
1764
- }
1765
- if (contextDependencies) {
1766
- this.contextDependencies.addAll(contextDependencies);
1767
- }
1768
- if (missingDependencies) {
1769
- this.missingDependencies.addAll(missingDependencies);
1912
+ if (!factoryResult) {
1913
+ const {
1914
+ fileDependencies,
1915
+ contextDependencies,
1916
+ missingDependencies
1917
+ } = result;
1918
+ if (fileDependencies) {
1919
+ this.fileDependencies.addAll(fileDependencies);
1920
+ }
1921
+ if (contextDependencies) {
1922
+ this.contextDependencies.addAll(contextDependencies);
1923
+ }
1924
+ if (missingDependencies) {
1925
+ this.missingDependencies.addAll(missingDependencies);
1926
+ }
1770
1927
  }
1771
1928
  }
1772
1929
  if (err) {
@@ -1775,20 +1932,17 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1775
1932
  err,
1776
1933
  dependencies.map(d => d.loc).filter(Boolean)[0]
1777
1934
  );
1778
- return callback(notFoundError);
1935
+ return callback(notFoundError, factoryResult ? result : undefined);
1779
1936
  }
1780
1937
  if (!result) {
1781
1938
  return callback();
1782
1939
  }
1783
- const newModule = result.module;
1784
- if (!newModule) {
1785
- return callback();
1786
- }
1940
+
1787
1941
  if (currentProfile !== undefined) {
1788
1942
  currentProfile.markFactoryEnd();
1789
1943
  }
1790
1944
 
1791
- callback(null, newModule);
1945
+ callback(null, factoryResult ? result : result.module);
1792
1946
  }
1793
1947
  );
1794
1948
  }
@@ -2011,6 +2165,120 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2011
2165
  });
2012
2166
  }
2013
2167
 
2168
+ _computeAffectedModules(modules) {
2169
+ const moduleMemCacheCache = this.compiler.moduleMemCaches;
2170
+ if (!moduleMemCacheCache) return;
2171
+ if (!this.moduleMemCaches) {
2172
+ this.moduleMemCaches = new WeakMap();
2173
+ this.moduleGraph.setModuleMemCaches(this.moduleMemCaches);
2174
+ }
2175
+ const { moduleGraph, moduleMemCaches } = this;
2176
+ const affectedModules = new Set();
2177
+ const infectedModules = new Set();
2178
+ let statNew = 0;
2179
+ let statChanged = 0;
2180
+ let statUnchanged = 0;
2181
+ let statWithoutHash = 0;
2182
+ for (const module of modules) {
2183
+ const hash = module.buildInfo && module.buildInfo.hash;
2184
+ if (typeof hash === "string") {
2185
+ const cachedMemCache = moduleMemCacheCache.get(module);
2186
+ if (cachedMemCache === undefined) {
2187
+ // create a new entry
2188
+ const memCache = new WeakTupleMap();
2189
+ moduleMemCacheCache.set(module, {
2190
+ hash: hash,
2191
+ memCache
2192
+ });
2193
+ moduleMemCaches.set(module, memCache);
2194
+ affectedModules.add(module);
2195
+ statNew++;
2196
+ } else if (cachedMemCache.hash === hash) {
2197
+ // keep the old mem cache
2198
+ moduleMemCaches.set(module, cachedMemCache.memCache);
2199
+ statUnchanged++;
2200
+ } else {
2201
+ // use a new one
2202
+ const memCache = new WeakTupleMap();
2203
+ moduleMemCacheCache.set(module, {
2204
+ hash: hash,
2205
+ memCache
2206
+ });
2207
+ moduleMemCaches.set(module, memCache);
2208
+ affectedModules.add(module);
2209
+ cachedMemCache.hash = hash;
2210
+ cachedMemCache.memCache = memCache;
2211
+ statChanged++;
2212
+ }
2213
+ } else {
2214
+ infectedModules.add(module);
2215
+ statWithoutHash++;
2216
+ }
2217
+ }
2218
+ const reduceAffectType = connections => {
2219
+ let affected = false;
2220
+ for (const { dependency } of connections) {
2221
+ if (!dependency) continue;
2222
+ const type = dependency.couldAffectReferencingModule();
2223
+ if (type === Dependency.TRANSITIVE) return Dependency.TRANSITIVE;
2224
+ if (type === false) continue;
2225
+ affected = true;
2226
+ }
2227
+ return affected;
2228
+ };
2229
+ const directOnlyInfectedModules = new Set();
2230
+ for (const module of infectedModules) {
2231
+ for (const [
2232
+ referencingModule,
2233
+ connections
2234
+ ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
2235
+ if (!referencingModule) continue;
2236
+ if (infectedModules.has(referencingModule)) continue;
2237
+ const type = reduceAffectType(connections);
2238
+ if (!type) continue;
2239
+ if (type === true) {
2240
+ directOnlyInfectedModules.add(referencingModule);
2241
+ } else {
2242
+ infectedModules.add(referencingModule);
2243
+ }
2244
+ }
2245
+ }
2246
+ for (const module of directOnlyInfectedModules) infectedModules.add(module);
2247
+ const directOnlyAffectModules = new Set();
2248
+ for (const module of affectedModules) {
2249
+ for (const [
2250
+ referencingModule,
2251
+ connections
2252
+ ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
2253
+ if (!referencingModule) continue;
2254
+ if (infectedModules.has(referencingModule)) continue;
2255
+ if (affectedModules.has(referencingModule)) continue;
2256
+ const type = reduceAffectType(connections);
2257
+ if (!type) continue;
2258
+ if (type === true) {
2259
+ directOnlyAffectModules.add(referencingModule);
2260
+ } else {
2261
+ affectedModules.add(referencingModule);
2262
+ }
2263
+ const memCache = new WeakTupleMap();
2264
+ const cache = moduleMemCacheCache.get(module);
2265
+ cache.memCache = memCache;
2266
+ moduleMemCaches.set(referencingModule, memCache);
2267
+ }
2268
+ }
2269
+ for (const module of directOnlyAffectModules) affectedModules.add(module);
2270
+ this.logger.log(
2271
+ `${Math.round(
2272
+ (100 * (affectedModules.size + infectedModules.size)) /
2273
+ this.modules.size
2274
+ )}% (${affectedModules.size} affected + ${
2275
+ infectedModules.size
2276
+ } infected of ${
2277
+ this.modules.size
2278
+ }) modules flagged as affected (${statNew} new modules, ${statChanged} changed, ${statUnchanged} unchanged, ${statWithoutHash} without hash)`
2279
+ );
2280
+ }
2281
+
2014
2282
  finish(callback) {
2015
2283
  this.factorizeQueue.clear();
2016
2284
  if (this.profile) {
@@ -2191,17 +2459,29 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2191
2459
  );
2192
2460
  this.logger.timeEnd("finish module profiles");
2193
2461
  }
2462
+ this.logger.time("compute affected modules");
2463
+ this._computeAffectedModules(this.modules);
2464
+ this.logger.timeEnd("compute affected modules");
2194
2465
  this.logger.time("finish modules");
2195
- const { modules } = this;
2466
+ const { modules, moduleMemCaches } = this;
2196
2467
  this.hooks.finishModules.callAsync(modules, err => {
2197
2468
  this.logger.timeEnd("finish modules");
2198
2469
  if (err) return callback(err);
2199
2470
 
2200
2471
  // extract warnings and errors from modules
2472
+ this.moduleGraph.freeze("dependency errors");
2473
+ // TODO keep a cacheToken (= {}) for each module in the graph
2474
+ // create a new one per compilation and flag all updated files
2475
+ // and parents with it
2201
2476
  this.logger.time("report dependency errors and warnings");
2202
- this.moduleGraph.freeze();
2203
2477
  for (const module of modules) {
2204
- this.reportDependencyErrorsAndWarnings(module, [module]);
2478
+ // TODO only run for modules with changed cacheToken
2479
+ // global WeakMap<CacheToken, WeakSet<Module>> to keep modules without errors/warnings
2480
+ const memCache = moduleMemCaches && moduleMemCaches.get(module);
2481
+ if (memCache && memCache.get("noWarningsOrErrors")) continue;
2482
+ let hasProblems = this.reportDependencyErrorsAndWarnings(module, [
2483
+ module
2484
+ ]);
2205
2485
  const errors = module.getErrors();
2206
2486
  if (errors !== undefined) {
2207
2487
  for (const error of errors) {
@@ -2209,6 +2489,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2209
2489
  error.module = module;
2210
2490
  }
2211
2491
  this.errors.push(error);
2492
+ hasProblems = true;
2212
2493
  }
2213
2494
  }
2214
2495
  const warnings = module.getWarnings();
@@ -2218,8 +2499,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2218
2499
  warning.module = module;
2219
2500
  }
2220
2501
  this.warnings.push(warning);
2502
+ hasProblems = true;
2221
2503
  }
2222
2504
  }
2505
+ if (!hasProblems && memCache) memCache.set("noWarningsOrErrors", true);
2223
2506
  }
2224
2507
  this.moduleGraph.unfreeze();
2225
2508
  this.logger.timeEnd("report dependency errors and warnings");
@@ -2255,7 +2538,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2255
2538
  this.addModuleQueue.clear();
2256
2539
  return callback(err);
2257
2540
  };
2258
- const chunkGraph = new ChunkGraph(this.moduleGraph);
2541
+ const chunkGraph = new ChunkGraph(
2542
+ this.moduleGraph,
2543
+ this.outputOptions.hashFunction
2544
+ );
2259
2545
  this.chunkGraph = chunkGraph;
2260
2546
 
2261
2547
  for (const module of this.modules) {
@@ -2273,7 +2559,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2273
2559
 
2274
2560
  this.logger.time("create chunks");
2275
2561
  this.hooks.beforeChunks.call();
2276
- this.moduleGraph.freeze();
2562
+ this.moduleGraph.freeze("seal");
2277
2563
  /** @type {Map<Entrypoint, Module[]>} */
2278
2564
  const chunkGraphInit = new Map();
2279
2565
  for (const [name, { dependencies, includeDependencies, options }] of this
@@ -2573,9 +2859,10 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2573
2859
  /**
2574
2860
  * @param {Module} module module to report from
2575
2861
  * @param {DependenciesBlock[]} blocks blocks to report from
2576
- * @returns {void}
2862
+ * @returns {boolean} true, when it has warnings or errors
2577
2863
  */
2578
2864
  reportDependencyErrorsAndWarnings(module, blocks) {
2865
+ let hasProblems = false;
2579
2866
  for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
2580
2867
  const block = blocks[indexBlock];
2581
2868
  const dependencies = block.dependencies;
@@ -2590,6 +2877,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2590
2877
 
2591
2878
  const warning = new ModuleDependencyWarning(module, w, d.loc);
2592
2879
  this.warnings.push(warning);
2880
+ hasProblems = true;
2593
2881
  }
2594
2882
  }
2595
2883
  const errors = d.getErrors(this.moduleGraph);
@@ -2599,17 +2887,22 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2599
2887
 
2600
2888
  const error = new ModuleDependencyError(module, e, d.loc);
2601
2889
  this.errors.push(error);
2890
+ hasProblems = true;
2602
2891
  }
2603
2892
  }
2604
2893
  }
2605
2894
 
2606
- this.reportDependencyErrorsAndWarnings(module, block.blocks);
2895
+ if (this.reportDependencyErrorsAndWarnings(module, block.blocks))
2896
+ hasProblems = true;
2607
2897
  }
2898
+ return hasProblems;
2608
2899
  }
2609
2900
 
2610
2901
  codeGeneration(callback) {
2611
2902
  const { chunkGraph } = this;
2612
- this.codeGenerationResults = new CodeGenerationResults();
2903
+ this.codeGenerationResults = new CodeGenerationResults(
2904
+ this.outputOptions.hashFunction
2905
+ );
2613
2906
  /** @type {{module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}[]} */
2614
2907
  const jobs = [];
2615
2908
  for (const module of this.modules) {
@@ -2790,12 +3083,40 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2790
3083
  chunkGraphEntries = this._getChunkGraphEntries()
2791
3084
  } = {}) {
2792
3085
  const context = { chunkGraph, codeGenerationResults };
3086
+ const { moduleMemCaches } = this;
3087
+ this.logger.time("runtime requirements.modules");
2793
3088
  const additionalModuleRuntimeRequirements =
2794
3089
  this.hooks.additionalModuleRuntimeRequirements;
2795
3090
  const runtimeRequirementInModule = this.hooks.runtimeRequirementInModule;
2796
3091
  for (const module of modules) {
2797
3092
  if (chunkGraph.getNumberOfModuleChunks(module) > 0) {
3093
+ const memCache =
3094
+ moduleMemCaches &&
3095
+ // modules with async blocks depend on the chunk graph and can't be cached that way
3096
+ module.blocks.length === 0 &&
3097
+ moduleMemCaches.get(module);
3098
+ /** @type {RuntimeSpecMap<Set<string>>} */
3099
+ const moduleRuntimeRequirementsMemCache =
3100
+ memCache &&
3101
+ memCache.provide(
3102
+ "moduleRuntimeRequirements",
3103
+ () => new RuntimeSpecMap()
3104
+ );
2798
3105
  for (const runtime of chunkGraph.getModuleRuntimes(module)) {
3106
+ if (moduleRuntimeRequirementsMemCache) {
3107
+ const cached = moduleRuntimeRequirementsMemCache.get(runtime);
3108
+ if (cached !== undefined) {
3109
+ if (cached !== null) {
3110
+ chunkGraph.addModuleRuntimeRequirements(
3111
+ module,
3112
+ runtime,
3113
+ cached,
3114
+ false
3115
+ );
3116
+ }
3117
+ continue;
3118
+ }
3119
+ }
2799
3120
  let set;
2800
3121
  const runtimeRequirements =
2801
3122
  codeGenerationResults.getRuntimeRequirements(module, runtime);
@@ -2804,6 +3125,9 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2804
3125
  } else if (additionalModuleRuntimeRequirements.isUsed()) {
2805
3126
  set = new Set();
2806
3127
  } else {
3128
+ if (moduleRuntimeRequirementsMemCache) {
3129
+ moduleRuntimeRequirementsMemCache.set(runtime, null);
3130
+ }
2807
3131
  continue;
2808
3132
  }
2809
3133
  additionalModuleRuntimeRequirements.call(module, set, context);
@@ -2812,11 +3136,29 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2812
3136
  const hook = runtimeRequirementInModule.get(r);
2813
3137
  if (hook !== undefined) hook.call(module, set, context);
2814
3138
  }
2815
- chunkGraph.addModuleRuntimeRequirements(module, runtime, set);
3139
+ if (set.size === 0) {
3140
+ if (moduleRuntimeRequirementsMemCache) {
3141
+ moduleRuntimeRequirementsMemCache.set(runtime, null);
3142
+ }
3143
+ } else {
3144
+ if (moduleRuntimeRequirementsMemCache) {
3145
+ moduleRuntimeRequirementsMemCache.set(runtime, set);
3146
+ chunkGraph.addModuleRuntimeRequirements(
3147
+ module,
3148
+ runtime,
3149
+ set,
3150
+ false
3151
+ );
3152
+ } else {
3153
+ chunkGraph.addModuleRuntimeRequirements(module, runtime, set);
3154
+ }
3155
+ }
2816
3156
  }
2817
3157
  }
2818
3158
  }
3159
+ this.logger.timeEnd("runtime requirements.modules");
2819
3160
 
3161
+ this.logger.time("runtime requirements.chunks");
2820
3162
  for (const chunk of chunks) {
2821
3163
  const set = new Set();
2822
3164
  for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
@@ -2834,7 +3176,9 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2834
3176
 
2835
3177
  chunkGraph.addChunkRuntimeRequirements(chunk, set);
2836
3178
  }
3179
+ this.logger.timeEnd("runtime requirements.chunks");
2837
3180
 
3181
+ this.logger.time("runtime requirements.entries");
2838
3182
  for (const treeEntry of chunkGraphEntries) {
2839
3183
  const set = new Set();
2840
3184
  for (const chunk of treeEntry.getAllReferencedChunks()) {
@@ -2857,6 +3201,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2857
3201
 
2858
3202
  chunkGraph.addTreeRuntimeRequirements(treeEntry, set);
2859
3203
  }
3204
+ this.logger.timeEnd("runtime requirements.entries");
2860
3205
  }
2861
3206
 
2862
3207
  // TODO webpack 6 make chunkGraph argument non-optional
@@ -3201,12 +3546,35 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
3201
3546
 
3202
3547
  createModuleHashes() {
3203
3548
  let statModulesHashed = 0;
3204
- const { chunkGraph, runtimeTemplate } = this;
3549
+ let statModulesFromCache = 0;
3550
+ const { chunkGraph, runtimeTemplate, moduleMemCaches } = this;
3205
3551
  const { hashFunction, hashDigest, hashDigestLength } = this.outputOptions;
3206
3552
  for (const module of this.modules) {
3553
+ const memCache =
3554
+ moduleMemCaches &&
3555
+ // modules with async blocks depend on the chunk graph and can't be cached that way
3556
+ module.blocks.length === 0 &&
3557
+ moduleMemCaches.get(module);
3558
+ /** @type {RuntimeSpecMap<string>} */
3559
+ const moduleHashesMemCache =
3560
+ memCache &&
3561
+ memCache.provide("moduleHashes", () => new RuntimeSpecMap());
3207
3562
  for (const runtime of chunkGraph.getModuleRuntimes(module)) {
3563
+ if (moduleHashesMemCache) {
3564
+ const digest = moduleHashesMemCache.get(runtime);
3565
+ if (digest !== undefined) {
3566
+ chunkGraph.setModuleHashes(
3567
+ module,
3568
+ runtime,
3569
+ digest,
3570
+ digest.substr(0, hashDigestLength)
3571
+ );
3572
+ statModulesFromCache++;
3573
+ continue;
3574
+ }
3575
+ }
3208
3576
  statModulesHashed++;
3209
- this._createModuleHash(
3577
+ const digest = this._createModuleHash(
3210
3578
  module,
3211
3579
  chunkGraph,
3212
3580
  runtime,
@@ -3215,11 +3583,16 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
3215
3583
  hashDigest,
3216
3584
  hashDigestLength
3217
3585
  );
3586
+ if (moduleHashesMemCache) {
3587
+ moduleHashesMemCache.set(runtime, digest);
3588
+ }
3218
3589
  }
3219
3590
  }
3220
3591
  this.logger.log(
3221
- `${statModulesHashed} modules hashed (${
3222
- Math.round((100 * statModulesHashed) / this.modules.size) / 100
3592
+ `${statModulesHashed} modules hashed, ${statModulesFromCache} from cache (${
3593
+ Math.round(
3594
+ (100 * (statModulesHashed + statModulesFromCache)) / this.modules.size
3595
+ ) / 100
3223
3596
  } variants per module in average)`
3224
3597
  );
3225
3598
  }
@@ -4071,7 +4444,10 @@ This prevents using hashes of each other and should be avoided.`);
4071
4444
  if (err) return callback(err);
4072
4445
 
4073
4446
  // Create new chunk graph, chunk and entrypoint for the build time execution
4074
- const chunkGraph = new ChunkGraph(this.moduleGraph);
4447
+ const chunkGraph = new ChunkGraph(
4448
+ this.moduleGraph,
4449
+ this.outputOptions.hashFunction
4450
+ );
4075
4451
  const runtime = "build time";
4076
4452
  const { hashFunction, hashDigest, hashDigestLength } =
4077
4453
  this.outputOptions;
@@ -4114,7 +4490,9 @@ This prevents using hashes of each other and should be avoided.`);
4114
4490
  );
4115
4491
  }
4116
4492
 
4117
- const codeGenerationResults = new CodeGenerationResults();
4493
+ const codeGenerationResults = new CodeGenerationResults(
4494
+ this.outputOptions.hashFunction
4495
+ );
4118
4496
  /** @type {WebpackError[]} */
4119
4497
  const errors = [];
4120
4498
  /**
@@ -4418,6 +4796,33 @@ This prevents using hashes of each other and should be avoided.`);
4418
4796
  }
4419
4797
  }
4420
4798
 
4799
+ /**
4800
+ * @typedef {Object} FactorizeModuleOptions
4801
+ * @property {ModuleProfile} currentProfile
4802
+ * @property {ModuleFactory} factory
4803
+ * @property {Dependency[]} dependencies
4804
+ * @property {boolean=} factoryResult return full ModuleFactoryResult instead of only module
4805
+ * @property {Module | null} originModule
4806
+ * @property {Partial<ModuleFactoryCreateDataContextInfo>=} contextInfo
4807
+ * @property {string=} context
4808
+ */
4809
+
4810
+ /**
4811
+ * @param {FactorizeModuleOptions} options options object
4812
+ * @param {ModuleCallback | ModuleFactoryResultCallback} callback callback
4813
+ * @returns {void}
4814
+ */
4815
+
4816
+ // Workaround for typescript as it doesn't support function overloading in jsdoc within a class
4817
+ Compilation.prototype.factorizeModule = /** @type {{
4818
+ (options: FactorizeModuleOptions & { factoryResult?: false }, callback: ModuleCallback): void;
4819
+ (options: FactorizeModuleOptions & { factoryResult: true }, callback: ModuleFactoryResultCallback): void;
4820
+ }} */ (
4821
+ function (options, callback) {
4822
+ this.factorizeQueue.add(options, callback);
4823
+ }
4824
+ );
4825
+
4421
4826
  // Hide from typescript
4422
4827
  const compilationPrototype = Compilation.prototype;
4423
4828