Chunk.js 21 KB

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