Chunk.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const ChunkGraph = require("./ChunkGraph");
  7. const Entrypoint = require("./Entrypoint");
  8. const { intersect } = require("./util/SetHelpers");
  9. const SortableSet = require("./util/SortableSet");
  10. const StringXor = require("./util/StringXor");
  11. const {
  12. compareChunkGroupsByIndex,
  13. compareModulesById,
  14. compareModulesByIdentifier
  15. } = require("./util/comparators");
  16. const { createArrayToSetDeprecationSet } = require("./util/deprecation");
  17. const { mergeRuntime } = require("./util/runtime");
  18. /** @typedef {import("./ChunkGraph").ChunkFilterPredicate} ChunkFilterPredicate */
  19. /** @typedef {import("./ChunkGraph").ChunkSizeOptions} ChunkSizeOptions */
  20. /** @typedef {import("./ChunkGraph").ModuleFilterPredicate} ModuleFilterPredicate */
  21. /** @typedef {import("./ChunkGraph").ModuleId} ModuleId */
  22. /** @typedef {import("./ChunkGroup")} ChunkGroup */
  23. /** @typedef {import("./ChunkGroup").ChunkGroupOptions} ChunkGroupOptions */
  24. /** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */
  25. /** @typedef {import("./Module")} Module */
  26. /** @typedef {import("./TemplatedPathPlugin").TemplatePath} TemplatePath */
  27. /** @typedef {import("./util/Hash")} Hash */
  28. /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
  29. /** @typedef {string | null} ChunkName */
  30. /** @typedef {string | number} ChunkId */
  31. /** @typedef {SortableSet<string>} IdNameHints */
  32. const ChunkFilesSet = createArrayToSetDeprecationSet("chunk.files");
  33. /**
  34. * Defines the chunk maps type used by this module.
  35. * @deprecated
  36. * @typedef {object} ChunkMaps
  37. * @property {Record<ChunkId, string>} hash
  38. * @property {Record<ChunkId, Record<string, string>>} contentHash
  39. * @property {Record<ChunkId, string>} name
  40. */
  41. /**
  42. * Defines the chunk module id map type used by this module.
  43. * @deprecated
  44. * @typedef {Record<ChunkId, ChunkId[]>} ChunkModuleIdMap
  45. */
  46. /**
  47. * Defines the chunk module hash map type used by this module.
  48. * @deprecated
  49. * @typedef {Record<ModuleId, string>} chunkModuleHashMap
  50. */
  51. /**
  52. * Defines the chunk module maps type used by this module.
  53. * @deprecated
  54. * @typedef {object} ChunkModuleMaps
  55. * @property {ChunkModuleIdMap} id
  56. * @property {chunkModuleHashMap} hash
  57. */
  58. /** @typedef {Set<Chunk>} Chunks */
  59. /** @typedef {Set<Entrypoint>} Entrypoints */
  60. /** @typedef {Set<ChunkGroup>} Queue */
  61. /** @typedef {SortableSet<ChunkGroup>} SortableChunkGroups */
  62. /** @typedef {Record<string, ChunkId[]>} ChunkChildIdsByOrdersMap */
  63. /** @typedef {Record<string, ChunkChildIdsByOrdersMap>} ChunkChildIdsByOrdersMapByData */
  64. /** @typedef {{ onChunks: Chunk[], chunks: Chunks }} ChunkChildOfTypeInOrder */
  65. let debugId = 1000;
  66. /**
  67. * A Chunk is a unit of encapsulation for Modules.
  68. * Chunks are "rendered" into bundles that get emitted when the build completes.
  69. */
  70. class Chunk {
  71. /**
  72. * Creates an instance of Chunk.
  73. * @param {ChunkName=} name of chunk being created, is optional (for subclasses)
  74. * @param {boolean} backCompat enable backward-compatibility
  75. */
  76. constructor(name, backCompat = true) {
  77. /** @type {ChunkId | null} */
  78. this.id = null;
  79. /** @type {ChunkId[] | null} */
  80. this.ids = null;
  81. /** @type {number} */
  82. this.debugId = debugId++;
  83. /** @type {ChunkName | undefined} */
  84. this.name = name;
  85. /** @type {IdNameHints} */
  86. this.idNameHints = new SortableSet();
  87. /** @type {boolean} */
  88. this.preventIntegration = false;
  89. /** @type {TemplatePath | undefined} */
  90. this.filenameTemplate = undefined;
  91. /** @type {TemplatePath | undefined} */
  92. this.cssFilenameTemplate = undefined;
  93. /**
  94. * @private
  95. * @type {SortableChunkGroups}
  96. */
  97. this._groups = new SortableSet(undefined, compareChunkGroupsByIndex);
  98. /** @type {RuntimeSpec} */
  99. this.runtime = undefined;
  100. /** @type {Set<string>} */
  101. this.files = backCompat ? new ChunkFilesSet() : new Set();
  102. /** @type {Set<string>} */
  103. this.auxiliaryFiles = new Set();
  104. /** @type {boolean} */
  105. this.rendered = false;
  106. /** @type {string=} */
  107. this.hash = undefined;
  108. /** @type {Record<string, string>} */
  109. this.contentHash = Object.create(null);
  110. /** @type {string=} */
  111. this.renderedHash = undefined;
  112. /** @type {string=} */
  113. this.chunkReason = undefined;
  114. /** @type {boolean} */
  115. this.extraAsync = false;
  116. }
  117. // TODO remove in webpack 6
  118. // BACKWARD-COMPAT START
  119. /**
  120. * Returns entry module.
  121. * @deprecated
  122. * @returns {Module | undefined} entry module
  123. */
  124. get entryModule() {
  125. const entryModules = [
  126. ...ChunkGraph.getChunkGraphForChunk(
  127. this,
  128. "Chunk.entryModule",
  129. "DEP_WEBPACK_CHUNK_ENTRY_MODULE"
  130. ).getChunkEntryModulesIterable(this)
  131. ];
  132. if (entryModules.length === 0) {
  133. return undefined;
  134. } else if (entryModules.length === 1) {
  135. return entryModules[0];
  136. }
  137. throw new Error(
  138. "Module.entryModule: Multiple entry modules are not supported by the deprecated API (Use the new ChunkGroup API)"
  139. );
  140. }
  141. /**
  142. * Checks whether this chunk has an entry module.
  143. * @deprecated
  144. * @returns {boolean} true, if the chunk contains an entry module
  145. */
  146. hasEntryModule() {
  147. return (
  148. ChunkGraph.getChunkGraphForChunk(
  149. this,
  150. "Chunk.hasEntryModule",
  151. "DEP_WEBPACK_CHUNK_HAS_ENTRY_MODULE"
  152. ).getNumberOfEntryModules(this) > 0
  153. );
  154. }
  155. /**
  156. * Adds the provided module to the chunk.
  157. * @deprecated
  158. * @param {Module} module the module
  159. * @returns {boolean} true, if the chunk could be added
  160. */
  161. addModule(module) {
  162. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  163. this,
  164. "Chunk.addModule",
  165. "DEP_WEBPACK_CHUNK_ADD_MODULE"
  166. );
  167. if (chunkGraph.isModuleInChunk(module, this)) return false;
  168. chunkGraph.connectChunkAndModule(this, module);
  169. return true;
  170. }
  171. /**
  172. * Removes the provided module from the chunk.
  173. * @deprecated
  174. * @param {Module} module the module
  175. * @returns {void}
  176. */
  177. removeModule(module) {
  178. ChunkGraph.getChunkGraphForChunk(
  179. this,
  180. "Chunk.removeModule",
  181. "DEP_WEBPACK_CHUNK_REMOVE_MODULE"
  182. ).disconnectChunkAndModule(this, module);
  183. }
  184. /**
  185. * Gets the number of modules in this chunk.
  186. * @deprecated
  187. * @returns {number} the number of module which are contained in this chunk
  188. */
  189. getNumberOfModules() {
  190. return ChunkGraph.getChunkGraphForChunk(
  191. this,
  192. "Chunk.getNumberOfModules",
  193. "DEP_WEBPACK_CHUNK_GET_NUMBER_OF_MODULES"
  194. ).getNumberOfChunkModules(this);
  195. }
  196. /**
  197. * @deprecated
  198. * @returns {Iterable<Module>} modules
  199. */
  200. get modulesIterable() {
  201. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  202. this,
  203. "Chunk.modulesIterable",
  204. "DEP_WEBPACK_CHUNK_MODULES_ITERABLE"
  205. );
  206. return chunkGraph.getOrderedChunkModulesIterable(
  207. this,
  208. compareModulesByIdentifier
  209. );
  210. }
  211. /**
  212. * Compares this chunk with another chunk.
  213. * @deprecated
  214. * @param {Chunk} otherChunk the chunk to compare with
  215. * @returns {-1 | 0 | 1} the comparison result
  216. */
  217. compareTo(otherChunk) {
  218. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  219. this,
  220. "Chunk.compareTo",
  221. "DEP_WEBPACK_CHUNK_COMPARE_TO"
  222. );
  223. return chunkGraph.compareChunks(this, otherChunk);
  224. }
  225. /**
  226. * Checks whether this chunk contains the module.
  227. * @deprecated
  228. * @param {Module} module the module
  229. * @returns {boolean} true, if the chunk contains the module
  230. */
  231. containsModule(module) {
  232. return ChunkGraph.getChunkGraphForChunk(
  233. this,
  234. "Chunk.containsModule",
  235. "DEP_WEBPACK_CHUNK_CONTAINS_MODULE"
  236. ).isModuleInChunk(module, this);
  237. }
  238. /**
  239. * Returns the modules for this chunk.
  240. * @deprecated
  241. * @returns {Module[]} the modules for this chunk
  242. */
  243. getModules() {
  244. return ChunkGraph.getChunkGraphForChunk(
  245. this,
  246. "Chunk.getModules",
  247. "DEP_WEBPACK_CHUNK_GET_MODULES"
  248. ).getChunkModules(this);
  249. }
  250. /**
  251. * Removes this chunk from the chunk graph and chunk groups.
  252. * @deprecated
  253. * @returns {void}
  254. */
  255. remove() {
  256. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  257. this,
  258. "Chunk.remove",
  259. "DEP_WEBPACK_CHUNK_REMOVE"
  260. );
  261. chunkGraph.disconnectChunk(this);
  262. this.disconnectFromGroups();
  263. }
  264. /**
  265. * Moves a module from this chunk to another chunk.
  266. * @deprecated
  267. * @param {Module} module the module
  268. * @param {Chunk} otherChunk the target chunk
  269. * @returns {void}
  270. */
  271. moveModule(module, otherChunk) {
  272. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  273. this,
  274. "Chunk.moveModule",
  275. "DEP_WEBPACK_CHUNK_MOVE_MODULE"
  276. );
  277. chunkGraph.disconnectChunkAndModule(this, module);
  278. chunkGraph.connectChunkAndModule(otherChunk, module);
  279. }
  280. /**
  281. * Integrates another chunk into this chunk when possible.
  282. * @deprecated
  283. * @param {Chunk} otherChunk the other chunk
  284. * @returns {boolean} true, if the specified chunk has been integrated
  285. */
  286. integrate(otherChunk) {
  287. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  288. this,
  289. "Chunk.integrate",
  290. "DEP_WEBPACK_CHUNK_INTEGRATE"
  291. );
  292. if (chunkGraph.canChunksBeIntegrated(this, otherChunk)) {
  293. chunkGraph.integrateChunks(this, otherChunk);
  294. return true;
  295. }
  296. return false;
  297. }
  298. /**
  299. * Checks whether this chunk can be integrated with another chunk.
  300. * @deprecated
  301. * @param {Chunk} otherChunk the other chunk
  302. * @returns {boolean} true, if chunks could be integrated
  303. */
  304. canBeIntegrated(otherChunk) {
  305. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  306. this,
  307. "Chunk.canBeIntegrated",
  308. "DEP_WEBPACK_CHUNK_CAN_BE_INTEGRATED"
  309. );
  310. return chunkGraph.canChunksBeIntegrated(this, otherChunk);
  311. }
  312. /**
  313. * Checks whether this chunk is empty.
  314. * @deprecated
  315. * @returns {boolean} true, if this chunk contains no module
  316. */
  317. isEmpty() {
  318. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  319. this,
  320. "Chunk.isEmpty",
  321. "DEP_WEBPACK_CHUNK_IS_EMPTY"
  322. );
  323. return chunkGraph.getNumberOfChunkModules(this) === 0;
  324. }
  325. /**
  326. * Returns the total size of all modules in this chunk.
  327. * @deprecated
  328. * @returns {number} total size of all modules in this chunk
  329. */
  330. modulesSize() {
  331. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  332. this,
  333. "Chunk.modulesSize",
  334. "DEP_WEBPACK_CHUNK_MODULES_SIZE"
  335. );
  336. return chunkGraph.getChunkModulesSize(this);
  337. }
  338. /**
  339. * Returns the estimated size for the requested source type.
  340. * @deprecated
  341. * @param {ChunkSizeOptions} options options object
  342. * @returns {number} total size of this chunk
  343. */
  344. size(options = {}) {
  345. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  346. this,
  347. "Chunk.size",
  348. "DEP_WEBPACK_CHUNK_SIZE"
  349. );
  350. return chunkGraph.getChunkSize(this, options);
  351. }
  352. /**
  353. * Returns the integrated size with another chunk.
  354. * @deprecated
  355. * @param {Chunk} otherChunk the other chunk
  356. * @param {ChunkSizeOptions} options options object
  357. * @returns {number} total size of the chunk or false if the chunk can't be integrated
  358. */
  359. integratedSize(otherChunk, options) {
  360. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  361. this,
  362. "Chunk.integratedSize",
  363. "DEP_WEBPACK_CHUNK_INTEGRATED_SIZE"
  364. );
  365. return chunkGraph.getIntegratedChunksSize(this, otherChunk, options);
  366. }
  367. /**
  368. * Gets chunk module maps.
  369. * @deprecated
  370. * @param {ModuleFilterPredicate} filterFn function used to filter modules
  371. * @returns {ChunkModuleMaps} module map information
  372. */
  373. getChunkModuleMaps(filterFn) {
  374. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  375. this,
  376. "Chunk.getChunkModuleMaps",
  377. "DEP_WEBPACK_CHUNK_GET_CHUNK_MODULE_MAPS"
  378. );
  379. /** @type {ChunkModuleIdMap} */
  380. const chunkModuleIdMap = Object.create(null);
  381. /** @type {chunkModuleHashMap} */
  382. const chunkModuleHashMap = Object.create(null);
  383. for (const asyncChunk of this.getAllAsyncChunks()) {
  384. /** @type {ChunkId[] | undefined} */
  385. let array;
  386. for (const module of chunkGraph.getOrderedChunkModulesIterable(
  387. asyncChunk,
  388. compareModulesById(chunkGraph)
  389. )) {
  390. if (filterFn(module)) {
  391. if (array === undefined) {
  392. array = [];
  393. chunkModuleIdMap[/** @type {ChunkId} */ (asyncChunk.id)] = array;
  394. }
  395. const moduleId =
  396. /** @type {ModuleId} */
  397. (chunkGraph.getModuleId(module));
  398. array.push(moduleId);
  399. chunkModuleHashMap[moduleId] = chunkGraph.getRenderedModuleHash(
  400. module,
  401. undefined
  402. );
  403. }
  404. }
  405. }
  406. return {
  407. id: chunkModuleIdMap,
  408. hash: chunkModuleHashMap
  409. };
  410. }
  411. /**
  412. * Checks whether this chunk contains a matching module in the graph.
  413. * @deprecated
  414. * @param {ModuleFilterPredicate} filterFn predicate function used to filter modules
  415. * @param {ChunkFilterPredicate=} filterChunkFn predicate function used to filter chunks
  416. * @returns {boolean} return true if module exists in graph
  417. */
  418. hasModuleInGraph(filterFn, filterChunkFn) {
  419. const chunkGraph = ChunkGraph.getChunkGraphForChunk(
  420. this,
  421. "Chunk.hasModuleInGraph",
  422. "DEP_WEBPACK_CHUNK_HAS_MODULE_IN_GRAPH"
  423. );
  424. return chunkGraph.hasModuleInGraph(this, filterFn, filterChunkFn);
  425. }
  426. /**
  427. * Returns the chunk map information.
  428. * @deprecated
  429. * @param {boolean} realHash whether the full hash or the rendered hash is to be used
  430. * @returns {ChunkMaps} the chunk map information
  431. */
  432. getChunkMaps(realHash) {
  433. /** @type {Record<ChunkId, string>} */
  434. const chunkHashMap = Object.create(null);
  435. /** @type {Record<string, Record<ChunkId, string>>} */
  436. const chunkContentHashMap = Object.create(null);
  437. /** @type {Record<ChunkId, string>} */
  438. const chunkNameMap = Object.create(null);
  439. for (const chunk of this.getAllAsyncChunks()) {
  440. const id = /** @type {ChunkId} */ (chunk.id);
  441. chunkHashMap[id] =
  442. /** @type {string} */
  443. (realHash ? chunk.hash : chunk.renderedHash);
  444. for (const key of Object.keys(chunk.contentHash)) {
  445. if (!chunkContentHashMap[key]) {
  446. chunkContentHashMap[key] = Object.create(null);
  447. }
  448. chunkContentHashMap[key][id] = chunk.contentHash[key];
  449. }
  450. if (chunk.name) {
  451. chunkNameMap[id] = chunk.name;
  452. }
  453. }
  454. return {
  455. hash: chunkHashMap,
  456. contentHash: chunkContentHashMap,
  457. name: chunkNameMap
  458. };
  459. }
  460. // BACKWARD-COMPAT END
  461. /**
  462. * Checks whether this chunk has runtime.
  463. * @returns {boolean} whether or not the Chunk will have a runtime
  464. */
  465. hasRuntime() {
  466. for (const chunkGroup of this._groups) {
  467. if (
  468. chunkGroup instanceof Entrypoint &&
  469. chunkGroup.getRuntimeChunk() === this
  470. ) {
  471. return true;
  472. }
  473. }
  474. return false;
  475. }
  476. /**
  477. * Checks whether it can be initial.
  478. * @returns {boolean} whether or not this chunk can be an initial chunk
  479. */
  480. canBeInitial() {
  481. for (const chunkGroup of this._groups) {
  482. if (chunkGroup.isInitial()) return true;
  483. }
  484. return false;
  485. }
  486. /**
  487. * Checks whether this chunk is only initial.
  488. * @returns {boolean} whether this chunk can only be an initial chunk
  489. */
  490. isOnlyInitial() {
  491. if (this._groups.size <= 0) return false;
  492. for (const chunkGroup of this._groups) {
  493. if (!chunkGroup.isInitial()) return false;
  494. }
  495. return true;
  496. }
  497. /**
  498. * Gets entry options.
  499. * @returns {EntryOptions | undefined} the entry options for this chunk
  500. */
  501. getEntryOptions() {
  502. for (const chunkGroup of this._groups) {
  503. if (chunkGroup instanceof Entrypoint) {
  504. return chunkGroup.options;
  505. }
  506. }
  507. return undefined;
  508. }
  509. /**
  510. * Adds the provided chunk group to the chunk.
  511. * @param {ChunkGroup} chunkGroup the chunkGroup the chunk is being added
  512. * @returns {void}
  513. */
  514. addGroup(chunkGroup) {
  515. this._groups.add(chunkGroup);
  516. }
  517. /**
  518. * Removes the provided chunk group from the chunk.
  519. * @param {ChunkGroup} chunkGroup the chunkGroup the chunk is being removed from
  520. * @returns {void}
  521. */
  522. removeGroup(chunkGroup) {
  523. this._groups.delete(chunkGroup);
  524. }
  525. /**
  526. * Checks whether this chunk is in group.
  527. * @param {ChunkGroup} chunkGroup the chunkGroup to check
  528. * @returns {boolean} returns true if chunk has chunkGroup reference and exists in chunkGroup
  529. */
  530. isInGroup(chunkGroup) {
  531. return this._groups.has(chunkGroup);
  532. }
  533. /**
  534. * Gets number of groups.
  535. * @returns {number} the amount of groups that the said chunk is in
  536. */
  537. getNumberOfGroups() {
  538. return this._groups.size;
  539. }
  540. /**
  541. * Gets groups iterable.
  542. * @returns {SortableChunkGroups} the chunkGroups that the said chunk is referenced in
  543. */
  544. get groupsIterable() {
  545. this._groups.sort();
  546. return this._groups;
  547. }
  548. /**
  549. * Disconnects from groups.
  550. * @returns {void}
  551. */
  552. disconnectFromGroups() {
  553. for (const chunkGroup of this._groups) {
  554. chunkGroup.removeChunk(this);
  555. }
  556. }
  557. /**
  558. * Processes the provided new chunk.
  559. * @param {Chunk} newChunk the new chunk that will be split out of
  560. * @returns {void}
  561. */
  562. split(newChunk) {
  563. for (const chunkGroup of this._groups) {
  564. chunkGroup.insertChunk(newChunk, this);
  565. newChunk.addGroup(chunkGroup);
  566. }
  567. for (const idHint of this.idNameHints) {
  568. newChunk.idNameHints.add(idHint);
  569. }
  570. newChunk.runtime = mergeRuntime(newChunk.runtime, this.runtime);
  571. }
  572. /**
  573. * Updates the hash with the data contributed by this instance.
  574. * @param {Hash} hash hash (will be modified)
  575. * @param {ChunkGraph} chunkGraph the chunk graph
  576. * @returns {void}
  577. */
  578. updateHash(hash, chunkGraph) {
  579. hash.update(
  580. `${this.id} ${this.ids ? this.ids.join() : ""} ${this.name || ""} `
  581. );
  582. const xor = new StringXor();
  583. for (const m of chunkGraph.getChunkModulesIterable(this)) {
  584. xor.add(chunkGraph.getModuleHash(m, this.runtime));
  585. }
  586. xor.updateHash(hash);
  587. const entryModules =
  588. chunkGraph.getChunkEntryModulesWithChunkGroupIterable(this);
  589. for (const [m, chunkGroup] of entryModules) {
  590. hash.update(
  591. `entry${chunkGraph.getModuleId(m)}${
  592. /** @type {ChunkGroup} */ (chunkGroup).id
  593. }`
  594. );
  595. }
  596. }
  597. /**
  598. * Gets all async chunks.
  599. * @returns {Chunks} a set of all the async chunks
  600. */
  601. getAllAsyncChunks() {
  602. /** @type {Queue} */
  603. const queue = new Set();
  604. /** @type {Chunks} */
  605. const chunks = new Set();
  606. const initialChunks = intersect(
  607. Array.from(this.groupsIterable, (g) => new Set(g.chunks))
  608. );
  609. /** @type {Queue} */
  610. const initialQueue = new Set(this.groupsIterable);
  611. for (const chunkGroup of initialQueue) {
  612. for (const child of chunkGroup.childrenIterable) {
  613. if (child instanceof Entrypoint) {
  614. initialQueue.add(child);
  615. } else {
  616. queue.add(child);
  617. }
  618. }
  619. }
  620. for (const chunkGroup of queue) {
  621. for (const chunk of chunkGroup.chunks) {
  622. if (!initialChunks.has(chunk)) {
  623. chunks.add(chunk);
  624. }
  625. }
  626. for (const child of chunkGroup.childrenIterable) {
  627. queue.add(child);
  628. }
  629. }
  630. return chunks;
  631. }
  632. /**
  633. * Gets all initial chunks.
  634. * @returns {Chunks} a set of all the initial chunks (including itself)
  635. */
  636. getAllInitialChunks() {
  637. /** @type {Chunks} */
  638. const chunks = new Set();
  639. /** @type {Queue} */
  640. const queue = new Set(this.groupsIterable);
  641. for (const group of queue) {
  642. if (group.isInitial()) {
  643. for (const c of group.chunks) chunks.add(c);
  644. for (const g of group.childrenIterable) queue.add(g);
  645. }
  646. }
  647. return chunks;
  648. }
  649. /**
  650. * Gets all referenced chunks.
  651. * @returns {Chunks} a set of all the referenced chunks (including itself)
  652. */
  653. getAllReferencedChunks() {
  654. /** @type {Queue} */
  655. const queue = new Set(this.groupsIterable);
  656. /** @type {Chunks} */
  657. const chunks = new Set();
  658. for (const chunkGroup of queue) {
  659. for (const chunk of chunkGroup.chunks) {
  660. chunks.add(chunk);
  661. }
  662. for (const child of chunkGroup.childrenIterable) {
  663. queue.add(child);
  664. }
  665. }
  666. return chunks;
  667. }
  668. /**
  669. * Gets all referenced async entrypoints.
  670. * @returns {Entrypoints} a set of all the referenced entrypoints
  671. */
  672. getAllReferencedAsyncEntrypoints() {
  673. /** @type {Queue} */
  674. const queue = new Set(this.groupsIterable);
  675. /** @type {Entrypoints} */
  676. const entrypoints = new Set();
  677. for (const chunkGroup of queue) {
  678. for (const entrypoint of chunkGroup.asyncEntrypointsIterable) {
  679. entrypoints.add(/** @type {Entrypoint} */ (entrypoint));
  680. }
  681. for (const child of chunkGroup.childrenIterable) {
  682. queue.add(child);
  683. }
  684. }
  685. return entrypoints;
  686. }
  687. /**
  688. * Checks whether this chunk has async chunks.
  689. * @returns {boolean} true, if the chunk references async chunks
  690. */
  691. hasAsyncChunks() {
  692. /** @type {Queue} */
  693. const queue = new Set();
  694. const initialChunks = intersect(
  695. Array.from(this.groupsIterable, (g) => new Set(g.chunks))
  696. );
  697. for (const chunkGroup of this.groupsIterable) {
  698. for (const child of chunkGroup.childrenIterable) {
  699. queue.add(child);
  700. }
  701. }
  702. for (const chunkGroup of queue) {
  703. for (const chunk of chunkGroup.chunks) {
  704. if (!initialChunks.has(chunk)) {
  705. return true;
  706. }
  707. }
  708. for (const child of chunkGroup.childrenIterable) {
  709. queue.add(child);
  710. }
  711. }
  712. return false;
  713. }
  714. /**
  715. * Gets child ids by orders.
  716. * @param {ChunkGraph} chunkGraph the chunk graph
  717. * @param {ChunkFilterPredicate=} filterFn function used to filter chunks
  718. * @returns {Record<string, ChunkId[]>} a record object of names to lists of child ids(?)
  719. */
  720. getChildIdsByOrders(chunkGraph, filterFn) {
  721. /** @type {Map<string, { order: number, group: ChunkGroup }[]>} */
  722. const lists = new Map();
  723. for (const group of this.groupsIterable) {
  724. if (group.chunks[group.chunks.length - 1] === this) {
  725. for (const childGroup of group.childrenIterable) {
  726. for (const key of Object.keys(childGroup.options)) {
  727. if (key.endsWith("Order")) {
  728. const name = key.slice(0, key.length - "Order".length);
  729. let list = lists.get(name);
  730. if (list === undefined) {
  731. list = [];
  732. lists.set(name, list);
  733. }
  734. list.push({
  735. order:
  736. /** @type {number} */
  737. (
  738. childGroup.options[
  739. /** @type {keyof ChunkGroupOptions} */
  740. (key)
  741. ]
  742. ),
  743. group: childGroup
  744. });
  745. }
  746. }
  747. }
  748. }
  749. }
  750. /** @type {Record<string, ChunkId[]>} */
  751. const result = Object.create(null);
  752. for (const [name, list] of lists) {
  753. list.sort((a, b) => {
  754. const cmp = b.order - a.order;
  755. if (cmp !== 0) return cmp;
  756. return a.group.compareTo(chunkGraph, b.group);
  757. });
  758. /** @type {Set<ChunkId>} */
  759. const chunkIdSet = new Set();
  760. for (const item of list) {
  761. for (const chunk of item.group.chunks) {
  762. if (filterFn && !filterFn(chunk, chunkGraph)) continue;
  763. chunkIdSet.add(/** @type {ChunkId} */ (chunk.id));
  764. }
  765. }
  766. if (chunkIdSet.size > 0) {
  767. result[name] = [...chunkIdSet];
  768. }
  769. }
  770. return result;
  771. }
  772. /**
  773. * Gets children of type in order.
  774. * @param {ChunkGraph} chunkGraph the chunk graph
  775. * @param {string} type option name
  776. * @returns {ChunkChildOfTypeInOrder[] | undefined} referenced chunks for a specific type
  777. */
  778. getChildrenOfTypeInOrder(chunkGraph, type) {
  779. /** @type {{ order: number, group: ChunkGroup, childGroup: ChunkGroup }[]} */
  780. const list = [];
  781. for (const group of this.groupsIterable) {
  782. for (const childGroup of group.childrenIterable) {
  783. const order =
  784. /** @type {number} */
  785. (childGroup.options[/** @type {keyof ChunkGroupOptions} */ (type)]);
  786. if (order === undefined) continue;
  787. list.push({
  788. order,
  789. group,
  790. childGroup
  791. });
  792. }
  793. }
  794. if (list.length === 0) return;
  795. list.sort((a, b) => {
  796. const cmp = b.order - a.order;
  797. if (cmp !== 0) return cmp;
  798. return a.group.compareTo(chunkGraph, b.group);
  799. });
  800. /** @type {ChunkChildOfTypeInOrder[]} */
  801. const result = [];
  802. /** @type {undefined | ChunkChildOfTypeInOrder} */
  803. let lastEntry;
  804. for (const { group, childGroup } of list) {
  805. if (lastEntry && lastEntry.onChunks === group.chunks) {
  806. for (const chunk of childGroup.chunks) {
  807. lastEntry.chunks.add(chunk);
  808. }
  809. } else {
  810. result.push(
  811. (lastEntry = {
  812. onChunks: group.chunks,
  813. chunks: new Set(childGroup.chunks)
  814. })
  815. );
  816. }
  817. }
  818. return result;
  819. }
  820. /**
  821. * Gets child ids by orders map.
  822. * @param {ChunkGraph} chunkGraph the chunk graph
  823. * @param {boolean=} includeDirectChildren include direct children (by default only children of async children are included)
  824. * @param {ChunkFilterPredicate=} filterFn function used to filter chunks
  825. * @returns {ChunkChildIdsByOrdersMapByData} a record object of names to lists of child ids(?) by chunk id
  826. */
  827. getChildIdsByOrdersMap(chunkGraph, includeDirectChildren, filterFn) {
  828. /** @type {ChunkChildIdsByOrdersMapByData} */
  829. const chunkMaps = Object.create(null);
  830. /**
  831. * Adds child ids by orders to map.
  832. * @param {Chunk} chunk a chunk
  833. * @returns {void}
  834. */
  835. const addChildIdsByOrdersToMap = (chunk) => {
  836. const data = chunk.getChildIdsByOrders(chunkGraph, filterFn);
  837. for (const key of Object.keys(data)) {
  838. let chunkMap = chunkMaps[key];
  839. if (chunkMap === undefined) {
  840. chunkMaps[key] = chunkMap = Object.create(null);
  841. }
  842. chunkMap[/** @type {ChunkId} */ (chunk.id)] = data[key];
  843. }
  844. };
  845. if (includeDirectChildren) {
  846. /** @type {Chunks} */
  847. const chunks = new Set();
  848. for (const chunkGroup of this.groupsIterable) {
  849. for (const chunk of chunkGroup.chunks) {
  850. chunks.add(chunk);
  851. }
  852. }
  853. for (const chunk of chunks) {
  854. addChildIdsByOrdersToMap(chunk);
  855. }
  856. }
  857. for (const chunk of this.getAllAsyncChunks()) {
  858. addChildIdsByOrdersToMap(chunk);
  859. }
  860. return chunkMaps;
  861. }
  862. /**
  863. * Checks whether this chunk contains the chunk graph.
  864. * @param {ChunkGraph} chunkGraph the chunk graph
  865. * @param {string} type option name
  866. * @param {boolean=} includeDirectChildren include direct children (by default only children of async children are included)
  867. * @param {ChunkFilterPredicate=} filterFn function used to filter chunks
  868. * @returns {boolean} true when the child is of type order, otherwise false
  869. */
  870. hasChildByOrder(chunkGraph, type, includeDirectChildren, filterFn) {
  871. if (includeDirectChildren) {
  872. /** @type {Chunks} */
  873. const chunks = new Set();
  874. for (const chunkGroup of this.groupsIterable) {
  875. for (const chunk of chunkGroup.chunks) {
  876. chunks.add(chunk);
  877. }
  878. }
  879. for (const chunk of chunks) {
  880. const data = chunk.getChildIdsByOrders(chunkGraph, filterFn);
  881. if (data[type] !== undefined) return true;
  882. }
  883. }
  884. for (const chunk of this.getAllAsyncChunks()) {
  885. const data = chunk.getChildIdsByOrders(chunkGraph, filterFn);
  886. if (data[type] !== undefined) return true;
  887. }
  888. return false;
  889. }
  890. }
  891. module.exports = Chunk;