source: imaps-frontend/node_modules/webpack/lib/ChunkGroup.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 15.4 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const util = require("util");
9const SortableSet = require("./util/SortableSet");
10const {
11 compareLocations,
12 compareChunks,
13 compareIterables
14} = require("./util/comparators");
15
16/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
17/** @typedef {import("./Chunk")} Chunk */
18/** @typedef {import("./ChunkGraph")} ChunkGraph */
19/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
20/** @typedef {import("./Entrypoint")} Entrypoint */
21/** @typedef {import("./Module")} Module */
22/** @typedef {import("./ModuleGraph")} ModuleGraph */
23
24/** @typedef {{id: number}} HasId */
25/** @typedef {{module: Module | null, loc: DependencyLocation, request: string}} OriginRecord */
26
27/**
28 * @typedef {object} RawChunkGroupOptions
29 * @property {number=} preloadOrder
30 * @property {number=} prefetchOrder
31 * @property {("low" | "high" | "auto")=} fetchPriority
32 */
33
34/** @typedef {RawChunkGroupOptions & { name?: string | null }} ChunkGroupOptions */
35
36let debugId = 5000;
37
38/**
39 * @template T
40 * @param {SortableSet<T>} set set to convert to array.
41 * @returns {T[]} the array format of existing set
42 */
43const getArray = set => Array.from(set);
44
45/**
46 * A convenience method used to sort chunks based on their id's
47 * @param {ChunkGroup} a first sorting comparator
48 * @param {ChunkGroup} b second sorting comparator
49 * @returns {1|0|-1} a sorting index to determine order
50 */
51const sortById = (a, b) => {
52 if (a.id < b.id) return -1;
53 if (b.id < a.id) return 1;
54 return 0;
55};
56
57/**
58 * @param {OriginRecord} a the first comparator in sort
59 * @param {OriginRecord} b the second comparator in sort
60 * @returns {1|-1|0} returns sorting order as index
61 */
62const sortOrigin = (a, b) => {
63 const aIdent = a.module ? a.module.identifier() : "";
64 const bIdent = b.module ? b.module.identifier() : "";
65 if (aIdent < bIdent) return -1;
66 if (aIdent > bIdent) return 1;
67 return compareLocations(a.loc, b.loc);
68};
69
70class ChunkGroup {
71 /**
72 * Creates an instance of ChunkGroup.
73 * @param {string | ChunkGroupOptions=} options chunk group options passed to chunkGroup
74 */
75 constructor(options) {
76 if (typeof options === "string") {
77 options = { name: options };
78 } else if (!options) {
79 options = { name: undefined };
80 }
81 /** @type {number} */
82 this.groupDebugId = debugId++;
83 this.options = /** @type {ChunkGroupOptions} */ (options);
84 /** @type {SortableSet<ChunkGroup>} */
85 this._children = new SortableSet(undefined, sortById);
86 /** @type {SortableSet<ChunkGroup>} */
87 this._parents = new SortableSet(undefined, sortById);
88 /** @type {SortableSet<ChunkGroup>} */
89 this._asyncEntrypoints = new SortableSet(undefined, sortById);
90 this._blocks = new SortableSet();
91 /** @type {Chunk[]} */
92 this.chunks = [];
93 /** @type {OriginRecord[]} */
94 this.origins = [];
95 /** Indices in top-down order */
96 /**
97 * @private
98 * @type {Map<Module, number>}
99 */
100 this._modulePreOrderIndices = new Map();
101 /** Indices in bottom-up order */
102 /**
103 * @private
104 * @type {Map<Module, number>}
105 */
106 this._modulePostOrderIndices = new Map();
107 /** @type {number | undefined} */
108 this.index = undefined;
109 }
110
111 /**
112 * when a new chunk is added to a chunkGroup, addingOptions will occur.
113 * @param {ChunkGroupOptions} options the chunkGroup options passed to addOptions
114 * @returns {void}
115 */
116 addOptions(options) {
117 for (const _key of Object.keys(options)) {
118 const key = /** @type {keyof ChunkGroupOptions} */ (_key);
119 if (this.options[key] === undefined) {
120 /** @type {TODO} */
121 (this.options)[key] = options[key];
122 } else if (this.options[key] !== options[key]) {
123 if (key.endsWith("Order")) {
124 /** @type {TODO} */
125 (this.options)[key] = Math.max(
126 /** @type {number} */ (this.options[key]),
127 /** @type {number} */ (options[key])
128 );
129 } else {
130 throw new Error(
131 `ChunkGroup.addOptions: No option merge strategy for ${key}`
132 );
133 }
134 }
135 }
136 }
137
138 /**
139 * returns the name of current ChunkGroup
140 * @returns {string | null | undefined} returns the ChunkGroup name
141 */
142 get name() {
143 return this.options.name;
144 }
145
146 /**
147 * sets a new name for current ChunkGroup
148 * @param {string | undefined} value the new name for ChunkGroup
149 * @returns {void}
150 */
151 set name(value) {
152 this.options.name = value;
153 }
154
155 /* istanbul ignore next */
156 /**
157 * get a uniqueId for ChunkGroup, made up of its member Chunk debugId's
158 * @returns {string} a unique concatenation of chunk debugId's
159 */
160 get debugId() {
161 return Array.from(this.chunks, x => x.debugId).join("+");
162 }
163
164 /**
165 * get a unique id for ChunkGroup, made up of its member Chunk id's
166 * @returns {string} a unique concatenation of chunk ids
167 */
168 get id() {
169 return Array.from(this.chunks, x => x.id).join("+");
170 }
171
172 /**
173 * Performs an unshift of a specific chunk
174 * @param {Chunk} chunk chunk being unshifted
175 * @returns {boolean} returns true if attempted chunk shift is accepted
176 */
177 unshiftChunk(chunk) {
178 const oldIdx = this.chunks.indexOf(chunk);
179 if (oldIdx > 0) {
180 this.chunks.splice(oldIdx, 1);
181 this.chunks.unshift(chunk);
182 } else if (oldIdx < 0) {
183 this.chunks.unshift(chunk);
184 return true;
185 }
186 return false;
187 }
188
189 /**
190 * inserts a chunk before another existing chunk in group
191 * @param {Chunk} chunk Chunk being inserted
192 * @param {Chunk} before Placeholder/target chunk marking new chunk insertion point
193 * @returns {boolean} return true if insertion was successful
194 */
195 insertChunk(chunk, before) {
196 const oldIdx = this.chunks.indexOf(chunk);
197 const idx = this.chunks.indexOf(before);
198 if (idx < 0) {
199 throw new Error("before chunk not found");
200 }
201 if (oldIdx >= 0 && oldIdx > idx) {
202 this.chunks.splice(oldIdx, 1);
203 this.chunks.splice(idx, 0, chunk);
204 } else if (oldIdx < 0) {
205 this.chunks.splice(idx, 0, chunk);
206 return true;
207 }
208 return false;
209 }
210
211 /**
212 * add a chunk into ChunkGroup. Is pushed on or prepended
213 * @param {Chunk} chunk chunk being pushed into ChunkGroupS
214 * @returns {boolean} returns true if chunk addition was successful.
215 */
216 pushChunk(chunk) {
217 const oldIdx = this.chunks.indexOf(chunk);
218 if (oldIdx >= 0) {
219 return false;
220 }
221 this.chunks.push(chunk);
222 return true;
223 }
224
225 /**
226 * @param {Chunk} oldChunk chunk to be replaced
227 * @param {Chunk} newChunk New chunk that will be replaced with
228 * @returns {boolean | undefined} returns true if the replacement was successful
229 */
230 replaceChunk(oldChunk, newChunk) {
231 const oldIdx = this.chunks.indexOf(oldChunk);
232 if (oldIdx < 0) return false;
233 const newIdx = this.chunks.indexOf(newChunk);
234 if (newIdx < 0) {
235 this.chunks[oldIdx] = newChunk;
236 return true;
237 }
238 if (newIdx < oldIdx) {
239 this.chunks.splice(oldIdx, 1);
240 return true;
241 } else if (newIdx !== oldIdx) {
242 this.chunks[oldIdx] = newChunk;
243 this.chunks.splice(newIdx, 1);
244 return true;
245 }
246 }
247
248 /**
249 * @param {Chunk} chunk chunk to remove
250 * @returns {boolean} returns true if chunk was removed
251 */
252 removeChunk(chunk) {
253 const idx = this.chunks.indexOf(chunk);
254 if (idx >= 0) {
255 this.chunks.splice(idx, 1);
256 return true;
257 }
258 return false;
259 }
260
261 /**
262 * @returns {boolean} true, when this chunk group will be loaded on initial page load
263 */
264 isInitial() {
265 return false;
266 }
267
268 /**
269 * @param {ChunkGroup} group chunk group to add
270 * @returns {boolean} returns true if chunk group was added
271 */
272 addChild(group) {
273 const size = this._children.size;
274 this._children.add(group);
275 return size !== this._children.size;
276 }
277
278 /**
279 * @returns {ChunkGroup[]} returns the children of this group
280 */
281 getChildren() {
282 return this._children.getFromCache(getArray);
283 }
284
285 getNumberOfChildren() {
286 return this._children.size;
287 }
288
289 get childrenIterable() {
290 return this._children;
291 }
292
293 /**
294 * @param {ChunkGroup} group the chunk group to remove
295 * @returns {boolean} returns true if the chunk group was removed
296 */
297 removeChild(group) {
298 if (!this._children.has(group)) {
299 return false;
300 }
301
302 this._children.delete(group);
303 group.removeParent(this);
304 return true;
305 }
306
307 /**
308 * @param {ChunkGroup} parentChunk the parent group to be added into
309 * @returns {boolean} returns true if this chunk group was added to the parent group
310 */
311 addParent(parentChunk) {
312 if (!this._parents.has(parentChunk)) {
313 this._parents.add(parentChunk);
314 return true;
315 }
316 return false;
317 }
318
319 /**
320 * @returns {ChunkGroup[]} returns the parents of this group
321 */
322 getParents() {
323 return this._parents.getFromCache(getArray);
324 }
325
326 getNumberOfParents() {
327 return this._parents.size;
328 }
329
330 /**
331 * @param {ChunkGroup} parent the parent group
332 * @returns {boolean} returns true if the parent group contains this group
333 */
334 hasParent(parent) {
335 return this._parents.has(parent);
336 }
337
338 get parentsIterable() {
339 return this._parents;
340 }
341
342 /**
343 * @param {ChunkGroup} chunkGroup the parent group
344 * @returns {boolean} returns true if this group has been removed from the parent
345 */
346 removeParent(chunkGroup) {
347 if (this._parents.delete(chunkGroup)) {
348 chunkGroup.removeChild(this);
349 return true;
350 }
351 return false;
352 }
353
354 /**
355 * @param {Entrypoint} entrypoint entrypoint to add
356 * @returns {boolean} returns true if entrypoint was added
357 */
358 addAsyncEntrypoint(entrypoint) {
359 const size = this._asyncEntrypoints.size;
360 this._asyncEntrypoints.add(entrypoint);
361 return size !== this._asyncEntrypoints.size;
362 }
363
364 get asyncEntrypointsIterable() {
365 return this._asyncEntrypoints;
366 }
367
368 /**
369 * @returns {Array<AsyncDependenciesBlock>} an array containing the blocks
370 */
371 getBlocks() {
372 return this._blocks.getFromCache(getArray);
373 }
374
375 getNumberOfBlocks() {
376 return this._blocks.size;
377 }
378
379 /**
380 * @param {AsyncDependenciesBlock} block block
381 * @returns {boolean} true, if block exists
382 */
383 hasBlock(block) {
384 return this._blocks.has(block);
385 }
386
387 /**
388 * @returns {Iterable<AsyncDependenciesBlock>} blocks
389 */
390 get blocksIterable() {
391 return this._blocks;
392 }
393
394 /**
395 * @param {AsyncDependenciesBlock} block a block
396 * @returns {boolean} false, if block was already added
397 */
398 addBlock(block) {
399 if (!this._blocks.has(block)) {
400 this._blocks.add(block);
401 return true;
402 }
403 return false;
404 }
405
406 /**
407 * @param {Module | null} module origin module
408 * @param {DependencyLocation} loc location of the reference in the origin module
409 * @param {string} request request name of the reference
410 * @returns {void}
411 */
412 addOrigin(module, loc, request) {
413 this.origins.push({
414 module,
415 loc,
416 request
417 });
418 }
419
420 /**
421 * @returns {string[]} the files contained this chunk group
422 */
423 getFiles() {
424 const files = new Set();
425
426 for (const chunk of this.chunks) {
427 for (const file of chunk.files) {
428 files.add(file);
429 }
430 }
431
432 return Array.from(files);
433 }
434
435 /**
436 * @returns {void}
437 */
438 remove() {
439 // cleanup parents
440 for (const parentChunkGroup of this._parents) {
441 // remove this chunk from its parents
442 parentChunkGroup._children.delete(this);
443
444 // cleanup "sub chunks"
445 for (const chunkGroup of this._children) {
446 /**
447 * remove this chunk as "intermediary" and connect
448 * it "sub chunks" and parents directly
449 */
450 // add parent to each "sub chunk"
451 chunkGroup.addParent(parentChunkGroup);
452 // add "sub chunk" to parent
453 parentChunkGroup.addChild(chunkGroup);
454 }
455 }
456
457 /**
458 * we need to iterate again over the children
459 * to remove this from the child's parents.
460 * This can not be done in the above loop
461 * as it is not guaranteed that `this._parents` contains anything.
462 */
463 for (const chunkGroup of this._children) {
464 // remove this as parent of every "sub chunk"
465 chunkGroup._parents.delete(this);
466 }
467
468 // remove chunks
469 for (const chunk of this.chunks) {
470 chunk.removeGroup(this);
471 }
472 }
473
474 sortItems() {
475 this.origins.sort(sortOrigin);
476 }
477
478 /**
479 * Sorting predicate which allows current ChunkGroup to be compared against another.
480 * Sorting values are based off of number of chunks in ChunkGroup.
481 * @param {ChunkGraph} chunkGraph the chunk graph
482 * @param {ChunkGroup} otherGroup the chunkGroup to compare this against
483 * @returns {-1|0|1} sort position for comparison
484 */
485 compareTo(chunkGraph, otherGroup) {
486 if (this.chunks.length > otherGroup.chunks.length) return -1;
487 if (this.chunks.length < otherGroup.chunks.length) return 1;
488 return compareIterables(compareChunks(chunkGraph))(
489 this.chunks,
490 otherGroup.chunks
491 );
492 }
493
494 /**
495 * @param {ModuleGraph} moduleGraph the module graph
496 * @param {ChunkGraph} chunkGraph the chunk graph
497 * @returns {Record<string, ChunkGroup[]>} mapping from children type to ordered list of ChunkGroups
498 */
499 getChildrenByOrders(moduleGraph, chunkGraph) {
500 /** @type {Map<string, {order: number, group: ChunkGroup}[]>} */
501 const lists = new Map();
502 for (const childGroup of this._children) {
503 for (const key of Object.keys(childGroup.options)) {
504 if (key.endsWith("Order")) {
505 const name = key.slice(0, key.length - "Order".length);
506 let list = lists.get(name);
507 if (list === undefined) {
508 lists.set(name, (list = []));
509 }
510 list.push({
511 order:
512 /** @type {number} */
513 (
514 childGroup.options[/** @type {keyof ChunkGroupOptions} */ (key)]
515 ),
516 group: childGroup
517 });
518 }
519 }
520 }
521 /** @type {Record<string, ChunkGroup[]>} */
522 const result = Object.create(null);
523 for (const [name, list] of lists) {
524 list.sort((a, b) => {
525 const cmp = b.order - a.order;
526 if (cmp !== 0) return cmp;
527 return a.group.compareTo(chunkGraph, b.group);
528 });
529 result[name] = list.map(i => i.group);
530 }
531 return result;
532 }
533
534 /**
535 * Sets the top-down index of a module in this ChunkGroup
536 * @param {Module} module module for which the index should be set
537 * @param {number} index the index of the module
538 * @returns {void}
539 */
540 setModulePreOrderIndex(module, index) {
541 this._modulePreOrderIndices.set(module, index);
542 }
543
544 /**
545 * Gets the top-down index of a module in this ChunkGroup
546 * @param {Module} module the module
547 * @returns {number | undefined} index
548 */
549 getModulePreOrderIndex(module) {
550 return this._modulePreOrderIndices.get(module);
551 }
552
553 /**
554 * Sets the bottom-up index of a module in this ChunkGroup
555 * @param {Module} module module for which the index should be set
556 * @param {number} index the index of the module
557 * @returns {void}
558 */
559 setModulePostOrderIndex(module, index) {
560 this._modulePostOrderIndices.set(module, index);
561 }
562
563 /**
564 * Gets the bottom-up index of a module in this ChunkGroup
565 * @param {Module} module the module
566 * @returns {number | undefined} index
567 */
568 getModulePostOrderIndex(module) {
569 return this._modulePostOrderIndices.get(module);
570 }
571
572 /* istanbul ignore next */
573 checkConstraints() {
574 const chunk = this;
575 for (const child of chunk._children) {
576 if (!child._parents.has(chunk)) {
577 throw new Error(
578 `checkConstraints: child missing parent ${chunk.debugId} -> ${child.debugId}`
579 );
580 }
581 }
582 for (const parentChunk of chunk._parents) {
583 if (!parentChunk._children.has(chunk)) {
584 throw new Error(
585 `checkConstraints: parent missing child ${parentChunk.debugId} <- ${chunk.debugId}`
586 );
587 }
588 }
589 }
590}
591
592ChunkGroup.prototype.getModuleIndex = util.deprecate(
593 ChunkGroup.prototype.getModulePreOrderIndex,
594 "ChunkGroup.getModuleIndex was renamed to getModulePreOrderIndex",
595 "DEP_WEBPACK_CHUNK_GROUP_GET_MODULE_INDEX"
596);
597
598ChunkGroup.prototype.getModuleIndex2 = util.deprecate(
599 ChunkGroup.prototype.getModulePostOrderIndex,
600 "ChunkGroup.getModuleIndex2 was renamed to getModulePostOrderIndex",
601 "DEP_WEBPACK_CHUNK_GROUP_GET_MODULE_INDEX_2"
602);
603
604module.exports = ChunkGroup;
Note: See TracBrowser for help on using the repository browser.