ChunkGraph.js 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const util = require("util");
  7. const Entrypoint = require("./Entrypoint");
  8. const ModuleGraphConnection = require("./ModuleGraphConnection");
  9. const { DEFAULTS } = require("./config/defaults");
  10. const { first } = require("./util/SetHelpers");
  11. const SortableSet = require("./util/SortableSet");
  12. const {
  13. compareIds,
  14. compareIterables,
  15. compareModulesById,
  16. compareModulesByIdentifier,
  17. compareSelect,
  18. concatComparators
  19. } = require("./util/comparators");
  20. const createHash = require("./util/createHash");
  21. const findGraphRoots = require("./util/findGraphRoots");
  22. const {
  23. RuntimeSpecMap,
  24. RuntimeSpecSet,
  25. forEachRuntime,
  26. mergeRuntime,
  27. runtimeToString
  28. } = require("./util/runtime");
  29. /** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
  30. /** @typedef {import("./Chunk")} Chunk */
  31. /** @typedef {import("./Chunk").Chunks} Chunks */
  32. /** @typedef {import("./Chunk").Entrypoints} Entrypoints */
  33. /** @typedef {import("./Chunk").ChunkId} ChunkId */
  34. /** @typedef {import("./ChunkGroup")} ChunkGroup */
  35. /** @typedef {import("./Module")} Module */
  36. /** @typedef {import("./Module").SourceType} SourceType */
  37. /** @typedef {import("./Module").SourceTypes} SourceTypes */
  38. /** @typedef {import("./Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
  39. /** @typedef {import("./Module").RuntimeRequirements} RuntimeRequirements */
  40. /** @typedef {import("./ModuleGraph")} ModuleGraph */
  41. /** @typedef {import("./ModuleGraphConnection").ConnectionState} ConnectionState */
  42. /** @typedef {import("./RuntimeModule")} RuntimeModule */
  43. /** @typedef {import("./util/Hash").HashFunction} HashFunction */
  44. /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
  45. /** @type {ReadonlySet<string>} */
  46. const EMPTY_SET = new Set();
  47. const ZERO_BIG_INT = BigInt(0);
  48. const compareModuleIterables = compareIterables(compareModulesByIdentifier);
  49. /** @typedef {(c: Chunk, chunkGraph: ChunkGraph) => boolean} ChunkFilterPredicate */
  50. /** @typedef {(m: Module) => boolean} ModuleFilterPredicate */
  51. /** @typedef {[Module, Entrypoint | undefined]} EntryModuleWithChunkGroup */
  52. /**
  53. * Represents the module hash info runtime component.
  54. * @typedef {object} ChunkSizeOptions
  55. * @property {number=} chunkOverhead constant overhead for a chunk
  56. * @property {number=} entryChunkMultiplicator multiplicator for initial chunks
  57. */
  58. class ModuleHashInfo {
  59. /**
  60. * Creates an instance of ModuleHashInfo.
  61. * @param {string} hash hash
  62. * @param {string} renderedHash rendered hash
  63. */
  64. constructor(hash, renderedHash) {
  65. /** @type {string} */
  66. this.hash = hash;
  67. /** @type {string} */
  68. this.renderedHash = renderedHash;
  69. }
  70. }
  71. /**
  72. * Returns set as array.
  73. * @template T
  74. * @param {SortableSet<T>} set the set
  75. * @returns {T[]} set as array
  76. */
  77. const getArray = (set) => [...set];
  78. /**
  79. * Gets module runtimes.
  80. * @param {SortableChunks} chunks the chunks
  81. * @returns {RuntimeSpecSet} runtimes
  82. */
  83. const getModuleRuntimes = (chunks) => {
  84. const runtimes = new RuntimeSpecSet();
  85. for (const chunk of chunks) {
  86. runtimes.add(chunk.runtime);
  87. }
  88. return runtimes;
  89. };
  90. /**
  91. * Modules by source type.
  92. * @param {SourceTypesByModule | undefined} sourceTypesByModule sourceTypesByModule
  93. * @returns {ModulesBySourceType} modules by source type
  94. */
  95. const modulesBySourceType = (sourceTypesByModule) => (set) => {
  96. /** @typedef {SortableSet<Module>} ModuleSortableSet */
  97. /** @type {Map<SourceType, ModuleSortableSet>} */
  98. const map = new Map();
  99. for (const module of set) {
  100. const sourceTypes =
  101. (sourceTypesByModule && sourceTypesByModule.get(module)) ||
  102. module.getSourceTypes();
  103. for (const sourceType of sourceTypes) {
  104. let innerSet = map.get(sourceType);
  105. if (innerSet === undefined) {
  106. /** @type {ModuleSortableSet} */
  107. innerSet = new SortableSet();
  108. map.set(sourceType, innerSet);
  109. }
  110. innerSet.add(module);
  111. }
  112. }
  113. for (const [key, innerSet] of map) {
  114. // When all modules have the source type, we reuse the original SortableSet
  115. // to benefit from the shared cache (especially for sorting)
  116. if (innerSet.size === set.size) {
  117. map.set(key, set);
  118. }
  119. }
  120. return map;
  121. };
  122. /** @typedef {(set: SortableSet<Module>) => Map<string, SortableSet<Module>>} ModulesBySourceType */
  123. /** @type {ModulesBySourceType} */
  124. const defaultModulesBySourceType = modulesBySourceType(undefined);
  125. /**
  126. * Defines the module set to array function type used by this module.
  127. * @typedef {(set: SortableSet<Module>) => Module[]} ModuleSetToArrayFunction
  128. */
  129. /**
  130. * @template T
  131. * @type {WeakMap<ModuleComparator, ModuleSetToArrayFunction>}
  132. */
  133. const createOrderedArrayFunctionMap = new WeakMap();
  134. /**
  135. * Creates an ordered array function.
  136. * @template T
  137. * @param {ModuleComparator} comparator comparator function
  138. * @returns {ModuleSetToArrayFunction} set as ordered array
  139. */
  140. const createOrderedArrayFunction = (comparator) => {
  141. let fn = createOrderedArrayFunctionMap.get(comparator);
  142. if (fn !== undefined) return fn;
  143. fn = (set) => {
  144. set.sortWith(comparator);
  145. return [...set];
  146. };
  147. createOrderedArrayFunctionMap.set(comparator, fn);
  148. return fn;
  149. };
  150. /**
  151. * Returns the size of the modules.
  152. * @param {Iterable<Module>} modules the modules to get the count/size of
  153. * @returns {number} the size of the modules
  154. */
  155. const getModulesSize = (modules) => {
  156. let size = 0;
  157. for (const module of modules) {
  158. for (const type of module.getSourceTypes()) {
  159. size += module.size(type);
  160. }
  161. }
  162. return size;
  163. };
  164. /** @typedef {Record<string, number>} SizesOfModules */
  165. /**
  166. * Gets modules sizes.
  167. * @param {Iterable<Module>} modules the sortable Set to get the size of
  168. * @returns {SizesOfModules} the sizes of the modules
  169. */
  170. const getModulesSizes = (modules) => {
  171. /** @type {SizesOfModules} */
  172. const sizes = Object.create(null);
  173. for (const module of modules) {
  174. for (const type of module.getSourceTypes()) {
  175. sizes[type] = (sizes[type] || 0) + module.size(type);
  176. }
  177. }
  178. return sizes;
  179. };
  180. /**
  181. * Checks whether this module hash info is available chunk.
  182. * @param {Chunk} a chunk
  183. * @param {Chunk} b chunk
  184. * @returns {boolean} true, if a is always a parent of b
  185. */
  186. const isAvailableChunk = (a, b) => {
  187. const queue = new Set(b.groupsIterable);
  188. for (const chunkGroup of queue) {
  189. if (a.isInGroup(chunkGroup)) continue;
  190. if (chunkGroup.isInitial()) return false;
  191. for (const parent of chunkGroup.parentsIterable) {
  192. queue.add(parent);
  193. }
  194. }
  195. return true;
  196. };
  197. /** @typedef {SortableSet<Chunk>} SortableChunks */
  198. /** @typedef {Set<Chunk>} EntryInChunks */
  199. /** @typedef {Set<Chunk>} RuntimeInChunks */
  200. /** @typedef {string | number} ModuleId */
  201. /** @typedef {RuntimeSpecMap<Set<string>, RuntimeRequirements>} ChunkGraphRuntimeRequirements */
  202. class ChunkGraphModule {
  203. constructor() {
  204. /** @type {SortableChunks} */
  205. this.chunks = new SortableSet();
  206. /** @type {EntryInChunks | undefined} */
  207. this.entryInChunks = undefined;
  208. /** @type {RuntimeInChunks | undefined} */
  209. this.runtimeInChunks = undefined;
  210. /** @type {RuntimeSpecMap<ModuleHashInfo> | undefined} */
  211. this.hashes = undefined;
  212. /** @type {ModuleId | null} */
  213. this.id = null;
  214. /** @type {ChunkGraphRuntimeRequirements | undefined} */
  215. this.runtimeRequirements = undefined;
  216. /** @type {RuntimeSpecMap<string, bigint> | undefined} */
  217. this.graphHashes = undefined;
  218. /** @type {RuntimeSpecMap<string, string> | undefined} */
  219. this.graphHashesWithConnections = undefined;
  220. }
  221. }
  222. /** @typedef {WeakMap<Module, SourceTypes>} SourceTypesByModule */
  223. /** @typedef {Map<Module, Entrypoint>} EntryModules */
  224. class ChunkGraphChunk {
  225. constructor() {
  226. /** @type {SortableSet<Module>} */
  227. this.modules = new SortableSet();
  228. /** @type {SourceTypesByModule | undefined} */
  229. this.sourceTypesByModule = undefined;
  230. /** @type {EntryModules} */
  231. this.entryModules = new Map();
  232. /** @type {SortableSet<RuntimeModule>} */
  233. this.runtimeModules = new SortableSet();
  234. /** @type {Set<RuntimeModule> | undefined} */
  235. this.fullHashModules = undefined;
  236. /** @type {Set<RuntimeModule> | undefined} */
  237. this.dependentHashModules = undefined;
  238. /** @type {RuntimeRequirements | undefined} */
  239. this.runtimeRequirements = undefined;
  240. /** @type {Set<string>} */
  241. this.runtimeRequirementsInTree = new Set();
  242. /** @type {ModulesBySourceType} */
  243. this._modulesBySourceType = defaultModulesBySourceType;
  244. }
  245. }
  246. /** @typedef {string | number} RuntimeId */
  247. /** @typedef {Record<ModuleId, string>} IdToHashMap */
  248. /** @typedef {Record<ChunkId, IdToHashMap>} ChunkModuleHashMap */
  249. /** @typedef {Record<ChunkId, ModuleId[]>} ChunkModuleIdMap */
  250. /** @typedef {Record<ChunkId, boolean>} ChunkConditionMap */
  251. /** @typedef {(a: Module, b: Module) => -1 | 0 | 1} ModuleComparator */
  252. class ChunkGraph {
  253. /**
  254. * Creates an instance of ChunkGraph.
  255. * @param {ModuleGraph} moduleGraph the module graph
  256. * @param {HashFunction} hashFunction the hash function to use
  257. */
  258. constructor(moduleGraph, hashFunction = DEFAULTS.HASH_FUNCTION) {
  259. /**
  260. * @private
  261. * @type {WeakMap<Module, ChunkGraphModule>}
  262. */
  263. this._modules = new WeakMap();
  264. /**
  265. * @private
  266. * @type {WeakMap<Chunk, ChunkGraphChunk>}
  267. */
  268. this._chunks = new WeakMap();
  269. /**
  270. * @private
  271. * @type {WeakMap<AsyncDependenciesBlock, ChunkGroup>}
  272. */
  273. this._blockChunkGroups = new WeakMap();
  274. /**
  275. * @private
  276. * @type {Map<string, RuntimeId>}
  277. */
  278. this._runtimeIds = new Map();
  279. /** @type {ModuleGraph} */
  280. this.moduleGraph = moduleGraph;
  281. this._hashFunction = hashFunction;
  282. this._getGraphRoots = this._getGraphRoots.bind(this);
  283. }
  284. /**
  285. * Get chunk graph module.
  286. * @private
  287. * @param {Module} module the module
  288. * @returns {ChunkGraphModule} internal module
  289. */
  290. _getChunkGraphModule(module) {
  291. let cgm = this._modules.get(module);
  292. if (cgm === undefined) {
  293. cgm = new ChunkGraphModule();
  294. this._modules.set(module, cgm);
  295. }
  296. return cgm;
  297. }
  298. /**
  299. * Get chunk graph chunk.
  300. * @private
  301. * @param {Chunk} chunk the chunk
  302. * @returns {ChunkGraphChunk} internal chunk
  303. */
  304. _getChunkGraphChunk(chunk) {
  305. let cgc = this._chunks.get(chunk);
  306. if (cgc === undefined) {
  307. cgc = new ChunkGraphChunk();
  308. this._chunks.set(chunk, cgc);
  309. }
  310. return cgc;
  311. }
  312. /**
  313. * Returns the graph roots.
  314. * @param {SortableSet<Module>} set the sortable Set to get the roots of
  315. * @returns {Module[]} the graph roots
  316. */
  317. _getGraphRoots(set) {
  318. const { moduleGraph } = this;
  319. return [
  320. ...findGraphRoots(set, (module) => {
  321. /** @type {Set<Module>} */
  322. const set = new Set();
  323. /**
  324. * Adds the provided module to the chunk graph.
  325. * @param {Module} module module
  326. */
  327. const addDependencies = (module) => {
  328. for (const connection of moduleGraph.getOutgoingConnections(module)) {
  329. if (!connection.module) continue;
  330. const activeState = connection.getActiveState(undefined);
  331. if (activeState === false) continue;
  332. if (activeState === ModuleGraphConnection.TRANSITIVE_ONLY) {
  333. addDependencies(connection.module);
  334. continue;
  335. }
  336. set.add(connection.module);
  337. }
  338. };
  339. addDependencies(module);
  340. return set;
  341. })
  342. ].sort(compareModulesByIdentifier);
  343. }
  344. /**
  345. * Connects chunk and module.
  346. * @param {Chunk} chunk the new chunk
  347. * @param {Module} module the module
  348. * @returns {void}
  349. */
  350. connectChunkAndModule(chunk, module) {
  351. const cgm = this._getChunkGraphModule(module);
  352. const cgc = this._getChunkGraphChunk(chunk);
  353. cgm.chunks.add(chunk);
  354. cgc.modules.add(module);
  355. }
  356. /**
  357. * Disconnects chunk and module.
  358. * @param {Chunk} chunk the chunk
  359. * @param {Module} module the module
  360. * @returns {void}
  361. */
  362. disconnectChunkAndModule(chunk, module) {
  363. const cgm = this._getChunkGraphModule(module);
  364. const cgc = this._getChunkGraphChunk(chunk);
  365. cgc.modules.delete(module);
  366. // No need to invalidate cgc._modulesBySourceType because we modified cgc.modules anyway
  367. if (cgc.sourceTypesByModule) cgc.sourceTypesByModule.delete(module);
  368. cgm.chunks.delete(chunk);
  369. }
  370. /**
  371. * Processes the provided chunk.
  372. * @param {Chunk} chunk the chunk which will be disconnected
  373. * @returns {void}
  374. */
  375. disconnectChunk(chunk) {
  376. const cgc = this._getChunkGraphChunk(chunk);
  377. for (const module of cgc.modules) {
  378. const cgm = this._getChunkGraphModule(module);
  379. cgm.chunks.delete(chunk);
  380. }
  381. cgc.modules.clear();
  382. chunk.disconnectFromGroups();
  383. ChunkGraph.clearChunkGraphForChunk(chunk);
  384. }
  385. /**
  386. * Processes the provided chunk.
  387. * @param {Chunk} chunk the chunk
  388. * @param {Iterable<Module>} modules the modules
  389. * @returns {void}
  390. */
  391. attachModules(chunk, modules) {
  392. const cgc = this._getChunkGraphChunk(chunk);
  393. for (const module of modules) {
  394. cgc.modules.add(module);
  395. }
  396. }
  397. /**
  398. * Attach runtime modules.
  399. * @param {Chunk} chunk the chunk
  400. * @param {Iterable<RuntimeModule>} modules the runtime modules
  401. * @returns {void}
  402. */
  403. attachRuntimeModules(chunk, modules) {
  404. const cgc = this._getChunkGraphChunk(chunk);
  405. for (const module of modules) {
  406. cgc.runtimeModules.add(module);
  407. }
  408. }
  409. /**
  410. * Attach full hash modules.
  411. * @param {Chunk} chunk the chunk
  412. * @param {Iterable<RuntimeModule>} modules the modules that require a full hash
  413. * @returns {void}
  414. */
  415. attachFullHashModules(chunk, modules) {
  416. const cgc = this._getChunkGraphChunk(chunk);
  417. if (cgc.fullHashModules === undefined) cgc.fullHashModules = new Set();
  418. for (const module of modules) {
  419. cgc.fullHashModules.add(module);
  420. }
  421. }
  422. /**
  423. * Attach dependent hash modules.
  424. * @param {Chunk} chunk the chunk
  425. * @param {Iterable<RuntimeModule>} modules the modules that require a full hash
  426. * @returns {void}
  427. */
  428. attachDependentHashModules(chunk, modules) {
  429. const cgc = this._getChunkGraphChunk(chunk);
  430. if (cgc.dependentHashModules === undefined) {
  431. cgc.dependentHashModules = new Set();
  432. }
  433. for (const module of modules) {
  434. cgc.dependentHashModules.add(module);
  435. }
  436. }
  437. /**
  438. * Processes the provided old module.
  439. * @param {Module} oldModule the replaced module
  440. * @param {Module} newModule the replacing module
  441. * @returns {void}
  442. */
  443. replaceModule(oldModule, newModule) {
  444. const oldCgm = this._getChunkGraphModule(oldModule);
  445. const newCgm = this._getChunkGraphModule(newModule);
  446. for (const chunk of oldCgm.chunks) {
  447. const cgc = this._getChunkGraphChunk(chunk);
  448. cgc.modules.delete(oldModule);
  449. cgc.modules.add(newModule);
  450. newCgm.chunks.add(chunk);
  451. }
  452. oldCgm.chunks.clear();
  453. if (oldCgm.entryInChunks !== undefined) {
  454. if (newCgm.entryInChunks === undefined) {
  455. newCgm.entryInChunks = new Set();
  456. }
  457. for (const chunk of oldCgm.entryInChunks) {
  458. const cgc = this._getChunkGraphChunk(chunk);
  459. const old = /** @type {Entrypoint} */ (cgc.entryModules.get(oldModule));
  460. /** @type {EntryModules} */
  461. const newEntryModules = new Map();
  462. for (const [m, cg] of cgc.entryModules) {
  463. if (m === oldModule) {
  464. newEntryModules.set(newModule, old);
  465. } else {
  466. newEntryModules.set(m, cg);
  467. }
  468. }
  469. cgc.entryModules = newEntryModules;
  470. newCgm.entryInChunks.add(chunk);
  471. }
  472. oldCgm.entryInChunks = undefined;
  473. }
  474. if (oldCgm.runtimeInChunks !== undefined) {
  475. if (newCgm.runtimeInChunks === undefined) {
  476. newCgm.runtimeInChunks = new Set();
  477. }
  478. for (const chunk of oldCgm.runtimeInChunks) {
  479. const cgc = this._getChunkGraphChunk(chunk);
  480. cgc.runtimeModules.delete(/** @type {RuntimeModule} */ (oldModule));
  481. cgc.runtimeModules.add(/** @type {RuntimeModule} */ (newModule));
  482. newCgm.runtimeInChunks.add(chunk);
  483. if (
  484. cgc.fullHashModules !== undefined &&
  485. cgc.fullHashModules.has(/** @type {RuntimeModule} */ (oldModule))
  486. ) {
  487. cgc.fullHashModules.delete(/** @type {RuntimeModule} */ (oldModule));
  488. cgc.fullHashModules.add(/** @type {RuntimeModule} */ (newModule));
  489. }
  490. if (
  491. cgc.dependentHashModules !== undefined &&
  492. cgc.dependentHashModules.has(/** @type {RuntimeModule} */ (oldModule))
  493. ) {
  494. cgc.dependentHashModules.delete(
  495. /** @type {RuntimeModule} */ (oldModule)
  496. );
  497. cgc.dependentHashModules.add(
  498. /** @type {RuntimeModule} */ (newModule)
  499. );
  500. }
  501. }
  502. oldCgm.runtimeInChunks = undefined;
  503. }
  504. }
  505. /**
  506. * Checks whether this chunk graph is module in chunk.
  507. * @param {Module} module the checked module
  508. * @param {Chunk} chunk the checked chunk
  509. * @returns {boolean} true, if the chunk contains the module
  510. */
  511. isModuleInChunk(module, chunk) {
  512. const cgc = this._getChunkGraphChunk(chunk);
  513. return cgc.modules.has(module);
  514. }
  515. /**
  516. * Checks whether this chunk graph is module in chunk group.
  517. * @param {Module} module the checked module
  518. * @param {ChunkGroup} chunkGroup the checked chunk group
  519. * @returns {boolean} true, if the chunk contains the module
  520. */
  521. isModuleInChunkGroup(module, chunkGroup) {
  522. for (const chunk of chunkGroup.chunks) {
  523. if (this.isModuleInChunk(module, chunk)) return true;
  524. }
  525. return false;
  526. }
  527. /**
  528. * Checks whether this chunk graph is entry module.
  529. * @param {Module} module the checked module
  530. * @returns {boolean} true, if the module is entry of any chunk
  531. */
  532. isEntryModule(module) {
  533. const cgm = this._getChunkGraphModule(module);
  534. return cgm.entryInChunks !== undefined;
  535. }
  536. /**
  537. * Gets module chunks iterable.
  538. * @param {Module} module the module
  539. * @returns {Iterable<Chunk>} iterable of chunks (do not modify)
  540. */
  541. getModuleChunksIterable(module) {
  542. const cgm = this._getChunkGraphModule(module);
  543. return cgm.chunks;
  544. }
  545. /**
  546. * Gets ordered module chunks iterable.
  547. * @param {Module} module the module
  548. * @param {(a: Chunk, b: Chunk) => -1 | 0 | 1} sortFn sort function
  549. * @returns {Iterable<Chunk>} iterable of chunks (do not modify)
  550. */
  551. getOrderedModuleChunksIterable(module, sortFn) {
  552. const cgm = this._getChunkGraphModule(module);
  553. cgm.chunks.sortWith(sortFn);
  554. return cgm.chunks;
  555. }
  556. /**
  557. * Gets module chunks.
  558. * @param {Module} module the module
  559. * @returns {Chunk[]} array of chunks (cached, do not modify)
  560. */
  561. getModuleChunks(module) {
  562. const cgm = this._getChunkGraphModule(module);
  563. return cgm.chunks.getFromCache(getArray);
  564. }
  565. /**
  566. * Gets number of module chunks.
  567. * @param {Module} module the module
  568. * @returns {number} the number of chunk which contain the module
  569. */
  570. getNumberOfModuleChunks(module) {
  571. const cgm = this._getChunkGraphModule(module);
  572. return cgm.chunks.size;
  573. }
  574. /**
  575. * Gets module runtimes.
  576. * @param {Module} module the module
  577. * @returns {RuntimeSpecSet} runtimes
  578. */
  579. getModuleRuntimes(module) {
  580. const cgm = this._getChunkGraphModule(module);
  581. return cgm.chunks.getFromUnorderedCache(getModuleRuntimes);
  582. }
  583. /**
  584. * Gets number of chunk modules.
  585. * @param {Chunk} chunk the chunk
  586. * @returns {number} the number of modules which are contained in this chunk
  587. */
  588. getNumberOfChunkModules(chunk) {
  589. const cgc = this._getChunkGraphChunk(chunk);
  590. return cgc.modules.size;
  591. }
  592. /**
  593. * Gets number of chunk full hash modules.
  594. * @param {Chunk} chunk the chunk
  595. * @returns {number} the number of full hash modules which are contained in this chunk
  596. */
  597. getNumberOfChunkFullHashModules(chunk) {
  598. const cgc = this._getChunkGraphChunk(chunk);
  599. return cgc.fullHashModules === undefined ? 0 : cgc.fullHashModules.size;
  600. }
  601. /**
  602. * Gets chunk modules iterable.
  603. * @param {Chunk} chunk the chunk
  604. * @returns {Iterable<Module>} return the modules for this chunk
  605. */
  606. getChunkModulesIterable(chunk) {
  607. const cgc = this._getChunkGraphChunk(chunk);
  608. return cgc.modules;
  609. }
  610. /**
  611. * Gets chunk modules iterable by source type.
  612. * @param {Chunk} chunk the chunk
  613. * @param {string} sourceType source type
  614. * @returns {Iterable<Module> | undefined} return the modules for this chunk
  615. */
  616. getChunkModulesIterableBySourceType(chunk, sourceType) {
  617. const cgc = this._getChunkGraphChunk(chunk);
  618. const modulesWithSourceType = cgc.modules
  619. .getFromUnorderedCache(cgc._modulesBySourceType)
  620. .get(sourceType);
  621. return modulesWithSourceType;
  622. }
  623. /**
  624. * Sets chunk module source types.
  625. * @param {Chunk} chunk chunk
  626. * @param {Module} module chunk module
  627. * @param {SourceTypes} sourceTypes source types
  628. */
  629. setChunkModuleSourceTypes(chunk, module, sourceTypes) {
  630. const cgc = this._getChunkGraphChunk(chunk);
  631. if (cgc.sourceTypesByModule === undefined) {
  632. cgc.sourceTypesByModule = new WeakMap();
  633. }
  634. cgc.sourceTypesByModule.set(module, sourceTypes);
  635. // Update cgc._modulesBySourceType to invalidate the cache
  636. cgc._modulesBySourceType = modulesBySourceType(cgc.sourceTypesByModule);
  637. }
  638. /**
  639. * Gets chunk module source types.
  640. * @param {Chunk} chunk chunk
  641. * @param {Module} module chunk module
  642. * @returns {SourceTypes} source types
  643. */
  644. getChunkModuleSourceTypes(chunk, module) {
  645. const cgc = this._getChunkGraphChunk(chunk);
  646. if (cgc.sourceTypesByModule === undefined) {
  647. return module.getSourceTypes();
  648. }
  649. return cgc.sourceTypesByModule.get(module) || module.getSourceTypes();
  650. }
  651. /**
  652. * Gets module source types.
  653. * @param {Module} module module
  654. * @returns {SourceTypes} source types
  655. */
  656. getModuleSourceTypes(module) {
  657. return (
  658. this._getOverwrittenModuleSourceTypes(module) || module.getSourceTypes()
  659. );
  660. }
  661. /**
  662. * Get overwritten module source types.
  663. * @param {Module} module module
  664. * @returns {SourceTypes | undefined} source types
  665. */
  666. _getOverwrittenModuleSourceTypes(module) {
  667. let newSet = false;
  668. /** @type {Set<SourceType> | undefined} */
  669. let sourceTypes;
  670. for (const chunk of this.getModuleChunksIterable(module)) {
  671. const cgc = this._getChunkGraphChunk(chunk);
  672. if (cgc.sourceTypesByModule === undefined) return;
  673. const st = cgc.sourceTypesByModule.get(module);
  674. if (st === undefined) return;
  675. if (!sourceTypes) {
  676. sourceTypes = /** @type {Set<SourceType>} */ (st);
  677. } else if (!newSet) {
  678. for (const type of st) {
  679. if (!newSet) {
  680. if (!sourceTypes.has(type)) {
  681. newSet = true;
  682. sourceTypes = new Set(sourceTypes);
  683. sourceTypes.add(type);
  684. }
  685. } else {
  686. sourceTypes.add(type);
  687. }
  688. }
  689. } else {
  690. for (const type of st) sourceTypes.add(type);
  691. }
  692. }
  693. return sourceTypes;
  694. }
  695. /**
  696. * Gets ordered chunk modules iterable.
  697. * @param {Chunk} chunk the chunk
  698. * @param {ModuleComparator} comparator comparator function
  699. * @returns {Iterable<Module>} return the modules for this chunk
  700. */
  701. getOrderedChunkModulesIterable(chunk, comparator) {
  702. const cgc = this._getChunkGraphChunk(chunk);
  703. cgc.modules.sortWith(comparator);
  704. return cgc.modules;
  705. }
  706. /**
  707. * Gets ordered chunk modules iterable by source type.
  708. * @param {Chunk} chunk the chunk
  709. * @param {string} sourceType source type
  710. * @param {ModuleComparator} comparator comparator function
  711. * @returns {Iterable<Module> | undefined} return the modules for this chunk
  712. */
  713. getOrderedChunkModulesIterableBySourceType(chunk, sourceType, comparator) {
  714. const cgc = this._getChunkGraphChunk(chunk);
  715. const modulesWithSourceType = cgc.modules
  716. .getFromUnorderedCache(cgc._modulesBySourceType)
  717. .get(sourceType);
  718. if (modulesWithSourceType === undefined) return;
  719. modulesWithSourceType.sortWith(comparator);
  720. return modulesWithSourceType;
  721. }
  722. /**
  723. * Gets chunk modules.
  724. * @param {Chunk} chunk the chunk
  725. * @returns {Module[]} return the modules for this chunk (cached, do not modify)
  726. */
  727. getChunkModules(chunk) {
  728. const cgc = this._getChunkGraphChunk(chunk);
  729. return cgc.modules.getFromUnorderedCache(getArray);
  730. }
  731. /**
  732. * Gets ordered chunk modules.
  733. * @param {Chunk} chunk the chunk
  734. * @param {ModuleComparator} comparator comparator function
  735. * @returns {Module[]} return the modules for this chunk (cached, do not modify)
  736. */
  737. getOrderedChunkModules(chunk, comparator) {
  738. const cgc = this._getChunkGraphChunk(chunk);
  739. const arrayFunction = createOrderedArrayFunction(comparator);
  740. return cgc.modules.getFromUnorderedCache(arrayFunction);
  741. }
  742. /**
  743. * Gets chunk module id map.
  744. * @param {Chunk} chunk the chunk
  745. * @param {ModuleFilterPredicate} filterFn function used to filter modules
  746. * @param {boolean} includeAllChunks all chunks or only async chunks
  747. * @returns {ChunkModuleIdMap} chunk to module ids object
  748. */
  749. getChunkModuleIdMap(chunk, filterFn, includeAllChunks = false) {
  750. /** @type {ChunkModuleIdMap} */
  751. const chunkModuleIdMap = Object.create(null);
  752. for (const asyncChunk of includeAllChunks
  753. ? chunk.getAllReferencedChunks()
  754. : chunk.getAllAsyncChunks()) {
  755. /** @type {ModuleId[] | undefined} */
  756. let array;
  757. for (const module of this.getOrderedChunkModulesIterable(
  758. asyncChunk,
  759. compareModulesById(this)
  760. )) {
  761. if (filterFn(module)) {
  762. if (array === undefined) {
  763. array = [];
  764. chunkModuleIdMap[/** @type {ChunkId} */ (asyncChunk.id)] = array;
  765. }
  766. const moduleId = /** @type {ModuleId} */ (this.getModuleId(module));
  767. array.push(moduleId);
  768. }
  769. }
  770. }
  771. return chunkModuleIdMap;
  772. }
  773. /**
  774. * Gets chunk module rendered hash map.
  775. * @param {Chunk} chunk the chunk
  776. * @param {ModuleFilterPredicate} filterFn function used to filter modules
  777. * @param {number} hashLength length of the hash
  778. * @param {boolean} includeAllChunks all chunks or only async chunks
  779. * @returns {ChunkModuleHashMap} chunk to module id to module hash object
  780. */
  781. getChunkModuleRenderedHashMap(
  782. chunk,
  783. filterFn,
  784. hashLength = 0,
  785. includeAllChunks = false
  786. ) {
  787. /** @type {ChunkModuleHashMap} */
  788. const chunkModuleHashMap = Object.create(null);
  789. for (const asyncChunk of includeAllChunks
  790. ? chunk.getAllReferencedChunks()
  791. : chunk.getAllAsyncChunks()) {
  792. /** @type {IdToHashMap | undefined} */
  793. let idToHashMap;
  794. for (const module of this.getOrderedChunkModulesIterable(
  795. asyncChunk,
  796. compareModulesById(this)
  797. )) {
  798. if (filterFn(module)) {
  799. if (idToHashMap === undefined) {
  800. /** @type {IdToHashMap} */
  801. idToHashMap = Object.create(null);
  802. chunkModuleHashMap[/** @type {ChunkId} */ (asyncChunk.id)] =
  803. /** @type {IdToHashMap} */
  804. (idToHashMap);
  805. }
  806. const moduleId = this.getModuleId(module);
  807. const hash = this.getRenderedModuleHash(module, asyncChunk.runtime);
  808. /** @type {IdToHashMap} */
  809. (idToHashMap)[/** @type {ModuleId} */ (moduleId)] = hashLength
  810. ? hash.slice(0, hashLength)
  811. : hash;
  812. }
  813. }
  814. }
  815. return chunkModuleHashMap;
  816. }
  817. /**
  818. * Gets chunk condition map.
  819. * @param {Chunk} chunk the chunk
  820. * @param {ChunkFilterPredicate} filterFn function used to filter chunks
  821. * @returns {ChunkConditionMap} chunk condition map
  822. */
  823. getChunkConditionMap(chunk, filterFn) {
  824. /** @type {ChunkConditionMap} */
  825. const map = Object.create(null);
  826. for (const c of chunk.getAllReferencedChunks()) {
  827. map[/** @type {ChunkId} */ (c.id)] = filterFn(c, this);
  828. }
  829. return map;
  830. }
  831. /**
  832. * Checks whether this chunk graph contains the chunk.
  833. * @param {Chunk} chunk the chunk
  834. * @param {ModuleFilterPredicate} filterFn predicate function used to filter modules
  835. * @param {ChunkFilterPredicate=} filterChunkFn predicate function used to filter chunks
  836. * @returns {boolean} return true if module exists in graph
  837. */
  838. hasModuleInGraph(chunk, filterFn, filterChunkFn) {
  839. const queue = new Set(chunk.groupsIterable);
  840. /** @type {Set<Chunk>} */
  841. const chunksProcessed = new Set();
  842. for (const chunkGroup of queue) {
  843. for (const innerChunk of chunkGroup.chunks) {
  844. if (!chunksProcessed.has(innerChunk)) {
  845. chunksProcessed.add(innerChunk);
  846. if (!filterChunkFn || filterChunkFn(innerChunk, this)) {
  847. for (const module of this.getChunkModulesIterable(innerChunk)) {
  848. if (filterFn(module)) {
  849. return true;
  850. }
  851. }
  852. }
  853. }
  854. }
  855. for (const child of chunkGroup.childrenIterable) {
  856. queue.add(child);
  857. }
  858. }
  859. return false;
  860. }
  861. /**
  862. * Compares the provided values and returns their ordering.
  863. * @param {Chunk} chunkA first chunk
  864. * @param {Chunk} chunkB second chunk
  865. * @returns {-1 | 0 | 1} this is a comparator function like sort and returns -1, 0, or 1 based on sort order
  866. */
  867. compareChunks(chunkA, chunkB) {
  868. const cgcA = this._getChunkGraphChunk(chunkA);
  869. const cgcB = this._getChunkGraphChunk(chunkB);
  870. if (cgcA.modules.size > cgcB.modules.size) return -1;
  871. if (cgcA.modules.size < cgcB.modules.size) return 1;
  872. cgcA.modules.sortWith(compareModulesByIdentifier);
  873. cgcB.modules.sortWith(compareModulesByIdentifier);
  874. return compareModuleIterables(cgcA.modules, cgcB.modules);
  875. }
  876. /**
  877. * Gets chunk modules size.
  878. * @param {Chunk} chunk the chunk
  879. * @returns {number} total size of all modules in the chunk
  880. */
  881. getChunkModulesSize(chunk) {
  882. const cgc = this._getChunkGraphChunk(chunk);
  883. return cgc.modules.getFromUnorderedCache(getModulesSize);
  884. }
  885. /**
  886. * Gets chunk modules sizes.
  887. * @param {Chunk} chunk the chunk
  888. * @returns {Record<string, number>} total sizes of all modules in the chunk by source type
  889. */
  890. getChunkModulesSizes(chunk) {
  891. const cgc = this._getChunkGraphChunk(chunk);
  892. return cgc.modules.getFromUnorderedCache(getModulesSizes);
  893. }
  894. /**
  895. * Gets chunk root modules.
  896. * @param {Chunk} chunk the chunk
  897. * @returns {Module[]} root modules of the chunks (ordered by identifier)
  898. */
  899. getChunkRootModules(chunk) {
  900. const cgc = this._getChunkGraphChunk(chunk);
  901. return cgc.modules.getFromUnorderedCache(this._getGraphRoots);
  902. }
  903. /**
  904. * Returns total size of the chunk.
  905. * @param {Chunk} chunk the chunk
  906. * @param {ChunkSizeOptions} options options object
  907. * @returns {number} total size of the chunk
  908. */
  909. getChunkSize(chunk, options = {}) {
  910. const cgc = this._getChunkGraphChunk(chunk);
  911. const modulesSize = cgc.modules.getFromUnorderedCache(getModulesSize);
  912. const chunkOverhead =
  913. typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
  914. const entryChunkMultiplicator =
  915. typeof options.entryChunkMultiplicator === "number"
  916. ? options.entryChunkMultiplicator
  917. : 10;
  918. return (
  919. chunkOverhead +
  920. modulesSize * (chunk.canBeInitial() ? entryChunkMultiplicator : 1)
  921. );
  922. }
  923. /**
  924. * Gets integrated chunks size.
  925. * @param {Chunk} chunkA chunk
  926. * @param {Chunk} chunkB chunk
  927. * @param {ChunkSizeOptions} options options object
  928. * @returns {number} total size of the chunk or false if chunks can't be integrated
  929. */
  930. getIntegratedChunksSize(chunkA, chunkB, options = {}) {
  931. const cgcA = this._getChunkGraphChunk(chunkA);
  932. const cgcB = this._getChunkGraphChunk(chunkB);
  933. const allModules = new Set(cgcA.modules);
  934. for (const m of cgcB.modules) allModules.add(m);
  935. const modulesSize = getModulesSize(allModules);
  936. const chunkOverhead =
  937. typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
  938. const entryChunkMultiplicator =
  939. typeof options.entryChunkMultiplicator === "number"
  940. ? options.entryChunkMultiplicator
  941. : 10;
  942. return (
  943. chunkOverhead +
  944. modulesSize *
  945. (chunkA.canBeInitial() || chunkB.canBeInitial()
  946. ? entryChunkMultiplicator
  947. : 1)
  948. );
  949. }
  950. /**
  951. * Checks whether it can chunks be integrated.
  952. * @param {Chunk} chunkA chunk
  953. * @param {Chunk} chunkB chunk
  954. * @returns {boolean} true, if chunks could be integrated
  955. */
  956. canChunksBeIntegrated(chunkA, chunkB) {
  957. if (chunkA.preventIntegration || chunkB.preventIntegration) {
  958. return false;
  959. }
  960. const hasRuntimeA = chunkA.hasRuntime();
  961. const hasRuntimeB = chunkB.hasRuntime();
  962. if (hasRuntimeA !== hasRuntimeB) {
  963. if (hasRuntimeA) {
  964. return isAvailableChunk(chunkA, chunkB);
  965. } else if (hasRuntimeB) {
  966. return isAvailableChunk(chunkB, chunkA);
  967. }
  968. return false;
  969. }
  970. if (
  971. this.getNumberOfEntryModules(chunkA) > 0 ||
  972. this.getNumberOfEntryModules(chunkB) > 0
  973. ) {
  974. return false;
  975. }
  976. return true;
  977. }
  978. /**
  979. * Processes the provided chunk a.
  980. * @param {Chunk} chunkA the target chunk
  981. * @param {Chunk} chunkB the chunk to integrate
  982. * @returns {void}
  983. */
  984. integrateChunks(chunkA, chunkB) {
  985. // Decide for one name (deterministic)
  986. if (chunkA.name && chunkB.name) {
  987. if (
  988. this.getNumberOfEntryModules(chunkA) > 0 ===
  989. this.getNumberOfEntryModules(chunkB) > 0
  990. ) {
  991. // When both chunks have entry modules or none have one, use
  992. // shortest name
  993. if (chunkA.name.length !== chunkB.name.length) {
  994. chunkA.name =
  995. chunkA.name.length < chunkB.name.length ? chunkA.name : chunkB.name;
  996. } else {
  997. chunkA.name = chunkA.name < chunkB.name ? chunkA.name : chunkB.name;
  998. }
  999. } else if (this.getNumberOfEntryModules(chunkB) > 0) {
  1000. // Pick the name of the chunk with the entry module
  1001. chunkA.name = chunkB.name;
  1002. }
  1003. } else if (chunkB.name) {
  1004. chunkA.name = chunkB.name;
  1005. }
  1006. // Merge id name hints
  1007. for (const hint of chunkB.idNameHints) {
  1008. chunkA.idNameHints.add(hint);
  1009. }
  1010. // Merge runtime
  1011. chunkA.runtime = mergeRuntime(chunkA.runtime, chunkB.runtime);
  1012. // getChunkModules is used here to create a clone, because disconnectChunkAndModule modifies
  1013. for (const module of this.getChunkModules(chunkB)) {
  1014. this.disconnectChunkAndModule(chunkB, module);
  1015. this.connectChunkAndModule(chunkA, module);
  1016. }
  1017. for (const [
  1018. module,
  1019. chunkGroup
  1020. ] of this.getChunkEntryModulesWithChunkGroupIterable(chunkB)) {
  1021. this.disconnectChunkAndEntryModule(chunkB, module);
  1022. this.connectChunkAndEntryModule(
  1023. chunkA,
  1024. module,
  1025. /** @type {Entrypoint} */
  1026. (chunkGroup)
  1027. );
  1028. }
  1029. for (const chunkGroup of chunkB.groupsIterable) {
  1030. chunkGroup.replaceChunk(chunkB, chunkA);
  1031. chunkA.addGroup(chunkGroup);
  1032. chunkB.removeGroup(chunkGroup);
  1033. }
  1034. ChunkGraph.clearChunkGraphForChunk(chunkB);
  1035. }
  1036. /**
  1037. * Upgrade dependent to full hash modules.
  1038. * @param {Chunk} chunk the chunk to upgrade
  1039. * @returns {void}
  1040. */
  1041. upgradeDependentToFullHashModules(chunk) {
  1042. const cgc = this._getChunkGraphChunk(chunk);
  1043. if (cgc.dependentHashModules === undefined) return;
  1044. if (cgc.fullHashModules === undefined) {
  1045. cgc.fullHashModules = cgc.dependentHashModules;
  1046. } else {
  1047. for (const m of cgc.dependentHashModules) {
  1048. cgc.fullHashModules.add(m);
  1049. }
  1050. cgc.dependentHashModules = undefined;
  1051. }
  1052. }
  1053. /**
  1054. * Checks whether this chunk graph is entry module in chunk.
  1055. * @param {Module} module the checked module
  1056. * @param {Chunk} chunk the checked chunk
  1057. * @returns {boolean} true, if the chunk contains the module as entry
  1058. */
  1059. isEntryModuleInChunk(module, chunk) {
  1060. const cgc = this._getChunkGraphChunk(chunk);
  1061. return cgc.entryModules.has(module);
  1062. }
  1063. /**
  1064. * Connects chunk and entry module.
  1065. * @param {Chunk} chunk the new chunk
  1066. * @param {Module} module the entry module
  1067. * @param {Entrypoint} entrypoint the chunk group which must be loaded before the module is executed
  1068. * @returns {void}
  1069. */
  1070. connectChunkAndEntryModule(chunk, module, entrypoint) {
  1071. const cgm = this._getChunkGraphModule(module);
  1072. const cgc = this._getChunkGraphChunk(chunk);
  1073. if (cgm.entryInChunks === undefined) {
  1074. cgm.entryInChunks = new Set();
  1075. }
  1076. cgm.entryInChunks.add(chunk);
  1077. cgc.entryModules.set(module, entrypoint);
  1078. }
  1079. /**
  1080. * Connects chunk and runtime module.
  1081. * @param {Chunk} chunk the new chunk
  1082. * @param {RuntimeModule} module the runtime module
  1083. * @returns {void}
  1084. */
  1085. connectChunkAndRuntimeModule(chunk, module) {
  1086. const cgm = this._getChunkGraphModule(module);
  1087. const cgc = this._getChunkGraphChunk(chunk);
  1088. if (cgm.runtimeInChunks === undefined) {
  1089. cgm.runtimeInChunks = new Set();
  1090. }
  1091. cgm.runtimeInChunks.add(chunk);
  1092. cgc.runtimeModules.add(module);
  1093. }
  1094. /**
  1095. * Adds full hash module to chunk.
  1096. * @param {Chunk} chunk the new chunk
  1097. * @param {RuntimeModule} module the module that require a full hash
  1098. * @returns {void}
  1099. */
  1100. addFullHashModuleToChunk(chunk, module) {
  1101. const cgc = this._getChunkGraphChunk(chunk);
  1102. if (cgc.fullHashModules === undefined) cgc.fullHashModules = new Set();
  1103. cgc.fullHashModules.add(module);
  1104. }
  1105. /**
  1106. * Adds dependent hash module to chunk.
  1107. * @param {Chunk} chunk the new chunk
  1108. * @param {RuntimeModule} module the module that require a full hash
  1109. * @returns {void}
  1110. */
  1111. addDependentHashModuleToChunk(chunk, module) {
  1112. const cgc = this._getChunkGraphChunk(chunk);
  1113. if (cgc.dependentHashModules === undefined) {
  1114. cgc.dependentHashModules = new Set();
  1115. }
  1116. cgc.dependentHashModules.add(module);
  1117. }
  1118. /**
  1119. * Disconnects chunk and entry module.
  1120. * @param {Chunk} chunk the new chunk
  1121. * @param {Module} module the entry module
  1122. * @returns {void}
  1123. */
  1124. disconnectChunkAndEntryModule(chunk, module) {
  1125. const cgm = this._getChunkGraphModule(module);
  1126. const cgc = this._getChunkGraphChunk(chunk);
  1127. /** @type {EntryInChunks} */
  1128. (cgm.entryInChunks).delete(chunk);
  1129. if (/** @type {EntryInChunks} */ (cgm.entryInChunks).size === 0) {
  1130. cgm.entryInChunks = undefined;
  1131. }
  1132. cgc.entryModules.delete(module);
  1133. }
  1134. /**
  1135. * Disconnects chunk and runtime module.
  1136. * @param {Chunk} chunk the new chunk
  1137. * @param {RuntimeModule} module the runtime module
  1138. * @returns {void}
  1139. */
  1140. disconnectChunkAndRuntimeModule(chunk, module) {
  1141. const cgm = this._getChunkGraphModule(module);
  1142. const cgc = this._getChunkGraphChunk(chunk);
  1143. /** @type {RuntimeInChunks} */
  1144. (cgm.runtimeInChunks).delete(chunk);
  1145. if (/** @type {RuntimeInChunks} */ (cgm.runtimeInChunks).size === 0) {
  1146. cgm.runtimeInChunks = undefined;
  1147. }
  1148. cgc.runtimeModules.delete(module);
  1149. }
  1150. /**
  1151. * Disconnects entry module.
  1152. * @param {Module} module the entry module, it will no longer be entry
  1153. * @returns {void}
  1154. */
  1155. disconnectEntryModule(module) {
  1156. const cgm = this._getChunkGraphModule(module);
  1157. for (const chunk of /** @type {EntryInChunks} */ (cgm.entryInChunks)) {
  1158. const cgc = this._getChunkGraphChunk(chunk);
  1159. cgc.entryModules.delete(module);
  1160. }
  1161. cgm.entryInChunks = undefined;
  1162. }
  1163. /**
  1164. * Disconnects entries.
  1165. * @param {Chunk} chunk the chunk, for which all entries will be removed
  1166. * @returns {void}
  1167. */
  1168. disconnectEntries(chunk) {
  1169. const cgc = this._getChunkGraphChunk(chunk);
  1170. for (const module of cgc.entryModules.keys()) {
  1171. const cgm = this._getChunkGraphModule(module);
  1172. /** @type {EntryInChunks} */
  1173. (cgm.entryInChunks).delete(chunk);
  1174. if (/** @type {EntryInChunks} */ (cgm.entryInChunks).size === 0) {
  1175. cgm.entryInChunks = undefined;
  1176. }
  1177. }
  1178. cgc.entryModules.clear();
  1179. }
  1180. /**
  1181. * Gets number of entry modules.
  1182. * @param {Chunk} chunk the chunk
  1183. * @returns {number} the amount of entry modules in chunk
  1184. */
  1185. getNumberOfEntryModules(chunk) {
  1186. const cgc = this._getChunkGraphChunk(chunk);
  1187. return cgc.entryModules.size;
  1188. }
  1189. /**
  1190. * Gets number of runtime modules.
  1191. * @param {Chunk} chunk the chunk
  1192. * @returns {number} the amount of entry modules in chunk
  1193. */
  1194. getNumberOfRuntimeModules(chunk) {
  1195. const cgc = this._getChunkGraphChunk(chunk);
  1196. return cgc.runtimeModules.size;
  1197. }
  1198. /**
  1199. * Gets chunk entry modules iterable.
  1200. * @param {Chunk} chunk the chunk
  1201. * @returns {Iterable<Module>} iterable of modules (do not modify)
  1202. */
  1203. getChunkEntryModulesIterable(chunk) {
  1204. const cgc = this._getChunkGraphChunk(chunk);
  1205. return cgc.entryModules.keys();
  1206. }
  1207. /**
  1208. * Gets chunk entry dependent chunks iterable.
  1209. * @param {Chunk} chunk the chunk
  1210. * @returns {Iterable<Chunk>} iterable of chunks
  1211. */
  1212. getChunkEntryDependentChunksIterable(chunk) {
  1213. /** @type {Chunks} */
  1214. const set = new Set();
  1215. for (const chunkGroup of chunk.groupsIterable) {
  1216. if (chunkGroup instanceof Entrypoint) {
  1217. const entrypointChunk = chunkGroup.getEntrypointChunk();
  1218. const cgc = this._getChunkGraphChunk(entrypointChunk);
  1219. for (const chunkGroup of cgc.entryModules.values()) {
  1220. for (const c of chunkGroup.chunks) {
  1221. if (c !== chunk && c !== entrypointChunk && !c.hasRuntime()) {
  1222. set.add(c);
  1223. }
  1224. }
  1225. }
  1226. }
  1227. }
  1228. return set;
  1229. }
  1230. /**
  1231. * Gets runtime chunk dependent chunks iterable.
  1232. * @param {Chunk} chunk the chunk
  1233. * @returns {Iterable<Chunk>} iterable of chunks and include chunks from children entrypoints
  1234. */
  1235. getRuntimeChunkDependentChunksIterable(chunk) {
  1236. /** @type {Chunks} */
  1237. const set = new Set();
  1238. /** @type {Entrypoints} */
  1239. const entrypoints = new Set();
  1240. for (const chunkGroup of chunk.groupsIterable) {
  1241. if (chunkGroup instanceof Entrypoint) {
  1242. const queue = [chunkGroup];
  1243. while (queue.length > 0) {
  1244. const current = queue.shift();
  1245. if (current) {
  1246. entrypoints.add(current);
  1247. let hasChildrenEntrypoint = false;
  1248. for (const child of current.childrenIterable) {
  1249. if (child instanceof Entrypoint && child.dependOn(current)) {
  1250. hasChildrenEntrypoint = true;
  1251. queue.push(/** @type {Entrypoint} */ (child));
  1252. }
  1253. }
  1254. // entryChunkB: hasChildrenEntrypoint = true
  1255. // entryChunkA: dependOn = entryChunkB
  1256. if (hasChildrenEntrypoint) {
  1257. const entrypointChunk = current.getEntrypointChunk();
  1258. if (entrypointChunk !== chunk && !entrypointChunk.hasRuntime()) {
  1259. // add entryChunkB to set
  1260. set.add(entrypointChunk);
  1261. }
  1262. }
  1263. }
  1264. }
  1265. }
  1266. }
  1267. for (const entrypoint of entrypoints) {
  1268. const entrypointChunk = entrypoint.getEntrypointChunk();
  1269. const cgc = this._getChunkGraphChunk(entrypointChunk);
  1270. for (const chunkGroup of cgc.entryModules.values()) {
  1271. for (const c of chunkGroup.chunks) {
  1272. if (c !== chunk && c !== entrypointChunk && !c.hasRuntime()) {
  1273. set.add(c);
  1274. }
  1275. }
  1276. }
  1277. }
  1278. return set;
  1279. }
  1280. /**
  1281. * Checks whether this chunk graph contains the chunk.
  1282. * @param {Chunk} chunk the chunk
  1283. * @returns {boolean} true, when it has dependent chunks
  1284. */
  1285. hasChunkEntryDependentChunks(chunk) {
  1286. const cgc = this._getChunkGraphChunk(chunk);
  1287. for (const chunkGroup of cgc.entryModules.values()) {
  1288. for (const c of chunkGroup.chunks) {
  1289. if (c !== chunk) {
  1290. return true;
  1291. }
  1292. }
  1293. }
  1294. return false;
  1295. }
  1296. /**
  1297. * Gets chunk runtime modules iterable.
  1298. * @param {Chunk} chunk the chunk
  1299. * @returns {Iterable<RuntimeModule>} iterable of modules (do not modify)
  1300. */
  1301. getChunkRuntimeModulesIterable(chunk) {
  1302. const cgc = this._getChunkGraphChunk(chunk);
  1303. return cgc.runtimeModules;
  1304. }
  1305. /**
  1306. * Gets chunk runtime modules in order.
  1307. * @param {Chunk} chunk the chunk
  1308. * @returns {RuntimeModule[]} array of modules in order of execution
  1309. */
  1310. getChunkRuntimeModulesInOrder(chunk) {
  1311. const cgc = this._getChunkGraphChunk(chunk);
  1312. const array = [...cgc.runtimeModules];
  1313. array.sort(
  1314. concatComparators(
  1315. compareSelect(
  1316. (r) => /** @type {RuntimeModule} */ (r).stage,
  1317. compareIds
  1318. ),
  1319. compareModulesByIdentifier
  1320. )
  1321. );
  1322. return array;
  1323. }
  1324. /**
  1325. * Gets chunk full hash modules iterable.
  1326. * @param {Chunk} chunk the chunk
  1327. * @returns {Iterable<RuntimeModule> | undefined} iterable of modules (do not modify)
  1328. */
  1329. getChunkFullHashModulesIterable(chunk) {
  1330. const cgc = this._getChunkGraphChunk(chunk);
  1331. return cgc.fullHashModules;
  1332. }
  1333. /**
  1334. * Gets chunk full hash modules set.
  1335. * @param {Chunk} chunk the chunk
  1336. * @returns {ReadonlySet<RuntimeModule> | undefined} set of modules (do not modify)
  1337. */
  1338. getChunkFullHashModulesSet(chunk) {
  1339. const cgc = this._getChunkGraphChunk(chunk);
  1340. return cgc.fullHashModules;
  1341. }
  1342. /**
  1343. * Gets chunk dependent hash modules iterable.
  1344. * @param {Chunk} chunk the chunk
  1345. * @returns {Iterable<RuntimeModule> | undefined} iterable of modules (do not modify)
  1346. */
  1347. getChunkDependentHashModulesIterable(chunk) {
  1348. const cgc = this._getChunkGraphChunk(chunk);
  1349. return cgc.dependentHashModules;
  1350. }
  1351. /**
  1352. * Gets chunk entry modules with chunk group iterable.
  1353. * @param {Chunk} chunk the chunk
  1354. * @returns {Iterable<EntryModuleWithChunkGroup>} iterable of modules (do not modify)
  1355. */
  1356. getChunkEntryModulesWithChunkGroupIterable(chunk) {
  1357. const cgc = this._getChunkGraphChunk(chunk);
  1358. return cgc.entryModules;
  1359. }
  1360. /**
  1361. * Gets block chunk group.
  1362. * @param {AsyncDependenciesBlock} depBlock the async block
  1363. * @returns {ChunkGroup | undefined} the chunk group
  1364. */
  1365. getBlockChunkGroup(depBlock) {
  1366. return this._blockChunkGroups.get(depBlock);
  1367. }
  1368. /**
  1369. * Connects block and chunk group.
  1370. * @param {AsyncDependenciesBlock} depBlock the async block
  1371. * @param {ChunkGroup} chunkGroup the chunk group
  1372. * @returns {void}
  1373. */
  1374. connectBlockAndChunkGroup(depBlock, chunkGroup) {
  1375. this._blockChunkGroups.set(depBlock, chunkGroup);
  1376. chunkGroup.addBlock(depBlock);
  1377. }
  1378. /**
  1379. * Disconnects chunk group.
  1380. * @param {ChunkGroup} chunkGroup the chunk group
  1381. * @returns {void}
  1382. */
  1383. disconnectChunkGroup(chunkGroup) {
  1384. for (const block of chunkGroup.blocksIterable) {
  1385. this._blockChunkGroups.delete(block);
  1386. }
  1387. // TODO refactor by moving blocks list into ChunkGraph
  1388. chunkGroup._blocks.clear();
  1389. }
  1390. /**
  1391. * Returns the id of the module.
  1392. * @param {Module} module the module
  1393. * @returns {ModuleId | null} the id of the module
  1394. */
  1395. getModuleId(module) {
  1396. const cgm = this._getChunkGraphModule(module);
  1397. return cgm.id;
  1398. }
  1399. /**
  1400. * Updates module id using the provided module.
  1401. * @param {Module} module the module
  1402. * @param {ModuleId} id the id of the module
  1403. * @returns {void}
  1404. */
  1405. setModuleId(module, id) {
  1406. const cgm = this._getChunkGraphModule(module);
  1407. cgm.id = id;
  1408. }
  1409. /**
  1410. * Returns the id of the runtime.
  1411. * @param {string} runtime runtime
  1412. * @returns {RuntimeId} the id of the runtime
  1413. */
  1414. getRuntimeId(runtime) {
  1415. return /** @type {RuntimeId} */ (this._runtimeIds.get(runtime));
  1416. }
  1417. /**
  1418. * Updates runtime id using the provided runtime.
  1419. * @param {string} runtime runtime
  1420. * @param {RuntimeId} id the id of the runtime
  1421. * @returns {void}
  1422. */
  1423. setRuntimeId(runtime, id) {
  1424. this._runtimeIds.set(runtime, id);
  1425. }
  1426. /**
  1427. * Get module hash info.
  1428. * @template T
  1429. * @param {Module} module the module
  1430. * @param {RuntimeSpecMap<T>} hashes hashes data
  1431. * @param {RuntimeSpec} runtime the runtime
  1432. * @returns {T} hash
  1433. */
  1434. _getModuleHashInfo(module, hashes, runtime) {
  1435. if (!hashes) {
  1436. throw new Error(
  1437. `Module ${module.identifier()} has no hash info for runtime ${runtimeToString(
  1438. runtime
  1439. )} (hashes not set at all)`
  1440. );
  1441. } else if (runtime === undefined) {
  1442. const hashInfoItems = new Set(hashes.values());
  1443. if (hashInfoItems.size !== 1) {
  1444. throw new Error(
  1445. `No unique hash info entry for unspecified runtime for ${module.identifier()} (existing runtimes: ${Array.from(
  1446. hashes.keys(),
  1447. (r) => runtimeToString(r)
  1448. ).join(", ")}).
  1449. Caller might not support runtime-dependent code generation (opt-out via optimization.usedExports: "global").`
  1450. );
  1451. }
  1452. return /** @type {T} */ (first(hashInfoItems));
  1453. } else {
  1454. const hashInfo = hashes.get(runtime);
  1455. if (!hashInfo) {
  1456. throw new Error(
  1457. `Module ${module.identifier()} has no hash info for runtime ${runtimeToString(
  1458. runtime
  1459. )} (available runtimes ${Array.from(
  1460. hashes.keys(),
  1461. runtimeToString
  1462. ).join(", ")})`
  1463. );
  1464. }
  1465. return hashInfo;
  1466. }
  1467. }
  1468. /**
  1469. * Checks whether this chunk graph contains the module.
  1470. * @param {Module} module the module
  1471. * @param {RuntimeSpec} runtime the runtime
  1472. * @returns {boolean} true, if the module has hashes for this runtime
  1473. */
  1474. hasModuleHashes(module, runtime) {
  1475. const cgm = this._getChunkGraphModule(module);
  1476. const hashes = /** @type {RuntimeSpecMap<ModuleHashInfo>} */ (cgm.hashes);
  1477. return hashes && hashes.has(runtime);
  1478. }
  1479. /**
  1480. * Returns hash.
  1481. * @param {Module} module the module
  1482. * @param {RuntimeSpec} runtime the runtime
  1483. * @returns {string} hash
  1484. */
  1485. getModuleHash(module, runtime) {
  1486. const cgm = this._getChunkGraphModule(module);
  1487. const hashes = /** @type {RuntimeSpecMap<ModuleHashInfo>} */ (cgm.hashes);
  1488. return this._getModuleHashInfo(module, hashes, runtime).hash;
  1489. }
  1490. /**
  1491. * Gets rendered module hash.
  1492. * @param {Module} module the module
  1493. * @param {RuntimeSpec} runtime the runtime
  1494. * @returns {string} hash
  1495. */
  1496. getRenderedModuleHash(module, runtime) {
  1497. const cgm = this._getChunkGraphModule(module);
  1498. const hashes = /** @type {RuntimeSpecMap<ModuleHashInfo>} */ (cgm.hashes);
  1499. return this._getModuleHashInfo(module, hashes, runtime).renderedHash;
  1500. }
  1501. /**
  1502. * Sets module hashes.
  1503. * @param {Module} module the module
  1504. * @param {RuntimeSpec} runtime the runtime
  1505. * @param {string} hash the full hash
  1506. * @param {string} renderedHash the shortened hash for rendering
  1507. * @returns {void}
  1508. */
  1509. setModuleHashes(module, runtime, hash, renderedHash) {
  1510. const cgm = this._getChunkGraphModule(module);
  1511. if (cgm.hashes === undefined) {
  1512. cgm.hashes = new RuntimeSpecMap();
  1513. }
  1514. cgm.hashes.set(runtime, new ModuleHashInfo(hash, renderedHash));
  1515. }
  1516. /**
  1517. * Adds module runtime requirements.
  1518. * @param {Module} module the module
  1519. * @param {RuntimeSpec} runtime the runtime
  1520. * @param {RuntimeRequirements} items runtime requirements to be added (ownership of this Set is given to ChunkGraph when transferOwnership not false)
  1521. * @param {boolean} transferOwnership true: transfer ownership of the items object, false: items is immutable and shared and won't be modified
  1522. * @returns {void}
  1523. */
  1524. addModuleRuntimeRequirements(
  1525. module,
  1526. runtime,
  1527. items,
  1528. transferOwnership = true
  1529. ) {
  1530. const cgm = this._getChunkGraphModule(module);
  1531. const runtimeRequirementsMap = cgm.runtimeRequirements;
  1532. if (runtimeRequirementsMap === undefined) {
  1533. /** @type {ChunkGraphRuntimeRequirements} */
  1534. const map = new RuntimeSpecMap();
  1535. // TODO avoid cloning item and track ownership instead
  1536. map.set(runtime, transferOwnership ? items : new Set(items));
  1537. cgm.runtimeRequirements = map;
  1538. return;
  1539. }
  1540. runtimeRequirementsMap.update(runtime, (runtimeRequirements) => {
  1541. if (runtimeRequirements === undefined) {
  1542. return transferOwnership ? items : new Set(items);
  1543. } else if (!transferOwnership || runtimeRequirements.size >= items.size) {
  1544. for (const item of items) runtimeRequirements.add(item);
  1545. return runtimeRequirements;
  1546. }
  1547. for (const item of runtimeRequirements) items.add(item);
  1548. return items;
  1549. });
  1550. }
  1551. /**
  1552. * Adds chunk runtime requirements.
  1553. * @param {Chunk} chunk the chunk
  1554. * @param {RuntimeRequirements} items runtime requirements to be added (ownership of this Set is given to ChunkGraph)
  1555. * @returns {void}
  1556. */
  1557. addChunkRuntimeRequirements(chunk, items) {
  1558. const cgc = this._getChunkGraphChunk(chunk);
  1559. const runtimeRequirements = cgc.runtimeRequirements;
  1560. if (runtimeRequirements === undefined) {
  1561. cgc.runtimeRequirements = items;
  1562. } else if (runtimeRequirements.size >= items.size) {
  1563. for (const item of items) runtimeRequirements.add(item);
  1564. } else {
  1565. for (const item of runtimeRequirements) items.add(item);
  1566. cgc.runtimeRequirements = items;
  1567. }
  1568. }
  1569. /**
  1570. * Adds tree runtime requirements.
  1571. * @param {Chunk} chunk the chunk
  1572. * @param {Iterable<string>} items runtime requirements to be added
  1573. * @returns {void}
  1574. */
  1575. addTreeRuntimeRequirements(chunk, items) {
  1576. const cgc = this._getChunkGraphChunk(chunk);
  1577. const runtimeRequirements = cgc.runtimeRequirementsInTree;
  1578. for (const item of items) runtimeRequirements.add(item);
  1579. }
  1580. /**
  1581. * Gets module runtime requirements.
  1582. * @param {Module} module the module
  1583. * @param {RuntimeSpec} runtime the runtime
  1584. * @returns {ReadOnlyRuntimeRequirements} runtime requirements
  1585. */
  1586. getModuleRuntimeRequirements(module, runtime) {
  1587. const cgm = this._getChunkGraphModule(module);
  1588. const runtimeRequirements =
  1589. cgm.runtimeRequirements && cgm.runtimeRequirements.get(runtime);
  1590. return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements;
  1591. }
  1592. /**
  1593. * Gets chunk runtime requirements.
  1594. * @param {Chunk} chunk the chunk
  1595. * @returns {ReadOnlyRuntimeRequirements} runtime requirements
  1596. */
  1597. getChunkRuntimeRequirements(chunk) {
  1598. const cgc = this._getChunkGraphChunk(chunk);
  1599. const runtimeRequirements = cgc.runtimeRequirements;
  1600. return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements;
  1601. }
  1602. /**
  1603. * Gets module graph hash.
  1604. * @param {Module} module the module
  1605. * @param {RuntimeSpec} runtime the runtime
  1606. * @param {boolean} withConnections include connections
  1607. * @returns {string} hash
  1608. */
  1609. getModuleGraphHash(module, runtime, withConnections = true) {
  1610. const cgm = this._getChunkGraphModule(module);
  1611. return withConnections
  1612. ? this._getModuleGraphHashWithConnections(cgm, module, runtime)
  1613. : this._getModuleGraphHashBigInt(cgm, module, runtime).toString(16);
  1614. }
  1615. /**
  1616. * Gets module graph hash big int.
  1617. * @param {Module} module the module
  1618. * @param {RuntimeSpec} runtime the runtime
  1619. * @param {boolean} withConnections include connections
  1620. * @returns {bigint} hash
  1621. */
  1622. getModuleGraphHashBigInt(module, runtime, withConnections = true) {
  1623. const cgm = this._getChunkGraphModule(module);
  1624. return withConnections
  1625. ? BigInt(
  1626. `0x${this._getModuleGraphHashWithConnections(cgm, module, runtime)}`
  1627. )
  1628. : this._getModuleGraphHashBigInt(cgm, module, runtime);
  1629. }
  1630. /**
  1631. * Get module graph hash big int.
  1632. * @param {ChunkGraphModule} cgm the ChunkGraphModule
  1633. * @param {Module} module the module
  1634. * @param {RuntimeSpec} runtime the runtime
  1635. * @returns {bigint} hash as big int
  1636. */
  1637. _getModuleGraphHashBigInt(cgm, module, runtime) {
  1638. if (cgm.graphHashes === undefined) {
  1639. cgm.graphHashes = new RuntimeSpecMap();
  1640. }
  1641. const graphHash = cgm.graphHashes.provide(runtime, () => {
  1642. const hash = createHash(this._hashFunction);
  1643. hash.update(`${cgm.id}${this.moduleGraph.isAsync(module)}`);
  1644. const sourceTypes = this._getOverwrittenModuleSourceTypes(module);
  1645. if (sourceTypes !== undefined) {
  1646. for (const type of sourceTypes) hash.update(type);
  1647. }
  1648. this.moduleGraph.getExportsInfo(module).updateHash(hash, runtime);
  1649. return BigInt(`0x${hash.digest("hex")}`);
  1650. });
  1651. return graphHash;
  1652. }
  1653. /**
  1654. * Get module graph hash with connections.
  1655. * @param {ChunkGraphModule} cgm the ChunkGraphModule
  1656. * @param {Module} module the module
  1657. * @param {RuntimeSpec} runtime the runtime
  1658. * @returns {string} hash
  1659. */
  1660. _getModuleGraphHashWithConnections(cgm, module, runtime) {
  1661. if (cgm.graphHashesWithConnections === undefined) {
  1662. cgm.graphHashesWithConnections = new RuntimeSpecMap();
  1663. }
  1664. /**
  1665. * Active state to string.
  1666. * @param {ConnectionState} state state
  1667. * @returns {"F" | "T" | "O"} result
  1668. */
  1669. const activeStateToString = (state) => {
  1670. if (state === false) return "F";
  1671. if (state === true) return "T";
  1672. if (state === ModuleGraphConnection.TRANSITIVE_ONLY) return "O";
  1673. throw new Error("Not implemented active state");
  1674. };
  1675. const strict = module.buildMeta && module.buildMeta.strictHarmonyModule;
  1676. return cgm.graphHashesWithConnections.provide(runtime, () => {
  1677. const graphHash = this._getModuleGraphHashBigInt(
  1678. cgm,
  1679. module,
  1680. runtime
  1681. ).toString(16);
  1682. const connections = this.moduleGraph.getOutgoingConnections(module);
  1683. /** @type {Set<Module>} */
  1684. const activeNamespaceModules = new Set();
  1685. /** @type {Map<string, Module | Set<Module>>} */
  1686. const connectedModules = new Map();
  1687. /**
  1688. * Process connection.
  1689. * @param {ModuleGraphConnection} connection connection
  1690. * @param {string} stateInfo state info
  1691. */
  1692. const processConnection = (connection, stateInfo) => {
  1693. const module = connection.module;
  1694. stateInfo += module.getExportsType(this.moduleGraph, strict);
  1695. // cspell:word Tnamespace
  1696. if (stateInfo === "Tnamespace") {
  1697. activeNamespaceModules.add(module);
  1698. } else {
  1699. const oldModule = connectedModules.get(stateInfo);
  1700. if (oldModule === undefined) {
  1701. connectedModules.set(stateInfo, module);
  1702. } else if (oldModule instanceof Set) {
  1703. oldModule.add(module);
  1704. } else if (oldModule !== module) {
  1705. connectedModules.set(stateInfo, new Set([oldModule, module]));
  1706. }
  1707. }
  1708. };
  1709. if (runtime === undefined || typeof runtime === "string") {
  1710. for (const connection of connections) {
  1711. const state = connection.getActiveState(runtime);
  1712. if (state === false) continue;
  1713. processConnection(connection, state === true ? "T" : "O");
  1714. }
  1715. } else {
  1716. // cspell:word Tnamespace
  1717. for (const connection of connections) {
  1718. /** @type {Set<ConnectionState>} */
  1719. const states = new Set();
  1720. let stateInfo = "";
  1721. forEachRuntime(
  1722. runtime,
  1723. (runtime) => {
  1724. const state = connection.getActiveState(runtime);
  1725. states.add(state);
  1726. stateInfo += activeStateToString(state) + runtime;
  1727. },
  1728. true
  1729. );
  1730. if (states.size === 1) {
  1731. const state = first(states);
  1732. if (state === false) continue;
  1733. stateInfo = activeStateToString(
  1734. /** @type {ConnectionState} */
  1735. (state)
  1736. );
  1737. }
  1738. processConnection(connection, stateInfo);
  1739. }
  1740. }
  1741. // cspell:word Tnamespace
  1742. if (activeNamespaceModules.size === 0 && connectedModules.size === 0) {
  1743. return graphHash;
  1744. }
  1745. const connectedModulesInOrder =
  1746. connectedModules.size > 1
  1747. ? [...connectedModules].sort(([a], [b]) => (a < b ? -1 : 1))
  1748. : connectedModules;
  1749. const hash = createHash(this._hashFunction);
  1750. /**
  1751. * Adds module to hash.
  1752. * @param {Module} module module
  1753. */
  1754. const addModuleToHash = (module) => {
  1755. hash.update(
  1756. this._getModuleGraphHashBigInt(
  1757. this._getChunkGraphModule(module),
  1758. module,
  1759. runtime
  1760. ).toString(16)
  1761. );
  1762. };
  1763. /**
  1764. * Adds modules to hash.
  1765. * @param {Set<Module>} modules modules
  1766. */
  1767. const addModulesToHash = (modules) => {
  1768. let xor = ZERO_BIG_INT;
  1769. for (const m of modules) {
  1770. xor ^= this._getModuleGraphHashBigInt(
  1771. this._getChunkGraphModule(m),
  1772. m,
  1773. runtime
  1774. );
  1775. }
  1776. hash.update(xor.toString(16));
  1777. };
  1778. if (activeNamespaceModules.size === 1) {
  1779. addModuleToHash(
  1780. /** @type {Module} */ (activeNamespaceModules.values().next().value)
  1781. );
  1782. } else if (activeNamespaceModules.size > 1) {
  1783. addModulesToHash(activeNamespaceModules);
  1784. }
  1785. for (const [stateInfo, modules] of connectedModulesInOrder) {
  1786. hash.update(stateInfo);
  1787. if (modules instanceof Set) {
  1788. addModulesToHash(modules);
  1789. } else {
  1790. addModuleToHash(modules);
  1791. }
  1792. }
  1793. hash.update(graphHash);
  1794. return hash.digest("hex");
  1795. });
  1796. }
  1797. /**
  1798. * Gets tree runtime requirements.
  1799. * @param {Chunk} chunk the chunk
  1800. * @returns {ReadOnlyRuntimeRequirements} runtime requirements
  1801. */
  1802. getTreeRuntimeRequirements(chunk) {
  1803. const cgc = this._getChunkGraphChunk(chunk);
  1804. return cgc.runtimeRequirementsInTree;
  1805. }
  1806. // TODO remove in webpack 6
  1807. /**
  1808. * Gets chunk graph for module.
  1809. * @deprecated
  1810. * @param {Module} module the module
  1811. * @param {string} deprecateMessage message for the deprecation message
  1812. * @param {string} deprecationCode code for the deprecation
  1813. * @returns {ChunkGraph} the chunk graph
  1814. */
  1815. static getChunkGraphForModule(module, deprecateMessage, deprecationCode) {
  1816. const fn = deprecateGetChunkGraphForModuleMap.get(deprecateMessage);
  1817. if (fn) return fn(module);
  1818. const newFn = util.deprecate(
  1819. /**
  1820. * Handles the callback logic for this hook.
  1821. * @param {Module} module the module
  1822. * @returns {ChunkGraph} the chunk graph
  1823. */
  1824. (module) => {
  1825. const chunkGraph = chunkGraphForModuleMap.get(module);
  1826. if (!chunkGraph) {
  1827. throw new Error(
  1828. `${
  1829. deprecateMessage
  1830. }: There was no ChunkGraph assigned to the Module for backward-compat (Use the new API)`
  1831. );
  1832. }
  1833. return chunkGraph;
  1834. },
  1835. `${deprecateMessage}: Use new ChunkGraph API`,
  1836. deprecationCode
  1837. );
  1838. deprecateGetChunkGraphForModuleMap.set(deprecateMessage, newFn);
  1839. return newFn(module);
  1840. }
  1841. // TODO remove in webpack 6
  1842. // BACKWARD-COMPAT START
  1843. /**
  1844. * Sets chunk graph for module.
  1845. * @deprecated
  1846. * @param {Module} module the module
  1847. * @param {ChunkGraph} chunkGraph the chunk graph
  1848. * @returns {void}
  1849. */
  1850. static setChunkGraphForModule(module, chunkGraph) {
  1851. chunkGraphForModuleMap.set(module, chunkGraph);
  1852. }
  1853. /**
  1854. * Clear chunk graph for module.
  1855. * @deprecated
  1856. * @param {Module} module the module
  1857. * @returns {void}
  1858. */
  1859. static clearChunkGraphForModule(module) {
  1860. chunkGraphForModuleMap.delete(module);
  1861. }
  1862. /**
  1863. * Gets chunk graph for chunk.
  1864. * @deprecated
  1865. * @param {Chunk} chunk the chunk
  1866. * @param {string} deprecateMessage message for the deprecation message
  1867. * @param {string} deprecationCode code for the deprecation
  1868. * @returns {ChunkGraph} the chunk graph
  1869. */
  1870. static getChunkGraphForChunk(chunk, deprecateMessage, deprecationCode) {
  1871. const fn = deprecateGetChunkGraphForChunkMap.get(deprecateMessage);
  1872. if (fn) return fn(chunk);
  1873. const newFn = util.deprecate(
  1874. /**
  1875. * Handles the callback logic for this hook.
  1876. * @param {Chunk} chunk the chunk
  1877. * @returns {ChunkGraph} the chunk graph
  1878. */
  1879. (chunk) => {
  1880. const chunkGraph = chunkGraphForChunkMap.get(chunk);
  1881. if (!chunkGraph) {
  1882. throw new Error(
  1883. `${
  1884. deprecateMessage
  1885. }There was no ChunkGraph assigned to the Chunk for backward-compat (Use the new API)`
  1886. );
  1887. }
  1888. return chunkGraph;
  1889. },
  1890. `${deprecateMessage}: Use new ChunkGraph API`,
  1891. deprecationCode
  1892. );
  1893. deprecateGetChunkGraphForChunkMap.set(deprecateMessage, newFn);
  1894. return newFn(chunk);
  1895. }
  1896. /**
  1897. * Sets chunk graph for chunk.
  1898. * @deprecated
  1899. * @param {Chunk} chunk the chunk
  1900. * @param {ChunkGraph} chunkGraph the chunk graph
  1901. * @returns {void}
  1902. */
  1903. static setChunkGraphForChunk(chunk, chunkGraph) {
  1904. chunkGraphForChunkMap.set(chunk, chunkGraph);
  1905. }
  1906. /**
  1907. * Clear chunk graph for chunk.
  1908. * @deprecated
  1909. * @param {Chunk} chunk the chunk
  1910. * @returns {void}
  1911. */
  1912. static clearChunkGraphForChunk(chunk) {
  1913. chunkGraphForChunkMap.delete(chunk);
  1914. }
  1915. // BACKWARD-COMPAT END
  1916. }
  1917. // TODO remove in webpack 6
  1918. /** @type {WeakMap<Module, ChunkGraph>} */
  1919. const chunkGraphForModuleMap = new WeakMap();
  1920. // TODO remove in webpack 6
  1921. /** @type {WeakMap<Chunk, ChunkGraph>} */
  1922. const chunkGraphForChunkMap = new WeakMap();
  1923. // TODO remove in webpack 6
  1924. /** @type {Map<string, (module: Module) => ChunkGraph>} */
  1925. const deprecateGetChunkGraphForModuleMap = new Map();
  1926. // TODO remove in webpack 6
  1927. /** @type {Map<string, (chunk: Chunk) => ChunkGraph>} */
  1928. const deprecateGetChunkGraphForChunkMap = new Map();
  1929. module.exports = ChunkGraph;