Chunk.js 23 KB

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