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

@@ -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");
@@ -38,7 +39,6 @@ const {
38
39
  tryRunOrWebpackError
39
40
  } = require("./HookWebpackError");
40
41
  const MainTemplate = require("./MainTemplate");
41
- const MemCache = require("./MemCache");
42
42
  const Module = require("./Module");
43
43
  const ModuleDependencyError = require("./ModuleDependencyError");
44
44
  const ModuleDependencyWarning = require("./ModuleDependencyWarning");
@@ -61,6 +61,7 @@ const { equals: arrayEquals } = require("./util/ArrayHelpers");
61
61
  const AsyncQueue = require("./util/AsyncQueue");
62
62
  const LazySet = require("./util/LazySet");
63
63
  const { provide } = require("./util/MapHelpers");
64
+ const WeakTupleMap = require("./util/WeakTupleMap");
64
65
  const { cachedCleverMerge } = require("./util/cleverMerge");
65
66
  const {
66
67
  compareLocations,
@@ -92,8 +93,8 @@ const { isSourceEqual } = require("./util/source");
92
93
  /** @typedef {import("./CacheFacade")} CacheFacade */
93
94
  /** @typedef {import("./ChunkGroup").ChunkGroupOptions} ChunkGroupOptions */
94
95
  /** @typedef {import("./Compiler")} Compiler */
96
+ /** @typedef {import("./Compiler").CompilationParams} CompilationParams */
95
97
  /** @typedef {import("./DependenciesBlock")} DependenciesBlock */
96
- /** @typedef {import("./Dependency")} Dependency */
97
98
  /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
98
99
  /** @typedef {import("./Dependency").ReferencedExport} ReferencedExport */
99
100
  /** @typedef {import("./DependencyTemplate")} DependencyTemplate */
@@ -101,6 +102,7 @@ const { isSourceEqual } = require("./util/source");
101
102
  /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
102
103
  /** @typedef {import("./ModuleFactory")} ModuleFactory */
103
104
  /** @typedef {import("./ModuleFactory").ModuleFactoryCreateDataContextInfo} ModuleFactoryCreateDataContextInfo */
105
+ /** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
104
106
  /** @typedef {import("./RequestShortener")} RequestShortener */
105
107
  /** @typedef {import("./RuntimeModule")} RuntimeModule */
106
108
  /** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */
@@ -125,6 +127,20 @@ const { isSourceEqual } = require("./util/source");
125
127
  * @returns {void}
126
128
  */
127
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
+
128
144
  /**
129
145
  * @callback ExecuteModuleCallback
130
146
  * @param {WebpackError=} err
@@ -400,12 +416,19 @@ const byLocation = compareSelect(err => err.loc, compareLocations);
400
416
 
401
417
  const compareErrors = concatComparators(byModule, byLocation, byMessage);
402
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
+
403
425
  class Compilation {
404
426
  /**
405
427
  * Creates an instance of Compilation.
406
428
  * @param {Compiler} compiler the compiler which created the compilation
429
+ * @param {CompilationParams} params the compilation parameters
407
430
  */
408
- constructor(compiler) {
431
+ constructor(compiler, params) {
409
432
  const getNormalModuleLoader = () => deprecatedNormalModuleLoaderHook(this);
410
433
  /** @typedef {{ additionalAssets?: true | Function }} ProcessAssetsAdditionalOptions */
411
434
  /** @type {AsyncSeriesHook<[CompilationAssets], ProcessAssetsAdditionalOptions>} */
@@ -880,6 +903,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
880
903
  /** @type {boolean} */
881
904
  this.profile = (options && options.profile) || false;
882
905
 
906
+ this.params = params;
883
907
  this.mainTemplate = new MainTemplate(this.outputOptions, this);
884
908
  this.chunkTemplate = new ChunkTemplate(this.outputOptions, this);
885
909
  this.runtimeTemplate = new RuntimeTemplate(
@@ -893,9 +917,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
893
917
  };
894
918
  defineRemovedModuleTemplates(this.moduleTemplates);
895
919
 
896
- /** @type {MemCache | undefined} */
897
- this.memCache = undefined;
898
- /** @type {WeakMap<Module, MemCache> | undefined} */
920
+ /** @type {WeakMap<Module, WeakTupleMap<any, any>> | undefined} */
899
921
  this.moduleMemCaches = undefined;
900
922
  this.moduleGraph = new ModuleGraph();
901
923
  /** @type {ChunkGraph} */
@@ -916,7 +938,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
916
938
  getKey: module => module.identifier(),
917
939
  processor: this._addModule.bind(this)
918
940
  });
919
- /** @type {AsyncQueue<FactorizeModuleOptions, string, Module>} */
941
+ /** @type {AsyncQueue<FactorizeModuleOptions, string, Module | ModuleFactoryResult>} */
920
942
  this.factorizeQueue = new AsyncQueue({
921
943
  name: "factorize",
922
944
  parent: this.addModuleQueue,
@@ -999,6 +1021,8 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
999
1021
  this.usedModuleIds = null;
1000
1022
  /** @type {boolean} */
1001
1023
  this.needAdditionalPass = false;
1024
+ /** @type {Set<Module>} */
1025
+ this._restoredUnsafeCacheEntries = new Set();
1002
1026
  /** @type {WeakSet<Module>} */
1003
1027
  this.builtModules = new WeakSet();
1004
1028
  /** @type {WeakSet<Module>} */
@@ -1031,6 +1055,11 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1031
1055
  this._modulesCache = this.getCache("Compilation/modules");
1032
1056
  this._assetsCache = this.getCache("Compilation/assets");
1033
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;
1034
1063
  }
1035
1064
 
1036
1065
  getStats() {
@@ -1415,12 +1444,44 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1415
1444
  /** @type {Dependency[]} */
1416
1445
  let listCacheValue;
1417
1446
 
1447
+ const unsafeRestoredModules = new Set();
1448
+
1418
1449
  /**
1419
1450
  * @param {Dependency} dep dependency
1420
1451
  * @returns {void}
1421
1452
  */
1422
1453
  const processDependency = dep => {
1423
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
+ }
1424
1485
  const resourceIdent = dep.getResourceIdentifier();
1425
1486
  if (resourceIdent !== undefined && resourceIdent !== null) {
1426
1487
  const category = dep.category;
@@ -1504,7 +1565,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1504
1565
  return callback(e);
1505
1566
  }
1506
1567
 
1507
- if (sortedDependencies.length === 0) {
1568
+ if (sortedDependencies.length === 0 && unsafeRestoredModules.size === 0) {
1508
1569
  callback();
1509
1570
  return;
1510
1571
  }
@@ -1512,27 +1573,78 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1512
1573
  // This is nested so we need to allow one additional task
1513
1574
  this.processDependenciesQueue.increaseParallelism();
1514
1575
 
1515
- asyncLib.forEach(
1516
- sortedDependencies,
1517
- (item, callback) => {
1518
- this.handleModuleCreation(item, err => {
1519
- // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
1520
- // errors are created inside closures that keep a reference to the Compilation, so errors are
1521
- // leaking the Compilation object.
1522
- if (err && this.bail) {
1523
- // eslint-disable-next-line no-self-assign
1524
- err.stack = err.stack;
1525
- return callback(err);
1526
- }
1527
- callback();
1528
- });
1529
- },
1530
- err => {
1531
- 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
+ };
1532
1589
 
1533
- return callback(err);
1534
- }
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
1535
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);
1536
1648
  }
1537
1649
 
1538
1650
  /**
@@ -1572,12 +1684,27 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1572
1684
  currentProfile,
1573
1685
  factory,
1574
1686
  dependencies,
1687
+ factoryResult: true,
1575
1688
  originModule,
1576
1689
  contextInfo,
1577
1690
  context
1578
1691
  },
1579
- (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
+ };
1580
1706
  if (err) {
1707
+ if (factoryResult) applyFactoryResultDependencies();
1581
1708
  if (dependencies.every(d => d.optional)) {
1582
1709
  this.warnings.push(err);
1583
1710
  return callback();
@@ -1587,7 +1714,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1587
1714
  }
1588
1715
  }
1589
1716
 
1717
+ const newModule = factoryResult.module;
1718
+
1590
1719
  if (!newModule) {
1720
+ applyFactoryResultDependencies();
1591
1721
  return callback();
1592
1722
  }
1593
1723
 
@@ -1597,6 +1727,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1597
1727
 
1598
1728
  this.addModule(newModule, (err, module) => {
1599
1729
  if (err) {
1730
+ applyFactoryResultDependencies();
1600
1731
  if (!err.module) {
1601
1732
  err.module = module;
1602
1733
  }
@@ -1605,13 +1736,37 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1605
1736
  return callback(err);
1606
1737
  }
1607
1738
 
1608
- for (let i = 0; i < dependencies.length; i++) {
1609
- const dependency = dependencies[i];
1610
- moduleGraph.setResolvedModule(
1611
- connectOrigin ? originModule : null,
1612
- dependency,
1613
- module
1614
- );
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
+ }
1615
1770
  }
1616
1771
 
1617
1772
  moduleGraph.setIssuerIfUnset(
@@ -1629,99 +1784,89 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1629
1784
  }
1630
1785
  }
1631
1786
 
1632
- // Check for cycles when build is trigger inside another build
1633
- let creatingModuleDuringBuildSet = undefined;
1634
- if (!recursive && this.buildQueue.isProcessing(originModule)) {
1635
- // Track build dependency
1636
- creatingModuleDuringBuildSet =
1637
- this.creatingModuleDuringBuild.get(originModule);
1638
- if (creatingModuleDuringBuildSet === undefined) {
1639
- creatingModuleDuringBuildSet = new Set();
1640
- this.creatingModuleDuringBuild.set(
1641
- originModule,
1642
- creatingModuleDuringBuildSet
1643
- );
1644
- }
1645
- creatingModuleDuringBuildSet.add(originModule);
1646
-
1647
- // When building is blocked by another module
1648
- // search for a cycle, cancel the cycle by throwing
1649
- // an error (otherwise this would deadlock)
1650
- const blockReasons = this.creatingModuleDuringBuild.get(module);
1651
- if (blockReasons !== undefined) {
1652
- const set = new Set(blockReasons);
1653
- for (const item of set) {
1654
- const blockReasons = this.creatingModuleDuringBuild.get(item);
1655
- if (blockReasons !== undefined) {
1656
- for (const m of blockReasons) {
1657
- if (m === module) {
1658
- return callback(new BuildCycleError(module));
1659
- }
1660
- set.add(m);
1661
- }
1662
- }
1663
- }
1664
- }
1665
- }
1787
+ this._handleModuleBuildAndDependencies(
1788
+ originModule,
1789
+ module,
1790
+ recursive,
1791
+ callback
1792
+ );
1793
+ });
1794
+ }
1795
+ );
1796
+ }
1666
1797
 
1667
- this.buildModule(module, err => {
1668
- if (creatingModuleDuringBuildSet !== undefined) {
1669
- creatingModuleDuringBuildSet.delete(module);
1670
- }
1671
- if (err) {
1672
- if (!err.module) {
1673
- 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));
1674
1826
  }
1675
- this.errors.push(err);
1676
-
1677
- return callback(err);
1827
+ set.add(m);
1678
1828
  }
1829
+ }
1830
+ }
1831
+ }
1832
+ }
1679
1833
 
1680
- if (!recursive) {
1681
- this.processModuleDependenciesNonRecursive(module);
1682
- callback(null, module);
1683
- return;
1684
- }
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);
1685
1843
 
1686
- // This avoids deadlocks for circular dependencies
1687
- if (this.processDependenciesQueue.isProcessing(module)) {
1688
- return callback();
1689
- }
1844
+ return callback(err);
1845
+ }
1690
1846
 
1691
- this.processModuleDependencies(module, err => {
1692
- if (err) {
1693
- return callback(err);
1694
- }
1695
- callback(null, module);
1696
- });
1697
- });
1698
- });
1847
+ if (!recursive) {
1848
+ this.processModuleDependenciesNonRecursive(module);
1849
+ callback(null, module);
1850
+ return;
1699
1851
  }
1700
- );
1701
- }
1702
1852
 
1703
- /**
1704
- * @typedef {Object} FactorizeModuleOptions
1705
- * @property {ModuleProfile} currentProfile
1706
- * @property {ModuleFactory} factory
1707
- * @property {Dependency[]} dependencies
1708
- * @property {Module | null} originModule
1709
- * @property {Partial<ModuleFactoryCreateDataContextInfo>=} contextInfo
1710
- * @property {string=} context
1711
- */
1853
+ // This avoids deadlocks for circular dependencies
1854
+ if (this.processDependenciesQueue.isProcessing(module)) {
1855
+ return callback();
1856
+ }
1712
1857
 
1713
- /**
1714
- * @param {FactorizeModuleOptions} options options object
1715
- * @param {ModuleCallback} callback callback
1716
- * @returns {void}
1717
- */
1718
- factorizeModule(options, callback) {
1719
- this.factorizeQueue.add(options, callback);
1858
+ this.processModuleDependencies(module, err => {
1859
+ if (err) {
1860
+ return callback(err);
1861
+ }
1862
+ callback(null, module);
1863
+ });
1864
+ });
1720
1865
  }
1721
1866
 
1722
1867
  /**
1723
1868
  * @param {FactorizeModuleOptions} options options object
1724
- * @param {ModuleCallback} callback callback
1869
+ * @param {ModuleOrFactoryResultCallback} callback callback
1725
1870
  * @returns {void}
1726
1871
  */
1727
1872
  _factorizeModule(
@@ -1730,6 +1875,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1730
1875
  factory,
1731
1876
  dependencies,
1732
1877
  originModule,
1878
+ factoryResult,
1733
1879
  contextInfo,
1734
1880
  context
1735
1881
  },
@@ -1763,16 +1909,21 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1763
1909
  module: result
1764
1910
  };
1765
1911
  }
1766
- const { fileDependencies, contextDependencies, missingDependencies } =
1767
- result;
1768
- if (fileDependencies) {
1769
- this.fileDependencies.addAll(fileDependencies);
1770
- }
1771
- if (contextDependencies) {
1772
- this.contextDependencies.addAll(contextDependencies);
1773
- }
1774
- if (missingDependencies) {
1775
- 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
+ }
1776
1927
  }
1777
1928
  }
1778
1929
  if (err) {
@@ -1781,20 +1932,17 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1781
1932
  err,
1782
1933
  dependencies.map(d => d.loc).filter(Boolean)[0]
1783
1934
  );
1784
- return callback(notFoundError);
1935
+ return callback(notFoundError, factoryResult ? result : undefined);
1785
1936
  }
1786
1937
  if (!result) {
1787
1938
  return callback();
1788
1939
  }
1789
- const newModule = result.module;
1790
- if (!newModule) {
1791
- return callback();
1792
- }
1940
+
1793
1941
  if (currentProfile !== undefined) {
1794
1942
  currentProfile.markFactoryEnd();
1795
1943
  }
1796
1944
 
1797
- callback(null, newModule);
1945
+ callback(null, factoryResult ? result : result.module);
1798
1946
  }
1799
1947
  );
1800
1948
  }
@@ -2020,9 +2168,11 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2020
2168
  _computeAffectedModules(modules) {
2021
2169
  const moduleMemCacheCache = this.compiler.moduleMemCaches;
2022
2170
  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;
2171
+ if (!this.moduleMemCaches) {
2172
+ this.moduleMemCaches = new WeakMap();
2173
+ this.moduleGraph.setModuleMemCaches(this.moduleMemCaches);
2174
+ }
2175
+ const { moduleGraph, moduleMemCaches } = this;
2026
2176
  const affectedModules = new Set();
2027
2177
  const infectedModules = new Set();
2028
2178
  let statNew = 0;
@@ -2035,6 +2185,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2035
2185
  const cachedMemCache = moduleMemCacheCache.get(module);
2036
2186
  if (cachedMemCache === undefined) {
2037
2187
  // create a new entry
2188
+ const memCache = new WeakTupleMap();
2038
2189
  moduleMemCacheCache.set(module, {
2039
2190
  hash: hash,
2040
2191
  memCache
@@ -2048,6 +2199,11 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2048
2199
  statUnchanged++;
2049
2200
  } else {
2050
2201
  // use a new one
2202
+ const memCache = new WeakTupleMap();
2203
+ moduleMemCacheCache.set(module, {
2204
+ hash: hash,
2205
+ memCache
2206
+ });
2051
2207
  moduleMemCaches.set(module, memCache);
2052
2208
  affectedModules.add(module);
2053
2209
  cachedMemCache.hash = hash;
@@ -2059,25 +2215,58 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2059
2215
  statWithoutHash++;
2060
2216
  }
2061
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();
2062
2230
  for (const module of infectedModules) {
2063
- for (const referencingModule of moduleGraph
2064
- .getIncomingConnectionsByOriginModule(module)
2065
- .keys()) {
2231
+ for (const [
2232
+ referencingModule,
2233
+ connections
2234
+ ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
2235
+ if (!referencingModule) continue;
2066
2236
  if (infectedModules.has(referencingModule)) continue;
2067
- infectedModules.add(referencingModule);
2237
+ const type = reduceAffectType(connections);
2238
+ if (!type) continue;
2239
+ if (type === true) {
2240
+ directOnlyInfectedModules.add(referencingModule);
2241
+ } else {
2242
+ infectedModules.add(referencingModule);
2243
+ }
2068
2244
  }
2069
2245
  }
2246
+ for (const module of directOnlyInfectedModules) infectedModules.add(module);
2247
+ const directOnlyAffectModules = new Set();
2070
2248
  for (const module of affectedModules) {
2071
- for (const referencingModule of moduleGraph
2072
- .getIncomingConnectionsByOriginModule(module)
2073
- .keys()) {
2249
+ for (const [
2250
+ referencingModule,
2251
+ connections
2252
+ ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
2074
2253
  if (!referencingModule) continue;
2075
2254
  if (infectedModules.has(referencingModule)) continue;
2076
2255
  if (affectedModules.has(referencingModule)) continue;
2077
- affectedModules.add(referencingModule);
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;
2078
2266
  moduleMemCaches.set(referencingModule, memCache);
2079
2267
  }
2080
2268
  }
2269
+ for (const module of directOnlyAffectModules) affectedModules.add(module);
2081
2270
  this.logger.log(
2082
2271
  `${Math.round(
2083
2272
  (100 * (affectedModules.size + infectedModules.size)) /
@@ -2280,7 +2469,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2280
2469
  if (err) return callback(err);
2281
2470
 
2282
2471
  // extract warnings and errors from modules
2283
- this.moduleGraph.freeze();
2472
+ this.moduleGraph.freeze("dependency errors");
2284
2473
  // TODO keep a cacheToken (= {}) for each module in the graph
2285
2474
  // create a new one per compilation and flag all updated files
2286
2475
  // and parents with it
@@ -2289,7 +2478,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2289
2478
  // TODO only run for modules with changed cacheToken
2290
2479
  // global WeakMap<CacheToken, WeakSet<Module>> to keep modules without errors/warnings
2291
2480
  const memCache = moduleMemCaches && moduleMemCaches.get(module);
2292
- if (memCache && memCache.get(module, "noWarningsOrErrors")) continue;
2481
+ if (memCache && memCache.get("noWarningsOrErrors")) continue;
2293
2482
  let hasProblems = this.reportDependencyErrorsAndWarnings(module, [
2294
2483
  module
2295
2484
  ]);
@@ -2313,8 +2502,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2313
2502
  hasProblems = true;
2314
2503
  }
2315
2504
  }
2316
- if (!hasProblems && memCache)
2317
- memCache.set(module, "noWarningsOrErrors", true);
2505
+ if (!hasProblems && memCache) memCache.set("noWarningsOrErrors", true);
2318
2506
  }
2319
2507
  this.moduleGraph.unfreeze();
2320
2508
  this.logger.timeEnd("report dependency errors and warnings");
@@ -2371,7 +2559,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2371
2559
 
2372
2560
  this.logger.time("create chunks");
2373
2561
  this.hooks.beforeChunks.call();
2374
- this.moduleGraph.freeze();
2562
+ this.moduleGraph.freeze("seal");
2375
2563
  /** @type {Map<Entrypoint, Module[]>} */
2376
2564
  const chunkGraphInit = new Map();
2377
2565
  for (const [name, { dependencies, includeDependencies, options }] of this
@@ -2911,7 +3099,6 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
2911
3099
  const moduleRuntimeRequirementsMemCache =
2912
3100
  memCache &&
2913
3101
  memCache.provide(
2914
- module,
2915
3102
  "moduleRuntimeRequirements",
2916
3103
  () => new RuntimeSpecMap()
2917
3104
  );
@@ -3371,7 +3558,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
3371
3558
  /** @type {RuntimeSpecMap<string>} */
3372
3559
  const moduleHashesMemCache =
3373
3560
  memCache &&
3374
- memCache.provide(module, "moduleHashes", () => new RuntimeSpecMap());
3561
+ memCache.provide("moduleHashes", () => new RuntimeSpecMap());
3375
3562
  for (const runtime of chunkGraph.getModuleRuntimes(module)) {
3376
3563
  if (moduleHashesMemCache) {
3377
3564
  const digest = moduleHashesMemCache.get(runtime);
@@ -4609,6 +4796,33 @@ This prevents using hashes of each other and should be avoided.`);
4609
4796
  }
4610
4797
  }
4611
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
+
4612
4826
  // Hide from typescript
4613
4827
  const compilationPrototype = Compilation.prototype;
4614
4828