ChunkGraph.js 49 KB

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