Chunk.js 23 KB

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