ChunkGraph.js 61 KB

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