Chunk.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const util = require("util");
  7. const SortableSet = require("./util/SortableSet");
  8. const intersect = require("./util/SetHelpers").intersect;
  9. const GraphHelpers = require("./GraphHelpers");
  10. const Entrypoint = require("./Entrypoint");
  11. let debugId = 1000;
  12. const ERR_CHUNK_ENTRY = "Chunk.entry was removed. Use hasRuntime()";
  13. const ERR_CHUNK_INITIAL =
  14. "Chunk.initial was removed. Use canBeInitial/isOnlyInitial()";
  15. /** @typedef {import("./Module")} Module */
  16. /** @typedef {import("./ChunkGroup")} ChunkGroup */
  17. /** @typedef {import("./ModuleReason")} ModuleReason */
  18. /** @typedef {import("webpack-sources").Source} Source */
  19. /** @typedef {import("./util/createHash").Hash} Hash */
  20. /**
  21. * @typedef {Object} WithId an object who has an id property *
  22. * @property {string | number} id the id of the object
  23. */
  24. /**
  25. * Compare two Modules based on their ids for sorting
  26. * @param {Module} a module
  27. * @param {Module} b module
  28. * @returns {-1|0|1} sort value
  29. */
  30. // TODO use @callback
  31. /** @typedef {(a: Module, b: Module) => -1|0|1} ModuleSortPredicate */
  32. /** @typedef {(m: Module) => boolean} ModuleFilterPredicate */
  33. /** @typedef {(c: Chunk) => boolean} ChunkFilterPredicate */
  34. const sortModuleById = (a, b) => {
  35. if (a.id < b.id) return -1;
  36. if (b.id < a.id) return 1;
  37. return 0;
  38. };
  39. /**
  40. * Compare two ChunkGroups based on their ids for sorting
  41. * @param {ChunkGroup} a chunk group
  42. * @param {ChunkGroup} b chunk group
  43. * @returns {-1|0|1} sort value
  44. */
  45. const sortChunkGroupById = (a, b) => {
  46. if (a.id < b.id) return -1;
  47. if (b.id < a.id) return 1;
  48. return 0;
  49. };
  50. /**
  51. * Compare two Identifiables , based on their ids for sorting
  52. * @param {Module} a first object with ident fn
  53. * @param {Module} b second object with ident fn
  54. * @returns {-1|0|1} The order number of the sort
  55. */
  56. const sortByIdentifier = (a, b) => {
  57. if (a.identifier() > b.identifier()) return 1;
  58. if (a.identifier() < b.identifier()) return -1;
  59. return 0;
  60. };
  61. /**
  62. * @returns {string} a concatenation of module identifiers sorted
  63. * @param {SortableSet} set to pull module identifiers from
  64. */
  65. const getModulesIdent = set => {
  66. set.sort();
  67. let str = "";
  68. for (const m of set) {
  69. str += m.identifier() + "#";
  70. }
  71. return str;
  72. };
  73. /**
  74. * @template T
  75. * @param {SortableSet<T>} set the sortable set to convert to array
  76. * @returns {Array<T>} the array returned from Array.from(set)
  77. */
  78. const getArray = set => Array.from(set);
  79. /**
  80. * @param {SortableSet<Module>} set the sortable Set to get the count/size of
  81. * @returns {number} the size of the modules
  82. */
  83. const getModulesSize = set => {
  84. let size = 0;
  85. for (const module of set) {
  86. size += module.size();
  87. }
  88. return size;
  89. };
  90. /**
  91. * A Chunk is a unit of encapsulation for Modules.
  92. * Chunks are "rendered" into bundles that get emitted when the build completes.
  93. */
  94. class Chunk {
  95. /**
  96. * @param {string=} name of chunk being created, is optional (for subclasses)
  97. */
  98. constructor(name) {
  99. /** @type {number | null} */
  100. this.id = null;
  101. /** @type {number[] | null} */
  102. this.ids = null;
  103. /** @type {number} */
  104. this.debugId = debugId++;
  105. /** @type {string} */
  106. this.name = name;
  107. /** @type {boolean} */
  108. this.preventIntegration = false;
  109. /** @type {Module=} */
  110. this.entryModule = undefined;
  111. /** @private @type {SortableSet<Module>} */
  112. this._modules = new SortableSet(undefined, sortByIdentifier);
  113. /** @type {string?} */
  114. this.filenameTemplate = undefined;
  115. /** @private @type {SortableSet<ChunkGroup>} */
  116. this._groups = new SortableSet(undefined, sortChunkGroupById);
  117. /** @type {string[]} */
  118. this.files = [];
  119. /** @type {boolean} */
  120. this.rendered = false;
  121. /** @type {string=} */
  122. this.hash = undefined;
  123. /** @type {Object} */
  124. this.contentHash = Object.create(null);
  125. /** @type {string=} */
  126. this.renderedHash = undefined;
  127. /** @type {string=} */
  128. this.chunkReason = undefined;
  129. /** @type {boolean} */
  130. this.extraAsync = false;
  131. this.removedModules = undefined;
  132. }
  133. /**
  134. * @deprecated Chunk.entry has been deprecated. Please use .hasRuntime() instead
  135. * @returns {never} Throws an error trying to access this property
  136. */
  137. get entry() {
  138. throw new Error(ERR_CHUNK_ENTRY);
  139. }
  140. /**
  141. * @deprecated .entry has been deprecated. Please use .hasRuntime() instead
  142. * @param {never} data The data that was attempting to be set
  143. * @returns {never} Throws an error trying to access this property
  144. */
  145. set entry(data) {
  146. throw new Error(ERR_CHUNK_ENTRY);
  147. }
  148. /**
  149. * @deprecated Chunk.initial was removed. Use canBeInitial/isOnlyInitial()
  150. * @returns {never} Throws an error trying to access this property
  151. */
  152. get initial() {
  153. throw new Error(ERR_CHUNK_INITIAL);
  154. }
  155. /**
  156. * @deprecated Chunk.initial was removed. Use canBeInitial/isOnlyInitial()
  157. * @param {never} data The data attempting to be set
  158. * @returns {never} Throws an error trying to access this property
  159. */
  160. set initial(data) {
  161. throw new Error(ERR_CHUNK_INITIAL);
  162. }
  163. /**
  164. * @returns {boolean} whether or not the Chunk will have a runtime
  165. */
  166. hasRuntime() {
  167. for (const chunkGroup of this._groups) {
  168. // We only need to check the first one
  169. return (
  170. chunkGroup.isInitial() &&
  171. chunkGroup instanceof Entrypoint &&
  172. chunkGroup.getRuntimeChunk() === this
  173. );
  174. }
  175. return false;
  176. }
  177. /**
  178. * @returns {boolean} whether or not this chunk can be an initial chunk
  179. */
  180. canBeInitial() {
  181. for (const chunkGroup of this._groups) {
  182. if (chunkGroup.isInitial()) return true;
  183. }
  184. return false;
  185. }
  186. /**
  187. * @returns {boolean} whether this chunk can only be an initial chunk
  188. */
  189. isOnlyInitial() {
  190. if (this._groups.size <= 0) return false;
  191. for (const chunkGroup of this._groups) {
  192. if (!chunkGroup.isInitial()) return false;
  193. }
  194. return true;
  195. }
  196. /**
  197. * @returns {boolean} if this chunk contains the entry module
  198. */
  199. hasEntryModule() {
  200. return !!this.entryModule;
  201. }
  202. /**
  203. * @param {Module} module the module that will be added to this chunk.
  204. * @returns {boolean} returns true if the chunk doesn't have the module and it was added
  205. */
  206. addModule(module) {
  207. if (!this._modules.has(module)) {
  208. this._modules.add(module);
  209. return true;
  210. }
  211. return false;
  212. }
  213. /**
  214. * @param {Module} module the module that will be removed from this chunk
  215. * @returns {boolean} returns true if chunk exists and is successfully deleted
  216. */
  217. removeModule(module) {
  218. if (this._modules.delete(module)) {
  219. module.removeChunk(this);
  220. return true;
  221. }
  222. return false;
  223. }
  224. /**
  225. * @param {Module[]} modules the new modules to be set
  226. * @returns {void} set new modules to this chunk and return nothing
  227. */
  228. setModules(modules) {
  229. this._modules = new SortableSet(modules, sortByIdentifier);
  230. }
  231. /**
  232. * @returns {number} the amount of modules in chunk
  233. */
  234. getNumberOfModules() {
  235. return this._modules.size;
  236. }
  237. /**
  238. * @returns {SortableSet} return the modules SortableSet for this chunk
  239. */
  240. get modulesIterable() {
  241. return this._modules;
  242. }
  243. /**
  244. * @param {ChunkGroup} chunkGroup the chunkGroup the chunk is being added
  245. * @returns {boolean} returns true if chunk is not apart of chunkGroup and is added successfully
  246. */
  247. addGroup(chunkGroup) {
  248. if (this._groups.has(chunkGroup)) return false;
  249. this._groups.add(chunkGroup);
  250. return true;
  251. }
  252. /**
  253. * @param {ChunkGroup} chunkGroup the chunkGroup the chunk is being removed from
  254. * @returns {boolean} returns true if chunk does exist in chunkGroup and is removed
  255. */
  256. removeGroup(chunkGroup) {
  257. if (!this._groups.has(chunkGroup)) return false;
  258. this._groups.delete(chunkGroup);
  259. return true;
  260. }
  261. /**
  262. * @param {ChunkGroup} chunkGroup the chunkGroup to check
  263. * @returns {boolean} returns true if chunk has chunkGroup reference and exists in chunkGroup
  264. */
  265. isInGroup(chunkGroup) {
  266. return this._groups.has(chunkGroup);
  267. }
  268. /**
  269. * @returns {number} the amount of groups said chunk is in
  270. */
  271. getNumberOfGroups() {
  272. return this._groups.size;
  273. }
  274. /**
  275. * @returns {SortableSet<ChunkGroup>} the chunkGroups that said chunk is referenced in
  276. */
  277. get groupsIterable() {
  278. return this._groups;
  279. }
  280. /**
  281. * @param {Chunk} otherChunk the chunk to compare itself with
  282. * @returns {-1|0|1} this is a comparitor function like sort and returns -1, 0, or 1 based on sort order
  283. */
  284. compareTo(otherChunk) {
  285. this._modules.sort();
  286. otherChunk._modules.sort();
  287. if (this._modules.size > otherChunk._modules.size) return -1;
  288. if (this._modules.size < otherChunk._modules.size) return 1;
  289. const a = this._modules[Symbol.iterator]();
  290. const b = otherChunk._modules[Symbol.iterator]();
  291. // eslint-disable-next-line no-constant-condition
  292. while (true) {
  293. const aItem = a.next();
  294. const bItem = b.next();
  295. if (aItem.done) return 0;
  296. const aModuleIdentifier = aItem.value.identifier();
  297. const bModuleIdentifier = bItem.value.identifier();
  298. if (aModuleIdentifier < bModuleIdentifier) return -1;
  299. if (aModuleIdentifier > bModuleIdentifier) return 1;
  300. }
  301. }
  302. /**
  303. * @param {Module} module Module to check
  304. * @returns {boolean} returns true if module does exist in this chunk
  305. */
  306. containsModule(module) {
  307. return this._modules.has(module);
  308. }
  309. getModules() {
  310. return this._modules.getFromCache(getArray);
  311. }
  312. getModulesIdent() {
  313. return this._modules.getFromUnorderedCache(getModulesIdent);
  314. }
  315. remove() {
  316. // cleanup modules
  317. // Array.from is used here to create a clone, because removeChunk modifies this._modules
  318. for (const module of Array.from(this._modules)) {
  319. module.removeChunk(this);
  320. }
  321. for (const chunkGroup of this._groups) {
  322. chunkGroup.removeChunk(this);
  323. }
  324. }
  325. /**
  326. *
  327. * @param {Module} module module to move
  328. * @param {Chunk} otherChunk other chunk to move it to
  329. * @returns {void}
  330. */
  331. moveModule(module, otherChunk) {
  332. GraphHelpers.disconnectChunkAndModule(this, module);
  333. GraphHelpers.connectChunkAndModule(otherChunk, module);
  334. module.rewriteChunkInReasons(this, [otherChunk]);
  335. }
  336. /**
  337. *
  338. * @param {Chunk} otherChunk the chunk to integrate with
  339. * @param {ModuleReason} reason reason why the module is being integrated
  340. * @returns {boolean} returns true or false if integration succeeds or fails
  341. */
  342. integrate(otherChunk, reason) {
  343. if (!this.canBeIntegrated(otherChunk)) {
  344. return false;
  345. }
  346. // Array.from is used here to create a clone, because moveModule modifies otherChunk._modules
  347. for (const module of Array.from(otherChunk._modules)) {
  348. otherChunk.moveModule(module, this);
  349. }
  350. otherChunk._modules.clear();
  351. for (const chunkGroup of otherChunk._groups) {
  352. chunkGroup.replaceChunk(otherChunk, this);
  353. this.addGroup(chunkGroup);
  354. }
  355. otherChunk._groups.clear();
  356. if (this.name && otherChunk.name) {
  357. if (this.name.length !== otherChunk.name.length) {
  358. this.name =
  359. this.name.length < otherChunk.name.length
  360. ? this.name
  361. : otherChunk.name;
  362. } else {
  363. this.name = this.name < otherChunk.name ? this.name : otherChunk.name;
  364. }
  365. }
  366. return true;
  367. }
  368. /**
  369. * @param {Chunk} newChunk the new chunk that will be split out of, and then chunk raphi twil=
  370. * @returns {void}
  371. */
  372. split(newChunk) {
  373. for (const chunkGroup of this._groups) {
  374. chunkGroup.insertChunk(newChunk, this);
  375. newChunk.addGroup(chunkGroup);
  376. }
  377. }
  378. isEmpty() {
  379. return this._modules.size === 0;
  380. }
  381. updateHash(hash) {
  382. hash.update(`${this.id} `);
  383. hash.update(this.ids ? this.ids.join(",") : "");
  384. hash.update(`${this.name || ""} `);
  385. for (const m of this._modules) {
  386. hash.update(m.hash);
  387. }
  388. }
  389. canBeIntegrated(otherChunk) {
  390. const isAvailable = (a, b) => {
  391. const queue = new Set(b.groupsIterable);
  392. for (const chunkGroup of queue) {
  393. if (a.isInGroup(chunkGroup)) continue;
  394. if (chunkGroup.isInitial()) return false;
  395. for (const parent of chunkGroup.parentsIterable) {
  396. queue.add(parent);
  397. }
  398. }
  399. return true;
  400. };
  401. if (this.preventIntegration || otherChunk.preventIntegration) {
  402. return false;
  403. }
  404. if (this.hasRuntime() !== otherChunk.hasRuntime()) {
  405. if (this.hasRuntime()) {
  406. return isAvailable(this, otherChunk);
  407. } else if (otherChunk.hasRuntime()) {
  408. return isAvailable(otherChunk, this);
  409. } else {
  410. return false;
  411. }
  412. }
  413. if (this.hasEntryModule() || otherChunk.hasEntryModule()) {
  414. return false;
  415. }
  416. return true;
  417. }
  418. /**
  419. *
  420. * @param {number} size the size
  421. * @param {Object} options the options passed in
  422. * @returns {number} the multiplier returned
  423. */
  424. addMultiplierAndOverhead(size, options) {
  425. const overhead =
  426. typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
  427. const multiplicator = this.canBeInitial()
  428. ? options.entryChunkMultiplicator || 10
  429. : 1;
  430. return size * multiplicator + overhead;
  431. }
  432. /**
  433. * @returns {number} the size of all modules
  434. */
  435. modulesSize() {
  436. return this._modules.getFromUnorderedCache(getModulesSize);
  437. }
  438. /**
  439. * @param {Object} options the size display options
  440. * @returns {number} the chunk size
  441. */
  442. size(options) {
  443. return this.addMultiplierAndOverhead(this.modulesSize(), options);
  444. }
  445. /**
  446. * @param {Chunk} otherChunk the other chunk
  447. * @param {TODO} options the options for this function
  448. * @returns {number | false} the size, or false if it can't be integrated
  449. */
  450. integratedSize(otherChunk, options) {
  451. // Chunk if it's possible to integrate this chunk
  452. if (!this.canBeIntegrated(otherChunk)) {
  453. return false;
  454. }
  455. let integratedModulesSize = this.modulesSize();
  456. // only count modules that do not exist in this chunk!
  457. for (const otherModule of otherChunk._modules) {
  458. if (!this._modules.has(otherModule)) {
  459. integratedModulesSize += otherModule.size();
  460. }
  461. }
  462. return this.addMultiplierAndOverhead(integratedModulesSize, options);
  463. }
  464. /**
  465. * @param {function(Module, Module): -1|0|1=} sortByFn a predicate function used to sort modules
  466. * @returns {void}
  467. */
  468. sortModules(sortByFn) {
  469. this._modules.sortWith(sortByFn || sortModuleById);
  470. }
  471. sortItems() {
  472. this.sortModules();
  473. }
  474. /**
  475. * @returns {Set<Chunk>} a set of all the async chunks
  476. */
  477. getAllAsyncChunks() {
  478. const queue = new Set();
  479. const chunks = new Set();
  480. const initialChunks = intersect(
  481. Array.from(this.groupsIterable, g => new Set(g.chunks))
  482. );
  483. for (const chunkGroup of this.groupsIterable) {
  484. for (const child of chunkGroup.childrenIterable) {
  485. queue.add(child);
  486. }
  487. }
  488. for (const chunkGroup of queue) {
  489. for (const chunk of chunkGroup.chunks) {
  490. if (!initialChunks.has(chunk)) {
  491. chunks.add(chunk);
  492. }
  493. }
  494. for (const child of chunkGroup.childrenIterable) {
  495. queue.add(child);
  496. }
  497. }
  498. return chunks;
  499. }
  500. /**
  501. * @typedef {Object} ChunkMaps
  502. * @property {Record<string|number, string>} hash
  503. * @property {Record<string|number, Record<string, string>>} contentHash
  504. * @property {Record<string|number, string>} name
  505. */
  506. /**
  507. * @param {boolean} realHash should the full hash or the rendered hash be used
  508. * @returns {ChunkMaps} the chunk map information
  509. */
  510. getChunkMaps(realHash) {
  511. /** @type {Record<string|number, string>} */
  512. const chunkHashMap = Object.create(null);
  513. /** @type {Record<string|number, Record<string, string>>} */
  514. const chunkContentHashMap = Object.create(null);
  515. /** @type {Record<string|number, string>} */
  516. const chunkNameMap = Object.create(null);
  517. for (const chunk of this.getAllAsyncChunks()) {
  518. chunkHashMap[chunk.id] = realHash ? chunk.hash : chunk.renderedHash;
  519. for (const key of Object.keys(chunk.contentHash)) {
  520. if (!chunkContentHashMap[key]) {
  521. chunkContentHashMap[key] = Object.create(null);
  522. }
  523. chunkContentHashMap[key][chunk.id] = chunk.contentHash[key];
  524. }
  525. if (chunk.name) {
  526. chunkNameMap[chunk.id] = chunk.name;
  527. }
  528. }
  529. return {
  530. hash: chunkHashMap,
  531. contentHash: chunkContentHashMap,
  532. name: chunkNameMap
  533. };
  534. }
  535. /**
  536. * @returns {Record<string, Set<TODO>[]>} a record object of names to lists of child ids(?)
  537. */
  538. getChildIdsByOrders() {
  539. const lists = new Map();
  540. for (const group of this.groupsIterable) {
  541. if (group.chunks[group.chunks.length - 1] === this) {
  542. for (const childGroup of group.childrenIterable) {
  543. // TODO webpack 5 remove this check for options
  544. if (typeof childGroup.options === "object") {
  545. for (const key of Object.keys(childGroup.options)) {
  546. if (key.endsWith("Order")) {
  547. const name = key.substr(0, key.length - "Order".length);
  548. let list = lists.get(name);
  549. if (list === undefined) lists.set(name, (list = []));
  550. list.push({
  551. order: childGroup.options[key],
  552. group: childGroup
  553. });
  554. }
  555. }
  556. }
  557. }
  558. }
  559. }
  560. const result = Object.create(null);
  561. for (const [name, list] of lists) {
  562. list.sort((a, b) => {
  563. const cmp = b.order - a.order;
  564. if (cmp !== 0) return cmp;
  565. // TODO webpack 5 remove this check of compareTo
  566. if (a.group.compareTo) {
  567. return a.group.compareTo(b.group);
  568. }
  569. return 0;
  570. });
  571. result[name] = Array.from(
  572. list.reduce((set, item) => {
  573. for (const chunk of item.group.chunks) {
  574. set.add(chunk.id);
  575. }
  576. return set;
  577. }, new Set())
  578. );
  579. }
  580. return result;
  581. }
  582. getChildIdsByOrdersMap(includeDirectChildren) {
  583. const chunkMaps = Object.create(null);
  584. const addChildIdsByOrdersToMap = chunk => {
  585. const data = chunk.getChildIdsByOrders();
  586. for (const key of Object.keys(data)) {
  587. let chunkMap = chunkMaps[key];
  588. if (chunkMap === undefined) {
  589. chunkMaps[key] = chunkMap = Object.create(null);
  590. }
  591. chunkMap[chunk.id] = data[key];
  592. }
  593. };
  594. if (includeDirectChildren) {
  595. addChildIdsByOrdersToMap(this);
  596. }
  597. for (const chunk of this.getAllAsyncChunks()) {
  598. addChildIdsByOrdersToMap(chunk);
  599. }
  600. return chunkMaps;
  601. }
  602. /**
  603. * @typedef {Object} ChunkModuleMaps
  604. * @property {Record<string|number, (string|number)[]>} id
  605. * @property {Record<string|number, string>} hash
  606. */
  607. /**
  608. * @param {ModuleFilterPredicate} filterFn function used to filter modules
  609. * @returns {ChunkModuleMaps} module map information
  610. */
  611. getChunkModuleMaps(filterFn) {
  612. /** @type {Record<string|number, (string|number)[]>} */
  613. const chunkModuleIdMap = Object.create(null);
  614. /** @type {Record<string|number, string>} */
  615. const chunkModuleHashMap = Object.create(null);
  616. for (const chunk of this.getAllAsyncChunks()) {
  617. /** @type {(string|number)[]} */
  618. let array;
  619. for (const module of chunk.modulesIterable) {
  620. if (filterFn(module)) {
  621. if (array === undefined) {
  622. array = [];
  623. chunkModuleIdMap[chunk.id] = array;
  624. }
  625. array.push(module.id);
  626. chunkModuleHashMap[module.id] = module.renderedHash;
  627. }
  628. }
  629. if (array !== undefined) {
  630. array.sort();
  631. }
  632. }
  633. return {
  634. id: chunkModuleIdMap,
  635. hash: chunkModuleHashMap
  636. };
  637. }
  638. /**
  639. *
  640. * @param {function(Module): boolean} filterFn predicate function used to filter modules
  641. * @param {function(Chunk): boolean} filterChunkFn predicate function used to filter chunks
  642. * @returns {boolean} return true if module exists in graph
  643. */
  644. hasModuleInGraph(filterFn, filterChunkFn) {
  645. const queue = new Set(this.groupsIterable);
  646. const chunksProcessed = new Set();
  647. for (const chunkGroup of queue) {
  648. for (const chunk of chunkGroup.chunks) {
  649. if (!chunksProcessed.has(chunk)) {
  650. chunksProcessed.add(chunk);
  651. if (!filterChunkFn || filterChunkFn(chunk)) {
  652. for (const module of chunk.modulesIterable) {
  653. if (filterFn(module)) {
  654. return true;
  655. }
  656. }
  657. }
  658. }
  659. }
  660. for (const child of chunkGroup.childrenIterable) {
  661. queue.add(child);
  662. }
  663. }
  664. return false;
  665. }
  666. toString() {
  667. return `Chunk[${Array.from(this._modules).join()}]`;
  668. }
  669. }
  670. // TODO remove in webpack 5
  671. Object.defineProperty(Chunk.prototype, "forEachModule", {
  672. configurable: false,
  673. value: util.deprecate(
  674. /**
  675. * @deprecated
  676. * @this {Chunk}
  677. * @typedef {function(any, any, Set<any>): void} ForEachModuleCallback
  678. * @param {ForEachModuleCallback} fn Callback function
  679. * @returns {void}
  680. */
  681. function(fn) {
  682. this._modules.forEach(fn);
  683. },
  684. "Chunk.forEachModule: Use for(const module of chunk.modulesIterable) instead"
  685. )
  686. });
  687. // TODO remove in webpack 5
  688. Object.defineProperty(Chunk.prototype, "mapModules", {
  689. configurable: false,
  690. value: util.deprecate(
  691. /**
  692. * @deprecated
  693. * @this {Chunk}
  694. * @typedef {function(any, number): any} MapModulesCallback
  695. * @param {MapModulesCallback} fn Callback function
  696. * @returns {TODO[]} result of mapped modules
  697. */
  698. function(fn) {
  699. return Array.from(this._modules, fn);
  700. },
  701. "Chunk.mapModules: Use Array.from(chunk.modulesIterable, fn) instead"
  702. )
  703. });
  704. // TODO remove in webpack 5
  705. Object.defineProperty(Chunk.prototype, "chunks", {
  706. configurable: false,
  707. get() {
  708. throw new Error("Chunk.chunks: Use ChunkGroup.getChildren() instead");
  709. },
  710. set() {
  711. throw new Error("Chunk.chunks: Use ChunkGroup.add/removeChild() instead");
  712. }
  713. });
  714. // TODO remove in webpack 5
  715. Object.defineProperty(Chunk.prototype, "parents", {
  716. configurable: false,
  717. get() {
  718. throw new Error("Chunk.parents: Use ChunkGroup.getParents() instead");
  719. },
  720. set() {
  721. throw new Error("Chunk.parents: Use ChunkGroup.add/removeParent() instead");
  722. }
  723. });
  724. // TODO remove in webpack 5
  725. Object.defineProperty(Chunk.prototype, "blocks", {
  726. configurable: false,
  727. get() {
  728. throw new Error("Chunk.blocks: Use ChunkGroup.getBlocks() instead");
  729. },
  730. set() {
  731. throw new Error("Chunk.blocks: Use ChunkGroup.add/removeBlock() instead");
  732. }
  733. });
  734. // TODO remove in webpack 5
  735. Object.defineProperty(Chunk.prototype, "entrypoints", {
  736. configurable: false,
  737. get() {
  738. throw new Error(
  739. "Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead"
  740. );
  741. },
  742. set() {
  743. throw new Error("Chunk.entrypoints: Use Chunks.addGroup instead");
  744. }
  745. });
  746. module.exports = Chunk;