source: trip-planner-front/node_modules/webpack/lib/stats/DefaultStatsFactoryPlugin.js@ fa375fe

Last change on this file since fa375fe was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 69.1 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 ModuleDependency = require("../dependencies/ModuleDependency");
10const formatLocation = require("../formatLocation");
11const { LogType } = require("../logging/Logger");
12const AggressiveSplittingPlugin = require("../optimize/AggressiveSplittingPlugin");
13const SizeLimitsPlugin = require("../performance/SizeLimitsPlugin");
14const { countIterable } = require("../util/IterableHelpers");
15const {
16 compareLocations,
17 compareChunksById,
18 compareNumbers,
19 compareIds,
20 concatComparators,
21 compareSelect,
22 compareModulesByIdentifier
23} = require("../util/comparators");
24const { makePathsRelative, parseResource } = require("../util/identifier");
25
26/** @typedef {import("webpack-sources").Source} Source */
27/** @typedef {import("../Chunk")} Chunk */
28/** @typedef {import("../ChunkGroup")} ChunkGroup */
29/** @typedef {import("../ChunkGroup").OriginRecord} OriginRecord */
30/** @typedef {import("../Compilation")} Compilation */
31/** @typedef {import("../Compilation").Asset} Asset */
32/** @typedef {import("../Compilation").AssetInfo} AssetInfo */
33/** @typedef {import("../Compilation").NormalizedStatsOptions} NormalizedStatsOptions */
34/** @typedef {import("../Compiler")} Compiler */
35/** @typedef {import("../Dependency")} Dependency */
36/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
37/** @typedef {import("../Module")} Module */
38/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
39/** @typedef {import("../ModuleProfile")} ModuleProfile */
40/** @typedef {import("../RequestShortener")} RequestShortener */
41/** @typedef {import("../WebpackError")} WebpackError */
42/** @template T @typedef {import("../util/comparators").Comparator<T>} Comparator<T> */
43/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
44/** @typedef {import("../util/smartGrouping").GroupConfig<any, object>} GroupConfig */
45/** @typedef {import("./StatsFactory")} StatsFactory */
46/** @typedef {import("./StatsFactory").StatsFactoryContext} StatsFactoryContext */
47
48/** @typedef {KnownStatsCompilation & Record<string, any>} StatsCompilation */
49/**
50 * @typedef {Object} KnownStatsCompilation
51 * @property {any=} env
52 * @property {string=} name
53 * @property {string=} hash
54 * @property {string=} version
55 * @property {number=} time
56 * @property {number=} builtAt
57 * @property {boolean=} needAdditionalPass
58 * @property {string=} publicPath
59 * @property {string=} outputPath
60 * @property {Record<string, string[]>=} assetsByChunkName
61 * @property {StatsAsset[]=} assets
62 * @property {number=} filteredAssets
63 * @property {StatsChunk[]=} chunks
64 * @property {StatsModule[]=} modules
65 * @property {number=} filteredModules
66 * @property {Record<string, StatsChunkGroup>=} entrypoints
67 * @property {Record<string, StatsChunkGroup>=} namedChunkGroups
68 * @property {StatsError[]=} errors
69 * @property {number=} errorsCount
70 * @property {StatsError[]=} warnings
71 * @property {number=} warningsCount
72 * @property {StatsCompilation[]=} children
73 * @property {Record<string, StatsLogging>=} logging
74 */
75
76/** @typedef {KnownStatsLogging & Record<string, any>} StatsLogging */
77/**
78 * @typedef {Object} KnownStatsLogging
79 * @property {StatsLoggingEntry[]} entries
80 * @property {number} filteredEntries
81 * @property {boolean} debug
82 */
83
84/** @typedef {KnownStatsLoggingEntry & Record<string, any>} StatsLoggingEntry */
85/**
86 * @typedef {Object} KnownStatsLoggingEntry
87 * @property {string} type
88 * @property {string} message
89 * @property {string[]=} trace
90 * @property {StatsLoggingEntry[]=} children
91 * @property {any[]=} args
92 * @property {number=} time
93 */
94
95/** @typedef {KnownStatsAsset & Record<string, any>} StatsAsset */
96/**
97 * @typedef {Object} KnownStatsAsset
98 * @property {string} type
99 * @property {string} name
100 * @property {AssetInfo} info
101 * @property {number} size
102 * @property {boolean} emitted
103 * @property {boolean} comparedForEmit
104 * @property {boolean} cached
105 * @property {StatsAsset[]=} related
106 * @property {(string|number)[]=} chunkNames
107 * @property {(string|number)[]=} chunkIdHints
108 * @property {(string|number)[]=} chunks
109 * @property {(string|number)[]=} auxiliaryChunkNames
110 * @property {(string|number)[]=} auxiliaryChunks
111 * @property {(string|number)[]=} auxiliaryChunkIdHints
112 * @property {number=} filteredRelated
113 * @property {boolean=} isOverSizeLimit
114 */
115
116/** @typedef {KnownStatsChunkGroup & Record<string, any>} StatsChunkGroup */
117/**
118 * @typedef {Object} KnownStatsChunkGroup
119 * @property {string=} name
120 * @property {(string|number)[]=} chunks
121 * @property {({ name: string, size?: number })[]=} assets
122 * @property {number=} filteredAssets
123 * @property {number=} assetsSize
124 * @property {({ name: string, size?: number })[]=} auxiliaryAssets
125 * @property {number=} filteredAuxiliaryAssets
126 * @property {number=} auxiliaryAssetsSize
127 * @property {{ [x: string]: StatsChunkGroup[] }=} children
128 * @property {{ [x: string]: string[] }=} childAssets
129 * @property {boolean=} isOverSizeLimit
130 */
131
132/** @typedef {KnownStatsModule & Record<string, any>} StatsModule */
133/**
134 * @typedef {Object} KnownStatsModule
135 * @property {string=} type
136 * @property {string=} moduleType
137 * @property {string=} layer
138 * @property {string=} identifier
139 * @property {string=} name
140 * @property {string=} nameForCondition
141 * @property {number=} index
142 * @property {number=} preOrderIndex
143 * @property {number=} index2
144 * @property {number=} postOrderIndex
145 * @property {number=} size
146 * @property {{[x: string]: number}=} sizes
147 * @property {boolean=} cacheable
148 * @property {boolean=} built
149 * @property {boolean=} codeGenerated
150 * @property {boolean=} buildTimeExecuted
151 * @property {boolean=} cached
152 * @property {boolean=} optional
153 * @property {boolean=} orphan
154 * @property {string|number=} id
155 * @property {string|number=} issuerId
156 * @property {(string|number)[]=} chunks
157 * @property {(string|number)[]=} assets
158 * @property {boolean=} dependent
159 * @property {string=} issuer
160 * @property {string=} issuerName
161 * @property {StatsModuleIssuer[]=} issuerPath
162 * @property {boolean=} failed
163 * @property {number=} errors
164 * @property {number=} warnings
165 * @property {StatsProfile=} profile
166 * @property {StatsModuleReason[]=} reasons
167 * @property {(boolean | string[])=} usedExports
168 * @property {string[]=} providedExports
169 * @property {string[]=} optimizationBailout
170 * @property {number=} depth
171 * @property {StatsModule[]=} modules
172 * @property {number=} filteredModules
173 * @property {ReturnType<Source["source"]>=} source
174 */
175
176/** @typedef {KnownStatsProfile & Record<string, any>} StatsProfile */
177/**
178 * @typedef {Object} KnownStatsProfile
179 * @property {number} total
180 * @property {number} resolving
181 * @property {number} restoring
182 * @property {number} building
183 * @property {number} integration
184 * @property {number} storing
185 * @property {number} additionalResolving
186 * @property {number} additionalIntegration
187 * @property {number} factory
188 * @property {number} dependencies
189 */
190
191/** @typedef {KnownStatsModuleIssuer & Record<string, any>} StatsModuleIssuer */
192/**
193 * @typedef {Object} KnownStatsModuleIssuer
194 * @property {string=} identifier
195 * @property {string=} name
196 * @property {(string|number)=} id
197 * @property {StatsProfile=} profile
198 */
199
200/** @typedef {KnownStatsModuleReason & Record<string, any>} StatsModuleReason */
201/**
202 * @typedef {Object} KnownStatsModuleReason
203 * @property {string=} moduleIdentifier
204 * @property {string=} module
205 * @property {string=} moduleName
206 * @property {string=} resolvedModuleIdentifier
207 * @property {string=} resolvedModule
208 * @property {string=} type
209 * @property {boolean} active
210 * @property {string=} explanation
211 * @property {string=} userRequest
212 * @property {string=} loc
213 * @property {(string|number)=} moduleId
214 * @property {(string|number)=} resolvedModuleId
215 */
216
217/** @typedef {KnownStatsChunk & Record<string, any>} StatsChunk */
218/**
219 * @typedef {Object} KnownStatsChunk
220 * @property {boolean} rendered
221 * @property {boolean} initial
222 * @property {boolean} entry
223 * @property {boolean} recorded
224 * @property {string=} reason
225 * @property {number} size
226 * @property {Record<string, number>=} sizes
227 * @property {string[]=} names
228 * @property {string[]=} idHints
229 * @property {string[]=} runtime
230 * @property {string[]=} files
231 * @property {string[]=} auxiliaryFiles
232 * @property {string} hash
233 * @property {Record<string, (string|number)[]>=} childrenByOrder
234 * @property {(string|number)=} id
235 * @property {(string|number)[]=} siblings
236 * @property {(string|number)[]=} parents
237 * @property {(string|number)[]=} children
238 * @property {StatsModule[]=} modules
239 * @property {number=} filteredModules
240 * @property {StatsChunkOrigin[]=} origins
241 */
242
243/** @typedef {KnownStatsChunkOrigin & Record<string, any>} StatsChunkOrigin */
244/**
245 * @typedef {Object} KnownStatsChunkOrigin
246 * @property {string=} module
247 * @property {string=} moduleIdentifier
248 * @property {string=} moduleName
249 * @property {string=} loc
250 * @property {string=} request
251 * @property {(string|number)=} moduleId
252 */
253
254/** @typedef {KnownStatsModuleTraceItem & Record<string, any>} StatsModuleTraceItem */
255/**
256 * @typedef {Object} KnownStatsModuleTraceItem
257 * @property {string=} originIdentifier
258 * @property {string=} originName
259 * @property {string=} moduleIdentifier
260 * @property {string=} moduleName
261 * @property {StatsModuleTraceDependency[]=} dependencies
262 * @property {(string|number)=} originId
263 * @property {(string|number)=} moduleId
264 */
265
266/** @typedef {KnownStatsModuleTraceDependency & Record<string, any>} StatsModuleTraceDependency */
267/**
268 * @typedef {Object} KnownStatsModuleTraceDependency
269 * @property {string=} loc
270 */
271
272/** @typedef {KnownStatsError & Record<string, any>} StatsError */
273/**
274 * @typedef {Object} KnownStatsError
275 * @property {string} message
276 * @property {string=} chunkName
277 * @property {boolean=} chunkEntry
278 * @property {boolean=} chunkInitial
279 * @property {string=} file
280 * @property {string=} moduleIdentifier
281 * @property {string=} moduleName
282 * @property {string=} loc
283 * @property {string|number=} chunkId
284 * @property {string|number=} moduleId
285 * @property {StatsModuleTraceItem[]=} moduleTrace
286 * @property {any=} details
287 * @property {string=} stack
288 */
289
290/** @typedef {Asset & { type: string, related: PreprocessedAsset[] }} PreprocessedAsset */
291
292/**
293 * @template T
294 * @template O
295 * @typedef {Record<string, (object: O, data: T, context: StatsFactoryContext, options: NormalizedStatsOptions, factory: StatsFactory) => void>} ExtractorsByOption
296 */
297
298/**
299 * @typedef {Object} SimpleExtractors
300 * @property {ExtractorsByOption<Compilation, StatsCompilation>} compilation
301 * @property {ExtractorsByOption<PreprocessedAsset, StatsAsset>} asset
302 * @property {ExtractorsByOption<PreprocessedAsset, StatsAsset>} asset$visible
303 * @property {ExtractorsByOption<{ name: string, chunkGroup: ChunkGroup }, StatsChunkGroup>} chunkGroup
304 * @property {ExtractorsByOption<Module, StatsModule>} module
305 * @property {ExtractorsByOption<Module, StatsModule>} module$visible
306 * @property {ExtractorsByOption<Module, StatsModuleIssuer>} moduleIssuer
307 * @property {ExtractorsByOption<ModuleProfile, StatsProfile>} profile
308 * @property {ExtractorsByOption<ModuleGraphConnection, StatsModuleReason>} moduleReason
309 * @property {ExtractorsByOption<Chunk, StatsChunk>} chunk
310 * @property {ExtractorsByOption<OriginRecord, StatsChunkOrigin>} chunkOrigin
311 * @property {ExtractorsByOption<WebpackError, StatsError>} error
312 * @property {ExtractorsByOption<WebpackError, StatsError>} warning
313 * @property {ExtractorsByOption<{ origin: Module, module: Module }, StatsModuleTraceItem>} moduleTraceItem
314 * @property {ExtractorsByOption<Dependency, StatsModuleTraceDependency>} moduleTraceDependency
315 */
316
317/**
318 * @template T
319 * @template I
320 * @param {Iterable<T>} items items to select from
321 * @param {function(T): Iterable<I>} selector selector function to select values from item
322 * @returns {I[]} array of values
323 */
324const uniqueArray = (items, selector) => {
325 /** @type {Set<I>} */
326 const set = new Set();
327 for (const item of items) {
328 for (const i of selector(item)) {
329 set.add(i);
330 }
331 }
332 return Array.from(set);
333};
334
335/**
336 * @template T
337 * @template I
338 * @param {Iterable<T>} items items to select from
339 * @param {function(T): Iterable<I>} selector selector function to select values from item
340 * @param {Comparator<I>} comparator comparator function
341 * @returns {I[]} array of values
342 */
343const uniqueOrderedArray = (items, selector, comparator) => {
344 return uniqueArray(items, selector).sort(comparator);
345};
346
347/** @template T @template R @typedef {{ [P in keyof T]: R }} MappedValues<T, R> */
348
349/**
350 * @template T
351 * @template R
352 * @param {T} obj object to be mapped
353 * @param {function(T[keyof T], keyof T): R} fn mapping function
354 * @returns {MappedValues<T, R>} mapped object
355 */
356const mapObject = (obj, fn) => {
357 const newObj = Object.create(null);
358 for (const key of Object.keys(obj)) {
359 newObj[key] = fn(obj[key], /** @type {keyof T} */ (key));
360 }
361 return newObj;
362};
363
364/**
365 * @param {Compilation} compilation the compilation
366 * @param {function(Compilation, string): any[]} getItems get items
367 * @returns {number} total number
368 */
369const countWithChildren = (compilation, getItems) => {
370 let count = getItems(compilation, "").length;
371 for (const child of compilation.children) {
372 count += countWithChildren(child, (c, type) =>
373 getItems(c, `.children[].compilation${type}`)
374 );
375 }
376 return count;
377};
378
379/** @type {ExtractorsByOption<WebpackError | string, StatsError>} */
380const EXTRACT_ERROR = {
381 _: (object, error, context, { requestShortener }) => {
382 // TODO webpack 6 disallow strings in the errors/warnings list
383 if (typeof error === "string") {
384 object.message = error;
385 } else {
386 if (error.chunk) {
387 object.chunkName = error.chunk.name;
388 object.chunkEntry = error.chunk.hasRuntime();
389 object.chunkInitial = error.chunk.canBeInitial();
390 }
391 if (error.file) {
392 object.file = error.file;
393 }
394 if (error.module) {
395 object.moduleIdentifier = error.module.identifier();
396 object.moduleName = error.module.readableIdentifier(requestShortener);
397 }
398 if (error.loc) {
399 object.loc = formatLocation(error.loc);
400 }
401 object.message = error.message;
402 }
403 },
404 ids: (object, error, { compilation: { chunkGraph } }) => {
405 if (typeof error !== "string") {
406 if (error.chunk) {
407 object.chunkId = error.chunk.id;
408 }
409 if (error.module) {
410 object.moduleId = chunkGraph.getModuleId(error.module);
411 }
412 }
413 },
414 moduleTrace: (object, error, context, options, factory) => {
415 if (typeof error !== "string" && error.module) {
416 const {
417 type,
418 compilation: { moduleGraph }
419 } = context;
420 /** @type {Set<Module>} */
421 const visitedModules = new Set();
422 const moduleTrace = [];
423 let current = error.module;
424 while (current) {
425 if (visitedModules.has(current)) break; // circular (technically impossible, but how knows)
426 visitedModules.add(current);
427 const origin = moduleGraph.getIssuer(current);
428 if (!origin) break;
429 moduleTrace.push({ origin, module: current });
430 current = origin;
431 }
432 object.moduleTrace = factory.create(
433 `${type}.moduleTrace`,
434 moduleTrace,
435 context
436 );
437 }
438 },
439 errorDetails: (
440 object,
441 error,
442 { type, compilation, cachedGetErrors, cachedGetWarnings },
443 { errorDetails }
444 ) => {
445 if (
446 typeof error !== "string" &&
447 (errorDetails === true ||
448 (type.endsWith(".error") && cachedGetErrors(compilation).length < 3))
449 ) {
450 object.details = error.details;
451 }
452 },
453 errorStack: (object, error) => {
454 if (typeof error !== "string") {
455 object.stack = error.stack;
456 }
457 }
458};
459
460/** @type {SimpleExtractors} */
461const SIMPLE_EXTRACTORS = {
462 compilation: {
463 _: (object, compilation, context, options) => {
464 if (!context.makePathsRelative) {
465 context.makePathsRelative = makePathsRelative.bindContextCache(
466 compilation.compiler.context,
467 compilation.compiler.root
468 );
469 }
470 if (!context.cachedGetErrors) {
471 const map = new WeakMap();
472 context.cachedGetErrors = compilation => {
473 return (
474 map.get(compilation) ||
475 (errors => (map.set(compilation, errors), errors))(
476 compilation.getErrors()
477 )
478 );
479 };
480 }
481 if (!context.cachedGetWarnings) {
482 const map = new WeakMap();
483 context.cachedGetWarnings = compilation => {
484 return (
485 map.get(compilation) ||
486 (warnings => (map.set(compilation, warnings), warnings))(
487 compilation.getWarnings()
488 )
489 );
490 };
491 }
492 if (compilation.name) {
493 object.name = compilation.name;
494 }
495 if (compilation.needAdditionalPass) {
496 object.needAdditionalPass = true;
497 }
498
499 const { logging, loggingDebug, loggingTrace } = options;
500 if (logging || (loggingDebug && loggingDebug.length > 0)) {
501 const util = require("util");
502 object.logging = {};
503 let acceptedTypes;
504 let collapsedGroups = false;
505 switch (logging) {
506 default:
507 acceptedTypes = new Set();
508 break;
509 case "error":
510 acceptedTypes = new Set([LogType.error]);
511 break;
512 case "warn":
513 acceptedTypes = new Set([LogType.error, LogType.warn]);
514 break;
515 case "info":
516 acceptedTypes = new Set([
517 LogType.error,
518 LogType.warn,
519 LogType.info
520 ]);
521 break;
522 case "log":
523 acceptedTypes = new Set([
524 LogType.error,
525 LogType.warn,
526 LogType.info,
527 LogType.log,
528 LogType.group,
529 LogType.groupEnd,
530 LogType.groupCollapsed,
531 LogType.clear
532 ]);
533 break;
534 case "verbose":
535 acceptedTypes = new Set([
536 LogType.error,
537 LogType.warn,
538 LogType.info,
539 LogType.log,
540 LogType.group,
541 LogType.groupEnd,
542 LogType.groupCollapsed,
543 LogType.profile,
544 LogType.profileEnd,
545 LogType.time,
546 LogType.status,
547 LogType.clear
548 ]);
549 collapsedGroups = true;
550 break;
551 }
552 const cachedMakePathsRelative = makePathsRelative.bindContextCache(
553 options.context,
554 compilation.compiler.root
555 );
556 let depthInCollapsedGroup = 0;
557 for (const [origin, logEntries] of compilation.logging) {
558 const debugMode = loggingDebug.some(fn => fn(origin));
559 if (logging === false && !debugMode) continue;
560 /** @type {KnownStatsLoggingEntry[]} */
561 const groupStack = [];
562 /** @type {KnownStatsLoggingEntry[]} */
563 const rootList = [];
564 let currentList = rootList;
565 let processedLogEntries = 0;
566 for (const entry of logEntries) {
567 let type = entry.type;
568 if (!debugMode && !acceptedTypes.has(type)) continue;
569
570 // Expand groups in verbose and debug modes
571 if (
572 type === LogType.groupCollapsed &&
573 (debugMode || collapsedGroups)
574 )
575 type = LogType.group;
576
577 if (depthInCollapsedGroup === 0) {
578 processedLogEntries++;
579 }
580
581 if (type === LogType.groupEnd) {
582 groupStack.pop();
583 if (groupStack.length > 0) {
584 currentList = groupStack[groupStack.length - 1].children;
585 } else {
586 currentList = rootList;
587 }
588 if (depthInCollapsedGroup > 0) depthInCollapsedGroup--;
589 continue;
590 }
591 let message = undefined;
592 if (entry.type === LogType.time) {
593 message = `${entry.args[0]}: ${
594 entry.args[1] * 1000 + entry.args[2] / 1000000
595 } ms`;
596 } else if (entry.args && entry.args.length > 0) {
597 message = util.format(entry.args[0], ...entry.args.slice(1));
598 }
599 /** @type {KnownStatsLoggingEntry} */
600 const newEntry = {
601 ...entry,
602 type,
603 message,
604 trace: loggingTrace ? entry.trace : undefined,
605 children:
606 type === LogType.group || type === LogType.groupCollapsed
607 ? []
608 : undefined
609 };
610 currentList.push(newEntry);
611 if (newEntry.children) {
612 groupStack.push(newEntry);
613 currentList = newEntry.children;
614 if (depthInCollapsedGroup > 0) {
615 depthInCollapsedGroup++;
616 } else if (type === LogType.groupCollapsed) {
617 depthInCollapsedGroup = 1;
618 }
619 }
620 }
621 let name = cachedMakePathsRelative(origin).replace(/\|/g, " ");
622 if (name in object.logging) {
623 let i = 1;
624 while (`${name}#${i}` in object.logging) {
625 i++;
626 }
627 name = `${name}#${i}`;
628 }
629 object.logging[name] = {
630 entries: rootList,
631 filteredEntries: logEntries.length - processedLogEntries,
632 debug: debugMode
633 };
634 }
635 }
636 },
637 hash: (object, compilation) => {
638 object.hash = compilation.hash;
639 },
640 version: object => {
641 object.version = require("../../package.json").version;
642 },
643 env: (object, compilation, context, { _env }) => {
644 object.env = _env;
645 },
646 timings: (object, compilation) => {
647 object.time = compilation.endTime - compilation.startTime;
648 },
649 builtAt: (object, compilation) => {
650 object.builtAt = compilation.endTime;
651 },
652 publicPath: (object, compilation) => {
653 object.publicPath = compilation.getPath(
654 compilation.outputOptions.publicPath
655 );
656 },
657 outputPath: (object, compilation) => {
658 object.outputPath = compilation.outputOptions.path;
659 },
660 assets: (object, compilation, context, options, factory) => {
661 const { type } = context;
662 /** @type {Map<string, Chunk[]>} */
663 const compilationFileToChunks = new Map();
664 /** @type {Map<string, Chunk[]>} */
665 const compilationAuxiliaryFileToChunks = new Map();
666 for (const chunk of compilation.chunks) {
667 for (const file of chunk.files) {
668 let array = compilationFileToChunks.get(file);
669 if (array === undefined) {
670 array = [];
671 compilationFileToChunks.set(file, array);
672 }
673 array.push(chunk);
674 }
675 for (const file of chunk.auxiliaryFiles) {
676 let array = compilationAuxiliaryFileToChunks.get(file);
677 if (array === undefined) {
678 array = [];
679 compilationAuxiliaryFileToChunks.set(file, array);
680 }
681 array.push(chunk);
682 }
683 }
684 /** @type {Map<string, PreprocessedAsset>} */
685 const assetMap = new Map();
686 /** @type {Set<PreprocessedAsset>} */
687 const assets = new Set();
688 for (const asset of compilation.getAssets()) {
689 /** @type {PreprocessedAsset} */
690 const item = {
691 ...asset,
692 type: "asset",
693 related: undefined
694 };
695 assets.add(item);
696 assetMap.set(asset.name, item);
697 }
698 for (const item of assetMap.values()) {
699 const related = item.info.related;
700 if (!related) continue;
701 for (const type of Object.keys(related)) {
702 const relatedEntry = related[type];
703 const deps = Array.isArray(relatedEntry)
704 ? relatedEntry
705 : [relatedEntry];
706 for (const dep of deps) {
707 const depItem = assetMap.get(dep);
708 if (!depItem) continue;
709 assets.delete(depItem);
710 depItem.type = type;
711 item.related = item.related || [];
712 item.related.push(depItem);
713 }
714 }
715 }
716
717 object.assetsByChunkName = {};
718 for (const [file, chunks] of compilationFileToChunks) {
719 for (const chunk of chunks) {
720 const name = chunk.name;
721 if (!name) continue;
722 if (
723 !Object.prototype.hasOwnProperty.call(
724 object.assetsByChunkName,
725 name
726 )
727 ) {
728 object.assetsByChunkName[name] = [];
729 }
730 object.assetsByChunkName[name].push(file);
731 }
732 }
733
734 const groupedAssets = factory.create(
735 `${type}.assets`,
736 Array.from(assets),
737 {
738 ...context,
739 compilationFileToChunks,
740 compilationAuxiliaryFileToChunks
741 }
742 );
743 const limited = spaceLimited(groupedAssets, options.assetsSpace);
744 object.assets = limited.children;
745 object.filteredAssets = limited.filteredChildren;
746 },
747 chunks: (object, compilation, context, options, factory) => {
748 const { type } = context;
749 object.chunks = factory.create(
750 `${type}.chunks`,
751 Array.from(compilation.chunks),
752 context
753 );
754 },
755 modules: (object, compilation, context, options, factory) => {
756 const { type } = context;
757 const array = Array.from(compilation.modules);
758 const groupedModules = factory.create(`${type}.modules`, array, context);
759 const limited = spaceLimited(groupedModules, options.modulesSpace);
760 object.modules = limited.children;
761 object.filteredModules = limited.filteredChildren;
762 },
763 entrypoints: (
764 object,
765 compilation,
766 context,
767 { entrypoints, chunkGroups, chunkGroupAuxiliary, chunkGroupChildren },
768 factory
769 ) => {
770 const { type } = context;
771 const array = Array.from(compilation.entrypoints, ([key, value]) => ({
772 name: key,
773 chunkGroup: value
774 }));
775 if (entrypoints === "auto" && !chunkGroups) {
776 if (array.length > 5) return;
777 if (
778 !chunkGroupChildren &&
779 array.every(({ chunkGroup }) => {
780 if (chunkGroup.chunks.length !== 1) return false;
781 const chunk = chunkGroup.chunks[0];
782 return (
783 chunk.files.size === 1 &&
784 (!chunkGroupAuxiliary || chunk.auxiliaryFiles.size === 0)
785 );
786 })
787 ) {
788 return;
789 }
790 }
791 object.entrypoints = factory.create(
792 `${type}.entrypoints`,
793 array,
794 context
795 );
796 },
797 chunkGroups: (object, compilation, context, options, factory) => {
798 const { type } = context;
799 const array = Array.from(
800 compilation.namedChunkGroups,
801 ([key, value]) => ({
802 name: key,
803 chunkGroup: value
804 })
805 );
806 object.namedChunkGroups = factory.create(
807 `${type}.namedChunkGroups`,
808 array,
809 context
810 );
811 },
812 errors: (object, compilation, context, options, factory) => {
813 const { type, cachedGetErrors } = context;
814 object.errors = factory.create(
815 `${type}.errors`,
816 cachedGetErrors(compilation),
817 context
818 );
819 },
820 errorsCount: (object, compilation, { cachedGetErrors }) => {
821 object.errorsCount = countWithChildren(compilation, c =>
822 cachedGetErrors(c)
823 );
824 },
825 warnings: (object, compilation, context, options, factory) => {
826 const { type, cachedGetWarnings } = context;
827 object.warnings = factory.create(
828 `${type}.warnings`,
829 cachedGetWarnings(compilation),
830 context
831 );
832 },
833 warningsCount: (
834 object,
835 compilation,
836 context,
837 { warningsFilter },
838 factory
839 ) => {
840 const { type, cachedGetWarnings } = context;
841 object.warningsCount = countWithChildren(compilation, (c, childType) => {
842 if (!warningsFilter && warningsFilter.length === 0)
843 return cachedGetWarnings(c);
844 return factory
845 .create(`${type}${childType}.warnings`, cachedGetWarnings(c), context)
846 .filter(warning => {
847 const warningString = Object.keys(warning)
848 .map(key => `${warning[key]}`)
849 .join("\n");
850 return !warningsFilter.some(filter =>
851 filter(warning, warningString)
852 );
853 });
854 });
855 },
856 errorDetails: (
857 object,
858 compilation,
859 { cachedGetErrors, cachedGetWarnings },
860 { errorDetails, errors, warnings }
861 ) => {
862 if (errorDetails === "auto") {
863 if (warnings) {
864 const warnings = cachedGetWarnings(compilation);
865 object.filteredWarningDetailsCount = warnings
866 .map(e => typeof e !== "string" && e.details)
867 .filter(Boolean).length;
868 }
869 if (errors) {
870 const errors = cachedGetErrors(compilation);
871 if (errors.length >= 3) {
872 object.filteredErrorDetailsCount = errors
873 .map(e => typeof e !== "string" && e.details)
874 .filter(Boolean).length;
875 }
876 }
877 }
878 },
879 children: (object, compilation, context, options, factory) => {
880 const { type } = context;
881 object.children = factory.create(
882 `${type}.children`,
883 compilation.children,
884 context
885 );
886 }
887 },
888 asset: {
889 _: (object, asset, context, options, factory) => {
890 const { compilation } = context;
891 object.type = asset.type;
892 object.name = asset.name;
893 object.size = asset.source.size();
894 object.emitted = compilation.emittedAssets.has(asset.name);
895 object.comparedForEmit = compilation.comparedForEmitAssets.has(
896 asset.name
897 );
898 const cached = !object.emitted && !object.comparedForEmit;
899 object.cached = cached;
900 object.info = asset.info;
901 if (!cached || options.cachedAssets) {
902 Object.assign(
903 object,
904 factory.create(`${context.type}$visible`, asset, context)
905 );
906 }
907 }
908 },
909 asset$visible: {
910 _: (
911 object,
912 asset,
913 { compilation, compilationFileToChunks, compilationAuxiliaryFileToChunks }
914 ) => {
915 const chunks = compilationFileToChunks.get(asset.name) || [];
916 const auxiliaryChunks =
917 compilationAuxiliaryFileToChunks.get(asset.name) || [];
918 object.chunkNames = uniqueOrderedArray(
919 chunks,
920 c => (c.name ? [c.name] : []),
921 compareIds
922 );
923 object.chunkIdHints = uniqueOrderedArray(
924 chunks,
925 c => Array.from(c.idNameHints),
926 compareIds
927 );
928 object.auxiliaryChunkNames = uniqueOrderedArray(
929 auxiliaryChunks,
930 c => (c.name ? [c.name] : []),
931 compareIds
932 );
933 object.auxiliaryChunkIdHints = uniqueOrderedArray(
934 auxiliaryChunks,
935 c => Array.from(c.idNameHints),
936 compareIds
937 );
938 object.filteredRelated = asset.related ? asset.related.length : undefined;
939 },
940 relatedAssets: (object, asset, context, options, factory) => {
941 const { type } = context;
942 object.related = factory.create(
943 `${type.slice(0, -8)}.related`,
944 asset.related,
945 context
946 );
947 object.filteredRelated = asset.related
948 ? asset.related.length - object.related.length
949 : undefined;
950 },
951 ids: (
952 object,
953 asset,
954 { compilationFileToChunks, compilationAuxiliaryFileToChunks }
955 ) => {
956 const chunks = compilationFileToChunks.get(asset.name) || [];
957 const auxiliaryChunks =
958 compilationAuxiliaryFileToChunks.get(asset.name) || [];
959 object.chunks = uniqueOrderedArray(chunks, c => c.ids, compareIds);
960 object.auxiliaryChunks = uniqueOrderedArray(
961 auxiliaryChunks,
962 c => c.ids,
963 compareIds
964 );
965 },
966 performance: (object, asset) => {
967 object.isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(asset.source);
968 }
969 },
970 chunkGroup: {
971 _: (
972 object,
973 { name, chunkGroup },
974 { compilation, compilation: { moduleGraph, chunkGraph } },
975 { ids, chunkGroupAuxiliary, chunkGroupChildren, chunkGroupMaxAssets }
976 ) => {
977 const children =
978 chunkGroupChildren &&
979 chunkGroup.getChildrenByOrders(moduleGraph, chunkGraph);
980 /**
981 * @param {string} name Name
982 * @returns {{ name: string, size: number }} Asset object
983 */
984 const toAsset = name => {
985 const asset = compilation.getAsset(name);
986 return {
987 name,
988 size: asset ? asset.info.size : -1
989 };
990 };
991 /** @type {(total: number, asset: { size: number }) => number} */
992 const sizeReducer = (total, { size }) => total + size;
993 const assets = uniqueArray(chunkGroup.chunks, c => c.files).map(toAsset);
994 const auxiliaryAssets = uniqueOrderedArray(
995 chunkGroup.chunks,
996 c => c.auxiliaryFiles,
997 compareIds
998 ).map(toAsset);
999 const assetsSize = assets.reduce(sizeReducer, 0);
1000 const auxiliaryAssetsSize = auxiliaryAssets.reduce(sizeReducer, 0);
1001 /** @type {KnownStatsChunkGroup} */
1002 const statsChunkGroup = {
1003 name,
1004 chunks: ids ? chunkGroup.chunks.map(c => c.id) : undefined,
1005 assets: assets.length <= chunkGroupMaxAssets ? assets : undefined,
1006 filteredAssets:
1007 assets.length <= chunkGroupMaxAssets ? 0 : assets.length,
1008 assetsSize,
1009 auxiliaryAssets:
1010 chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets
1011 ? auxiliaryAssets
1012 : undefined,
1013 filteredAuxiliaryAssets:
1014 chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets
1015 ? 0
1016 : auxiliaryAssets.length,
1017 auxiliaryAssetsSize,
1018 children: children
1019 ? mapObject(children, groups =>
1020 groups.map(group => {
1021 const assets = uniqueArray(group.chunks, c => c.files).map(
1022 toAsset
1023 );
1024 const auxiliaryAssets = uniqueOrderedArray(
1025 group.chunks,
1026 c => c.auxiliaryFiles,
1027 compareIds
1028 ).map(toAsset);
1029
1030 /** @type {KnownStatsChunkGroup} */
1031 const childStatsChunkGroup = {
1032 name: group.name,
1033 chunks: ids ? group.chunks.map(c => c.id) : undefined,
1034 assets:
1035 assets.length <= chunkGroupMaxAssets ? assets : undefined,
1036 filteredAssets:
1037 assets.length <= chunkGroupMaxAssets ? 0 : assets.length,
1038 auxiliaryAssets:
1039 chunkGroupAuxiliary &&
1040 auxiliaryAssets.length <= chunkGroupMaxAssets
1041 ? auxiliaryAssets
1042 : undefined,
1043 filteredAuxiliaryAssets:
1044 chunkGroupAuxiliary &&
1045 auxiliaryAssets.length <= chunkGroupMaxAssets
1046 ? 0
1047 : auxiliaryAssets.length
1048 };
1049
1050 return childStatsChunkGroup;
1051 })
1052 )
1053 : undefined,
1054 childAssets: children
1055 ? mapObject(children, groups => {
1056 /** @type {Set<string>} */
1057 const set = new Set();
1058 for (const group of groups) {
1059 for (const chunk of group.chunks) {
1060 for (const asset of chunk.files) {
1061 set.add(asset);
1062 }
1063 }
1064 }
1065 return Array.from(set);
1066 })
1067 : undefined
1068 };
1069 Object.assign(object, statsChunkGroup);
1070 },
1071 performance: (object, { chunkGroup }) => {
1072 object.isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(chunkGroup);
1073 }
1074 },
1075 module: {
1076 _: (object, module, context, options, factory) => {
1077 const { compilation, type } = context;
1078 const built = compilation.builtModules.has(module);
1079 const codeGenerated = compilation.codeGeneratedModules.has(module);
1080 const buildTimeExecuted =
1081 compilation.buildTimeExecutedModules.has(module);
1082 /** @type {{[x: string]: number}} */
1083 const sizes = {};
1084 for (const sourceType of module.getSourceTypes()) {
1085 sizes[sourceType] = module.size(sourceType);
1086 }
1087 /** @type {KnownStatsModule} */
1088 const statsModule = {
1089 type: "module",
1090 moduleType: module.type,
1091 layer: module.layer,
1092 size: module.size(),
1093 sizes,
1094 built,
1095 codeGenerated,
1096 buildTimeExecuted,
1097 cached: !built && !codeGenerated
1098 };
1099 Object.assign(object, statsModule);
1100
1101 if (built || codeGenerated || options.cachedModules) {
1102 Object.assign(
1103 object,
1104 factory.create(`${type}$visible`, module, context)
1105 );
1106 }
1107 }
1108 },
1109 module$visible: {
1110 _: (object, module, context, { requestShortener }, factory) => {
1111 const { compilation, type, rootModules } = context;
1112 const { moduleGraph } = compilation;
1113 /** @type {Module[]} */
1114 const path = [];
1115 const issuer = moduleGraph.getIssuer(module);
1116 let current = issuer;
1117 while (current) {
1118 path.push(current);
1119 current = moduleGraph.getIssuer(current);
1120 }
1121 path.reverse();
1122 const profile = moduleGraph.getProfile(module);
1123 const errors = module.getErrors();
1124 const errorsCount = errors !== undefined ? countIterable(errors) : 0;
1125 const warnings = module.getWarnings();
1126 const warningsCount =
1127 warnings !== undefined ? countIterable(warnings) : 0;
1128 /** @type {{[x: string]: number}} */
1129 const sizes = {};
1130 for (const sourceType of module.getSourceTypes()) {
1131 sizes[sourceType] = module.size(sourceType);
1132 }
1133 /** @type {KnownStatsModule} */
1134 const statsModule = {
1135 identifier: module.identifier(),
1136 name: module.readableIdentifier(requestShortener),
1137 nameForCondition: module.nameForCondition(),
1138 index: moduleGraph.getPreOrderIndex(module),
1139 preOrderIndex: moduleGraph.getPreOrderIndex(module),
1140 index2: moduleGraph.getPostOrderIndex(module),
1141 postOrderIndex: moduleGraph.getPostOrderIndex(module),
1142 cacheable: module.buildInfo.cacheable,
1143 optional: module.isOptional(moduleGraph),
1144 orphan:
1145 !type.endsWith("module.modules[].module$visible") &&
1146 compilation.chunkGraph.getNumberOfModuleChunks(module) === 0,
1147 dependent: rootModules ? !rootModules.has(module) : undefined,
1148 issuer: issuer && issuer.identifier(),
1149 issuerName: issuer && issuer.readableIdentifier(requestShortener),
1150 issuerPath:
1151 issuer &&
1152 factory.create(`${type.slice(0, -8)}.issuerPath`, path, context),
1153 failed: errorsCount > 0,
1154 errors: errorsCount,
1155 warnings: warningsCount
1156 };
1157 Object.assign(object, statsModule);
1158 if (profile) {
1159 object.profile = factory.create(
1160 `${type.slice(0, -8)}.profile`,
1161 profile,
1162 context
1163 );
1164 }
1165 },
1166 ids: (object, module, { compilation: { chunkGraph, moduleGraph } }) => {
1167 object.id = chunkGraph.getModuleId(module);
1168 const issuer = moduleGraph.getIssuer(module);
1169 object.issuerId = issuer && chunkGraph.getModuleId(issuer);
1170 object.chunks = Array.from(
1171 chunkGraph.getOrderedModuleChunksIterable(module, compareChunksById),
1172 chunk => chunk.id
1173 );
1174 },
1175 moduleAssets: (object, module) => {
1176 object.assets = module.buildInfo.assets
1177 ? Object.keys(module.buildInfo.assets)
1178 : [];
1179 },
1180 reasons: (object, module, context, options, factory) => {
1181 const {
1182 type,
1183 compilation: { moduleGraph }
1184 } = context;
1185 const groupsReasons = factory.create(
1186 `${type.slice(0, -8)}.reasons`,
1187 Array.from(moduleGraph.getIncomingConnections(module)),
1188 context
1189 );
1190 const limited = spaceLimited(groupsReasons, options.reasonsSpace);
1191 object.reasons = limited.children;
1192 object.filteredReasons = limited.filteredChildren;
1193 },
1194 usedExports: (
1195 object,
1196 module,
1197 { runtime, compilation: { moduleGraph } }
1198 ) => {
1199 const usedExports = moduleGraph.getUsedExports(module, runtime);
1200 if (usedExports === null) {
1201 object.usedExports = null;
1202 } else if (typeof usedExports === "boolean") {
1203 object.usedExports = usedExports;
1204 } else {
1205 object.usedExports = Array.from(usedExports);
1206 }
1207 },
1208 providedExports: (object, module, { compilation: { moduleGraph } }) => {
1209 const providedExports = moduleGraph.getProvidedExports(module);
1210 object.providedExports = Array.isArray(providedExports)
1211 ? providedExports
1212 : null;
1213 },
1214 optimizationBailout: (
1215 object,
1216 module,
1217 { compilation: { moduleGraph } },
1218 { requestShortener }
1219 ) => {
1220 object.optimizationBailout = moduleGraph
1221 .getOptimizationBailout(module)
1222 .map(item => {
1223 if (typeof item === "function") return item(requestShortener);
1224 return item;
1225 });
1226 },
1227 depth: (object, module, { compilation: { moduleGraph } }) => {
1228 object.depth = moduleGraph.getDepth(module);
1229 },
1230 nestedModules: (object, module, context, options, factory) => {
1231 const { type } = context;
1232 const innerModules = /** @type {Module & { modules?: Module[] }} */ (
1233 module
1234 ).modules;
1235 if (Array.isArray(innerModules)) {
1236 const groupedModules = factory.create(
1237 `${type.slice(0, -8)}.modules`,
1238 innerModules,
1239 context
1240 );
1241 const limited = spaceLimited(
1242 groupedModules,
1243 options.nestedModulesSpace
1244 );
1245 object.modules = limited.children;
1246 object.filteredModules = limited.filteredChildren;
1247 }
1248 },
1249 source: (object, module) => {
1250 const originalSource = module.originalSource();
1251 if (originalSource) {
1252 object.source = originalSource.source();
1253 }
1254 }
1255 },
1256 profile: {
1257 _: (object, profile) => {
1258 /** @type {KnownStatsProfile} */
1259 const statsProfile = {
1260 total:
1261 profile.factory +
1262 profile.restoring +
1263 profile.integration +
1264 profile.building +
1265 profile.storing,
1266 resolving: profile.factory,
1267 restoring: profile.restoring,
1268 building: profile.building,
1269 integration: profile.integration,
1270 storing: profile.storing,
1271 additionalResolving: profile.additionalFactories,
1272 additionalIntegration: profile.additionalIntegration,
1273 // TODO remove this in webpack 6
1274 factory: profile.factory,
1275 // TODO remove this in webpack 6
1276 dependencies: profile.additionalFactories
1277 };
1278 Object.assign(object, statsProfile);
1279 }
1280 },
1281 moduleIssuer: {
1282 _: (object, module, context, { requestShortener }, factory) => {
1283 const { compilation, type } = context;
1284 const { moduleGraph } = compilation;
1285 const profile = moduleGraph.getProfile(module);
1286 /** @type {KnownStatsModuleIssuer} */
1287 const statsModuleIssuer = {
1288 identifier: module.identifier(),
1289 name: module.readableIdentifier(requestShortener)
1290 };
1291 Object.assign(object, statsModuleIssuer);
1292 if (profile) {
1293 object.profile = factory.create(`${type}.profile`, profile, context);
1294 }
1295 },
1296 ids: (object, module, { compilation: { chunkGraph } }) => {
1297 object.id = chunkGraph.getModuleId(module);
1298 }
1299 },
1300 moduleReason: {
1301 _: (object, reason, { runtime }, { requestShortener }) => {
1302 const dep = reason.dependency;
1303 const moduleDep =
1304 dep && dep instanceof ModuleDependency ? dep : undefined;
1305 /** @type {KnownStatsModuleReason} */
1306 const statsModuleReason = {
1307 moduleIdentifier: reason.originModule
1308 ? reason.originModule.identifier()
1309 : null,
1310 module: reason.originModule
1311 ? reason.originModule.readableIdentifier(requestShortener)
1312 : null,
1313 moduleName: reason.originModule
1314 ? reason.originModule.readableIdentifier(requestShortener)
1315 : null,
1316 resolvedModuleIdentifier: reason.resolvedOriginModule
1317 ? reason.resolvedOriginModule.identifier()
1318 : null,
1319 resolvedModule: reason.resolvedOriginModule
1320 ? reason.resolvedOriginModule.readableIdentifier(requestShortener)
1321 : null,
1322 type: reason.dependency ? reason.dependency.type : null,
1323 active: reason.isActive(runtime),
1324 explanation: reason.explanation,
1325 userRequest: (moduleDep && moduleDep.userRequest) || null
1326 };
1327 Object.assign(object, statsModuleReason);
1328 if (reason.dependency) {
1329 const locInfo = formatLocation(reason.dependency.loc);
1330 if (locInfo) {
1331 object.loc = locInfo;
1332 }
1333 }
1334 },
1335 ids: (object, reason, { compilation: { chunkGraph } }) => {
1336 object.moduleId = reason.originModule
1337 ? chunkGraph.getModuleId(reason.originModule)
1338 : null;
1339 object.resolvedModuleId = reason.resolvedOriginModule
1340 ? chunkGraph.getModuleId(reason.resolvedOriginModule)
1341 : null;
1342 }
1343 },
1344 chunk: {
1345 _: (object, chunk, { makePathsRelative, compilation: { chunkGraph } }) => {
1346 const childIdByOrder = chunk.getChildIdsByOrders(chunkGraph);
1347
1348 /** @type {KnownStatsChunk} */
1349 const statsChunk = {
1350 rendered: chunk.rendered,
1351 initial: chunk.canBeInitial(),
1352 entry: chunk.hasRuntime(),
1353 recorded: AggressiveSplittingPlugin.wasChunkRecorded(chunk),
1354 reason: chunk.chunkReason,
1355 size: chunkGraph.getChunkModulesSize(chunk),
1356 sizes: chunkGraph.getChunkModulesSizes(chunk),
1357 names: chunk.name ? [chunk.name] : [],
1358 idHints: Array.from(chunk.idNameHints),
1359 runtime:
1360 chunk.runtime === undefined
1361 ? undefined
1362 : typeof chunk.runtime === "string"
1363 ? [makePathsRelative(chunk.runtime)]
1364 : Array.from(chunk.runtime.sort(), makePathsRelative),
1365 files: Array.from(chunk.files),
1366 auxiliaryFiles: Array.from(chunk.auxiliaryFiles).sort(compareIds),
1367 hash: chunk.renderedHash,
1368 childrenByOrder: childIdByOrder
1369 };
1370 Object.assign(object, statsChunk);
1371 },
1372 ids: (object, chunk) => {
1373 object.id = chunk.id;
1374 },
1375 chunkRelations: (object, chunk, { compilation: { chunkGraph } }) => {
1376 /** @type {Set<string|number>} */
1377 const parents = new Set();
1378 /** @type {Set<string|number>} */
1379 const children = new Set();
1380 /** @type {Set<string|number>} */
1381 const siblings = new Set();
1382
1383 for (const chunkGroup of chunk.groupsIterable) {
1384 for (const parentGroup of chunkGroup.parentsIterable) {
1385 for (const chunk of parentGroup.chunks) {
1386 parents.add(chunk.id);
1387 }
1388 }
1389 for (const childGroup of chunkGroup.childrenIterable) {
1390 for (const chunk of childGroup.chunks) {
1391 children.add(chunk.id);
1392 }
1393 }
1394 for (const sibling of chunkGroup.chunks) {
1395 if (sibling !== chunk) siblings.add(sibling.id);
1396 }
1397 }
1398 object.siblings = Array.from(siblings).sort(compareIds);
1399 object.parents = Array.from(parents).sort(compareIds);
1400 object.children = Array.from(children).sort(compareIds);
1401 },
1402 chunkModules: (object, chunk, context, options, factory) => {
1403 const {
1404 type,
1405 compilation: { chunkGraph }
1406 } = context;
1407 const array = chunkGraph.getChunkModules(chunk);
1408 const groupedModules = factory.create(`${type}.modules`, array, {
1409 ...context,
1410 runtime: chunk.runtime,
1411 rootModules: new Set(chunkGraph.getChunkRootModules(chunk))
1412 });
1413 const limited = spaceLimited(groupedModules, options.chunkModulesSpace);
1414 object.modules = limited.children;
1415 object.filteredModules = limited.filteredChildren;
1416 },
1417 chunkOrigins: (object, chunk, context, options, factory) => {
1418 const {
1419 type,
1420 compilation: { chunkGraph }
1421 } = context;
1422 /** @type {Set<string>} */
1423 const originsKeySet = new Set();
1424 const origins = [];
1425 for (const g of chunk.groupsIterable) {
1426 origins.push(...g.origins);
1427 }
1428 const array = origins.filter(origin => {
1429 const key = [
1430 origin.module ? chunkGraph.getModuleId(origin.module) : undefined,
1431 formatLocation(origin.loc),
1432 origin.request
1433 ].join();
1434 if (originsKeySet.has(key)) return false;
1435 originsKeySet.add(key);
1436 return true;
1437 });
1438 object.origins = factory.create(`${type}.origins`, array, context);
1439 }
1440 },
1441 chunkOrigin: {
1442 _: (object, origin, context, { requestShortener }) => {
1443 /** @type {KnownStatsChunkOrigin} */
1444 const statsChunkOrigin = {
1445 module: origin.module ? origin.module.identifier() : "",
1446 moduleIdentifier: origin.module ? origin.module.identifier() : "",
1447 moduleName: origin.module
1448 ? origin.module.readableIdentifier(requestShortener)
1449 : "",
1450 loc: formatLocation(origin.loc),
1451 request: origin.request
1452 };
1453 Object.assign(object, statsChunkOrigin);
1454 },
1455 ids: (object, origin, { compilation: { chunkGraph } }) => {
1456 object.moduleId = origin.module
1457 ? chunkGraph.getModuleId(origin.module)
1458 : undefined;
1459 }
1460 },
1461 error: EXTRACT_ERROR,
1462 warning: EXTRACT_ERROR,
1463 moduleTraceItem: {
1464 _: (object, { origin, module }, context, { requestShortener }, factory) => {
1465 const {
1466 type,
1467 compilation: { moduleGraph }
1468 } = context;
1469 object.originIdentifier = origin.identifier();
1470 object.originName = origin.readableIdentifier(requestShortener);
1471 object.moduleIdentifier = module.identifier();
1472 object.moduleName = module.readableIdentifier(requestShortener);
1473 const dependencies = Array.from(
1474 moduleGraph.getIncomingConnections(module)
1475 )
1476 .filter(c => c.resolvedOriginModule === origin && c.dependency)
1477 .map(c => c.dependency);
1478 object.dependencies = factory.create(
1479 `${type}.dependencies`,
1480 Array.from(new Set(dependencies)),
1481 context
1482 );
1483 },
1484 ids: (object, { origin, module }, { compilation: { chunkGraph } }) => {
1485 object.originId = chunkGraph.getModuleId(origin);
1486 object.moduleId = chunkGraph.getModuleId(module);
1487 }
1488 },
1489 moduleTraceDependency: {
1490 _: (object, dependency) => {
1491 object.loc = formatLocation(dependency.loc);
1492 }
1493 }
1494};
1495
1496/** @type {Record<string, Record<string, (thing: any, context: StatsFactoryContext, options: NormalizedStatsOptions) => boolean | undefined>>} */
1497const FILTER = {
1498 "module.reasons": {
1499 "!orphanModules": (reason, { compilation: { chunkGraph } }) => {
1500 if (
1501 reason.originModule &&
1502 chunkGraph.getNumberOfModuleChunks(reason.originModule) === 0
1503 ) {
1504 return false;
1505 }
1506 }
1507 }
1508};
1509
1510/** @type {Record<string, Record<string, (thing: Object, context: StatsFactoryContext, options: NormalizedStatsOptions) => boolean | undefined>>} */
1511const FILTER_RESULTS = {
1512 "compilation.warnings": {
1513 warningsFilter: util.deprecate(
1514 (warning, context, { warningsFilter }) => {
1515 const warningString = Object.keys(warning)
1516 .map(key => `${warning[key]}`)
1517 .join("\n");
1518 return !warningsFilter.some(filter => filter(warning, warningString));
1519 },
1520 "config.stats.warningsFilter is deprecated in favor of config.ignoreWarnings",
1521 "DEP_WEBPACK_STATS_WARNINGS_FILTER"
1522 )
1523 }
1524};
1525
1526/** @type {Record<string, (comparators: Function[], context: StatsFactoryContext) => void>} */
1527const MODULES_SORTER = {
1528 _: (comparators, { compilation: { moduleGraph } }) => {
1529 comparators.push(
1530 compareSelect(
1531 /**
1532 * @param {Module} m module
1533 * @returns {number} depth
1534 */
1535 m => moduleGraph.getDepth(m),
1536 compareNumbers
1537 ),
1538 compareSelect(
1539 /**
1540 * @param {Module} m module
1541 * @returns {number} index
1542 */
1543 m => moduleGraph.getPreOrderIndex(m),
1544 compareNumbers
1545 ),
1546 compareSelect(
1547 /**
1548 * @param {Module} m module
1549 * @returns {string} identifier
1550 */
1551 m => m.identifier(),
1552 compareIds
1553 )
1554 );
1555 }
1556};
1557
1558/** @type {Record<string, Record<string, (comparators: Function[], context: StatsFactoryContext) => void>>} */
1559const SORTERS = {
1560 "compilation.chunks": {
1561 _: comparators => {
1562 comparators.push(compareSelect(c => c.id, compareIds));
1563 }
1564 },
1565 "compilation.modules": MODULES_SORTER,
1566 "chunk.rootModules": MODULES_SORTER,
1567 "chunk.modules": MODULES_SORTER,
1568 "module.modules": MODULES_SORTER,
1569 "module.reasons": {
1570 _: (comparators, { compilation: { chunkGraph } }) => {
1571 comparators.push(
1572 compareSelect(x => x.originModule, compareModulesByIdentifier)
1573 );
1574 comparators.push(
1575 compareSelect(x => x.resolvedOriginModule, compareModulesByIdentifier)
1576 );
1577 comparators.push(
1578 compareSelect(
1579 x => x.dependency,
1580 concatComparators(
1581 compareSelect(
1582 /**
1583 * @param {Dependency} x dependency
1584 * @returns {DependencyLocation} location
1585 */
1586 x => x.loc,
1587 compareLocations
1588 ),
1589 compareSelect(x => x.type, compareIds)
1590 )
1591 )
1592 );
1593 }
1594 },
1595 "chunk.origins": {
1596 _: (comparators, { compilation: { chunkGraph } }) => {
1597 comparators.push(
1598 compareSelect(
1599 origin =>
1600 origin.module ? chunkGraph.getModuleId(origin.module) : undefined,
1601 compareIds
1602 ),
1603 compareSelect(origin => formatLocation(origin.loc), compareIds),
1604 compareSelect(origin => origin.request, compareIds)
1605 );
1606 }
1607 }
1608};
1609
1610const getItemSize = item => {
1611 // Each item takes 1 line
1612 // + the size of the children
1613 // + 1 extra line when it has children and filteredChildren
1614 return !item.children
1615 ? 1
1616 : item.filteredChildren
1617 ? 2 + getTotalSize(item.children)
1618 : 1 + getTotalSize(item.children);
1619};
1620
1621const getTotalSize = children => {
1622 let size = 0;
1623 for (const child of children) {
1624 size += getItemSize(child);
1625 }
1626 return size;
1627};
1628
1629const getTotalItems = children => {
1630 let count = 0;
1631 for (const child of children) {
1632 if (!child.children && !child.filteredChildren) {
1633 count++;
1634 } else {
1635 if (child.children) count += getTotalItems(child.children);
1636 if (child.filteredChildren) count += child.filteredChildren;
1637 }
1638 }
1639 return count;
1640};
1641
1642const collapse = children => {
1643 // After collapse each child must take exactly one line
1644 const newChildren = [];
1645 for (const child of children) {
1646 if (child.children) {
1647 let filteredChildren = child.filteredChildren || 0;
1648 filteredChildren += getTotalItems(child.children);
1649 newChildren.push({
1650 ...child,
1651 children: undefined,
1652 filteredChildren
1653 });
1654 } else {
1655 newChildren.push(child);
1656 }
1657 }
1658 return newChildren;
1659};
1660
1661const spaceLimited = (itemsAndGroups, max) => {
1662 /** @type {any[] | undefined} */
1663 let children = undefined;
1664 /** @type {number | undefined} */
1665 let filteredChildren = undefined;
1666 // This are the groups, which take 1+ lines each
1667 const groups = itemsAndGroups.filter(c => c.children || c.filteredChildren);
1668 // The sizes of the groups are stored in groupSizes
1669 const groupSizes = groups.map(g => getItemSize(g));
1670 // This are the items, which take 1 line each
1671 const items = itemsAndGroups.filter(c => !c.children && !c.filteredChildren);
1672 // The total of group sizes
1673 let groupsSize = groupSizes.reduce((a, b) => a + b, 0);
1674 if (groupsSize + items.length <= max) {
1675 // The total size in the current state fits into the max
1676 // keep all
1677 children = groups.concat(items);
1678 } else if (
1679 groups.length > 0 &&
1680 groups.length + Math.min(1, items.length) < max
1681 ) {
1682 // If each group would take 1 line the total would be below the maximum
1683 // collapse some groups, keep items
1684 while (groupsSize + items.length + (filteredChildren ? 1 : 0) > max) {
1685 // calculate how much we are over the size limit
1686 // this allows to approach the limit faster
1687 // it's always > 1
1688 const oversize =
1689 items.length + groupsSize + (filteredChildren ? 1 : 0) - max;
1690 // Find the maximum group and process only this one
1691 const maxGroupSize = Math.max(...groupSizes);
1692 if (maxGroupSize < items.length) {
1693 filteredChildren = items.length;
1694 items.length = 0;
1695 continue;
1696 }
1697 for (let i = 0; i < groups.length; i++) {
1698 if (groupSizes[i] === maxGroupSize) {
1699 const group = groups[i];
1700 // run this algorithm recursively and limit the size of the children to
1701 // current size - oversize / number of groups
1702 // So it should always end up being smaller
1703 const headerSize = !group.children
1704 ? 0
1705 : group.filteredChildren
1706 ? 2
1707 : 1;
1708 const limited = spaceLimited(
1709 group.children,
1710 groupSizes[i] - headerSize - oversize / groups.length
1711 );
1712 groups[i] = {
1713 ...group,
1714 children: limited.children,
1715 filteredChildren:
1716 (group.filteredChildren || 0) + limited.filteredChildren
1717 };
1718 const newSize = getItemSize(groups[i]);
1719 groupsSize -= groupSizes[i] - newSize;
1720 groupSizes[i] = newSize;
1721 break;
1722 }
1723 }
1724 }
1725 children = groups.concat(items);
1726 } else if (
1727 groups.length > 0 &&
1728 groups.length + Math.min(1, items.length) <= max
1729 ) {
1730 // If we have only enough space to show one line per group and one line for the filtered items
1731 // collapse all groups and items
1732 children = groups.length ? collapse(groups) : undefined;
1733 filteredChildren = items.length;
1734 } else {
1735 // If we have no space
1736 // collapse complete group
1737 filteredChildren = getTotalItems(itemsAndGroups);
1738 }
1739 return {
1740 children,
1741 filteredChildren
1742 };
1743};
1744
1745const assetGroup = (children, assets) => {
1746 let size = 0;
1747 for (const asset of children) {
1748 size += asset.size;
1749 }
1750 return {
1751 size
1752 };
1753};
1754
1755const moduleGroup = (children, modules) => {
1756 let size = 0;
1757 const sizes = {};
1758 for (const module of children) {
1759 size += module.size;
1760 for (const key of Object.keys(module.sizes)) {
1761 sizes[key] = (sizes[key] || 0) + module.sizes[key];
1762 }
1763 }
1764 return {
1765 size,
1766 sizes
1767 };
1768};
1769
1770const reasonGroup = (children, reasons) => {
1771 let active = false;
1772 for (const reason of children) {
1773 active = active || reason.active;
1774 }
1775 return {
1776 active
1777 };
1778};
1779
1780/** @type {Record<string, (groupConfigs: GroupConfig[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>} */
1781const ASSETS_GROUPERS = {
1782 _: (groupConfigs, context, options) => {
1783 const groupByFlag = (name, exclude) => {
1784 groupConfigs.push({
1785 getKeys: asset => {
1786 return asset[name] ? ["1"] : undefined;
1787 },
1788 getOptions: () => {
1789 return {
1790 groupChildren: !exclude,
1791 force: exclude
1792 };
1793 },
1794 createGroup: (key, children, assets) => {
1795 return exclude
1796 ? {
1797 type: "assets by status",
1798 [name]: !!key,
1799 filteredChildren: assets.length,
1800 ...assetGroup(children, assets)
1801 }
1802 : {
1803 type: "assets by status",
1804 [name]: !!key,
1805 children,
1806 ...assetGroup(children, assets)
1807 };
1808 }
1809 });
1810 };
1811 const {
1812 groupAssetsByEmitStatus,
1813 groupAssetsByPath,
1814 groupAssetsByExtension
1815 } = options;
1816 if (groupAssetsByEmitStatus) {
1817 groupByFlag("emitted");
1818 groupByFlag("comparedForEmit");
1819 groupByFlag("isOverSizeLimit");
1820 }
1821 if (groupAssetsByEmitStatus || !options.cachedAssets) {
1822 groupByFlag("cached", !options.cachedAssets);
1823 }
1824 if (groupAssetsByPath || groupAssetsByExtension) {
1825 groupConfigs.push({
1826 getKeys: asset => {
1827 const extensionMatch =
1828 groupAssetsByExtension && /(\.[^.]+)(?:\?.*|$)/.exec(asset.name);
1829 const extension = extensionMatch ? extensionMatch[1] : "";
1830 const pathMatch =
1831 groupAssetsByPath && /(.+)[/\\][^/\\]+(?:\?.*|$)/.exec(asset.name);
1832 const path = pathMatch ? pathMatch[1].split(/[/\\]/) : [];
1833 const keys = [];
1834 if (groupAssetsByPath) {
1835 keys.push(".");
1836 if (extension)
1837 keys.push(
1838 path.length
1839 ? `${path.join("/")}/*${extension}`
1840 : `*${extension}`
1841 );
1842 while (path.length > 0) {
1843 keys.push(path.join("/") + "/");
1844 path.pop();
1845 }
1846 } else {
1847 if (extension) keys.push(`*${extension}`);
1848 }
1849 return keys;
1850 },
1851 createGroup: (key, children, assets) => {
1852 return {
1853 type: groupAssetsByPath ? "assets by path" : "assets by extension",
1854 name: key,
1855 children,
1856 ...assetGroup(children, assets)
1857 };
1858 }
1859 });
1860 }
1861 },
1862 groupAssetsByInfo: (groupConfigs, context, options) => {
1863 const groupByAssetInfoFlag = name => {
1864 groupConfigs.push({
1865 getKeys: asset => {
1866 return asset.info && asset.info[name] ? ["1"] : undefined;
1867 },
1868 createGroup: (key, children, assets) => {
1869 return {
1870 type: "assets by info",
1871 info: {
1872 [name]: !!key
1873 },
1874 children,
1875 ...assetGroup(children, assets)
1876 };
1877 }
1878 });
1879 };
1880 groupByAssetInfoFlag("immutable");
1881 groupByAssetInfoFlag("development");
1882 groupByAssetInfoFlag("hotModuleReplacement");
1883 },
1884 groupAssetsByChunk: (groupConfigs, context, options) => {
1885 const groupByNames = name => {
1886 groupConfigs.push({
1887 getKeys: asset => {
1888 return asset[name];
1889 },
1890 createGroup: (key, children, assets) => {
1891 return {
1892 type: "assets by chunk",
1893 [name]: [key],
1894 children,
1895 ...assetGroup(children, assets)
1896 };
1897 }
1898 });
1899 };
1900 groupByNames("chunkNames");
1901 groupByNames("auxiliaryChunkNames");
1902 groupByNames("chunkIdHints");
1903 groupByNames("auxiliaryChunkIdHints");
1904 },
1905 excludeAssets: (groupConfigs, context, { excludeAssets }) => {
1906 groupConfigs.push({
1907 getKeys: asset => {
1908 const ident = asset.name;
1909 const excluded = excludeAssets.some(fn => fn(ident, asset));
1910 if (excluded) return ["excluded"];
1911 },
1912 getOptions: () => ({
1913 groupChildren: false,
1914 force: true
1915 }),
1916 createGroup: (key, children, assets) => ({
1917 type: "hidden assets",
1918 filteredChildren: assets.length,
1919 ...assetGroup(children, assets)
1920 })
1921 });
1922 }
1923};
1924
1925/** @type {function("module" | "chunk" | "root-of-chunk" | "nested"): Record<string, (groupConfigs: GroupConfig[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>} */
1926const MODULES_GROUPERS = type => ({
1927 _: (groupConfigs, context, options) => {
1928 const groupByFlag = (name, type, exclude) => {
1929 groupConfigs.push({
1930 getKeys: module => {
1931 return module[name] ? ["1"] : undefined;
1932 },
1933 getOptions: () => {
1934 return {
1935 groupChildren: !exclude,
1936 force: exclude
1937 };
1938 },
1939 createGroup: (key, children, modules) => {
1940 return {
1941 type,
1942 [name]: !!key,
1943 ...(exclude ? { filteredChildren: modules.length } : { children }),
1944 ...moduleGroup(children, modules)
1945 };
1946 }
1947 });
1948 };
1949 const {
1950 groupModulesByCacheStatus,
1951 groupModulesByLayer,
1952 groupModulesByAttributes,
1953 groupModulesByType,
1954 groupModulesByPath,
1955 groupModulesByExtension
1956 } = options;
1957 if (groupModulesByAttributes) {
1958 groupByFlag("errors", "modules with errors");
1959 groupByFlag("warnings", "modules with warnings");
1960 groupByFlag("assets", "modules with assets");
1961 groupByFlag("optional", "optional modules");
1962 }
1963 if (groupModulesByCacheStatus) {
1964 groupByFlag("cacheable", "cacheable modules");
1965 groupByFlag("built", "built modules");
1966 groupByFlag("codeGenerated", "code generated modules");
1967 }
1968 if (groupModulesByCacheStatus || !options.cachedModules) {
1969 groupByFlag("cached", "cached modules", !options.cachedModules);
1970 }
1971 if (groupModulesByAttributes || !options.orphanModules) {
1972 groupByFlag("orphan", "orphan modules", !options.orphanModules);
1973 }
1974 if (groupModulesByAttributes || !options.dependentModules) {
1975 groupByFlag("dependent", "dependent modules", !options.dependentModules);
1976 }
1977 if (groupModulesByType || !options.runtimeModules) {
1978 groupConfigs.push({
1979 getKeys: module => {
1980 if (!module.moduleType) return;
1981 if (groupModulesByType) {
1982 return [module.moduleType.split("/", 1)[0]];
1983 } else if (module.moduleType === "runtime") {
1984 return ["runtime"];
1985 }
1986 },
1987 getOptions: key => {
1988 const exclude = key === "runtime" && !options.runtimeModules;
1989 return {
1990 groupChildren: !exclude,
1991 force: exclude
1992 };
1993 },
1994 createGroup: (key, children, modules) => {
1995 const exclude = key === "runtime" && !options.runtimeModules;
1996 return {
1997 type: `${key} modules`,
1998 moduleType: key,
1999 ...(exclude ? { filteredChildren: modules.length } : { children }),
2000 ...moduleGroup(children, modules)
2001 };
2002 }
2003 });
2004 }
2005 if (groupModulesByLayer) {
2006 groupConfigs.push({
2007 getKeys: module => {
2008 return [module.layer];
2009 },
2010 createGroup: (key, children, modules) => {
2011 return {
2012 type: "modules by layer",
2013 layer: key,
2014 children,
2015 ...moduleGroup(children, modules)
2016 };
2017 }
2018 });
2019 }
2020 if (groupModulesByPath || groupModulesByExtension) {
2021 groupConfigs.push({
2022 getKeys: module => {
2023 if (!module.name) return;
2024 const resource = parseResource(module.name.split("!").pop()).path;
2025 const extensionMatch =
2026 groupModulesByExtension && /(\.[^.]+)(?:\?.*|$)/.exec(resource);
2027 const extension = extensionMatch ? extensionMatch[1] : "";
2028 const pathMatch =
2029 groupModulesByPath && /(.+)[/\\][^/\\]+(?:\?.*|$)/.exec(resource);
2030 const path = pathMatch ? pathMatch[1].split(/[/\\]/) : [];
2031 const keys = [];
2032 if (groupModulesByPath) {
2033 if (extension)
2034 keys.push(
2035 path.length
2036 ? `${path.join("/")}/*${extension}`
2037 : `*${extension}`
2038 );
2039 while (path.length > 0) {
2040 keys.push(path.join("/") + "/");
2041 path.pop();
2042 }
2043 } else {
2044 if (extension) keys.push(`*${extension}`);
2045 }
2046 return keys;
2047 },
2048 createGroup: (key, children, modules) => {
2049 return {
2050 type: groupModulesByPath
2051 ? "modules by path"
2052 : "modules by extension",
2053 name: key,
2054 children,
2055 ...moduleGroup(children, modules)
2056 };
2057 }
2058 });
2059 }
2060 },
2061 excludeModules: (groupConfigs, context, { excludeModules }) => {
2062 groupConfigs.push({
2063 getKeys: module => {
2064 const name = module.name;
2065 if (name) {
2066 const excluded = excludeModules.some(fn => fn(name, module, type));
2067 if (excluded) return ["1"];
2068 }
2069 },
2070 getOptions: () => ({
2071 groupChildren: false,
2072 force: true
2073 }),
2074 createGroup: (key, children, modules) => ({
2075 type: "hidden modules",
2076 filteredChildren: children.length,
2077 ...moduleGroup(children, modules)
2078 })
2079 });
2080 }
2081});
2082
2083/** @type {Record<string, Record<string, (groupConfigs: GroupConfig[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>>} */
2084const RESULT_GROUPERS = {
2085 "compilation.assets": ASSETS_GROUPERS,
2086 "asset.related": ASSETS_GROUPERS,
2087 "compilation.modules": MODULES_GROUPERS("module"),
2088 "chunk.modules": MODULES_GROUPERS("chunk"),
2089 "chunk.rootModules": MODULES_GROUPERS("root-of-chunk"),
2090 "module.modules": MODULES_GROUPERS("nested"),
2091 "module.reasons": {
2092 groupReasonsByOrigin: groupConfigs => {
2093 groupConfigs.push({
2094 getKeys: reason => {
2095 return [reason.module];
2096 },
2097 createGroup: (key, children, reasons) => {
2098 return {
2099 type: "from origin",
2100 module: key,
2101 children,
2102 ...reasonGroup(children, reasons)
2103 };
2104 }
2105 });
2106 }
2107 }
2108};
2109
2110// remove a prefixed "!" that can be specified to reverse sort order
2111const normalizeFieldKey = field => {
2112 if (field[0] === "!") {
2113 return field.substr(1);
2114 }
2115 return field;
2116};
2117
2118// if a field is prefixed by a "!" reverse sort order
2119const sortOrderRegular = field => {
2120 if (field[0] === "!") {
2121 return false;
2122 }
2123 return true;
2124};
2125
2126/**
2127 * @param {string} field field name
2128 * @returns {function(Object, Object): number} comparators
2129 */
2130const sortByField = field => {
2131 if (!field) {
2132 /**
2133 * @param {any} a first
2134 * @param {any} b second
2135 * @returns {-1|0|1} zero
2136 */
2137 const noSort = (a, b) => 0;
2138 return noSort;
2139 }
2140
2141 const fieldKey = normalizeFieldKey(field);
2142
2143 let sortFn = compareSelect(m => m[fieldKey], compareIds);
2144
2145 // if a field is prefixed with a "!" the sort is reversed!
2146 const sortIsRegular = sortOrderRegular(field);
2147
2148 if (!sortIsRegular) {
2149 const oldSortFn = sortFn;
2150 sortFn = (a, b) => oldSortFn(b, a);
2151 }
2152
2153 return sortFn;
2154};
2155
2156const ASSET_SORTERS = {
2157 /** @type {(comparators: Function[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void} */
2158 assetsSort: (comparators, context, { assetsSort }) => {
2159 comparators.push(sortByField(assetsSort));
2160 },
2161 _: comparators => {
2162 comparators.push(compareSelect(a => a.name, compareIds));
2163 }
2164};
2165
2166/** @type {Record<string, Record<string, (comparators: Function[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>>} */
2167const RESULT_SORTERS = {
2168 "compilation.chunks": {
2169 chunksSort: (comparators, context, { chunksSort }) => {
2170 comparators.push(sortByField(chunksSort));
2171 }
2172 },
2173 "compilation.modules": {
2174 modulesSort: (comparators, context, { modulesSort }) => {
2175 comparators.push(sortByField(modulesSort));
2176 }
2177 },
2178 "chunk.modules": {
2179 chunkModulesSort: (comparators, context, { chunkModulesSort }) => {
2180 comparators.push(sortByField(chunkModulesSort));
2181 }
2182 },
2183 "module.modules": {
2184 nestedModulesSort: (comparators, context, { nestedModulesSort }) => {
2185 comparators.push(sortByField(nestedModulesSort));
2186 }
2187 },
2188 "compilation.assets": ASSET_SORTERS,
2189 "asset.related": ASSET_SORTERS
2190};
2191
2192/**
2193 * @param {Record<string, Record<string, Function>>} config the config see above
2194 * @param {NormalizedStatsOptions} options stats options
2195 * @param {function(string, Function): void} fn handler function called for every active line in config
2196 * @returns {void}
2197 */
2198const iterateConfig = (config, options, fn) => {
2199 for (const hookFor of Object.keys(config)) {
2200 const subConfig = config[hookFor];
2201 for (const option of Object.keys(subConfig)) {
2202 if (option !== "_") {
2203 if (option.startsWith("!")) {
2204 if (options[option.slice(1)]) continue;
2205 } else {
2206 const value = options[option];
2207 if (
2208 value === false ||
2209 value === undefined ||
2210 (Array.isArray(value) && value.length === 0)
2211 )
2212 continue;
2213 }
2214 }
2215 fn(hookFor, subConfig[option]);
2216 }
2217 }
2218};
2219
2220/** @type {Record<string, string>} */
2221const ITEM_NAMES = {
2222 "compilation.children[]": "compilation",
2223 "compilation.modules[]": "module",
2224 "compilation.entrypoints[]": "chunkGroup",
2225 "compilation.namedChunkGroups[]": "chunkGroup",
2226 "compilation.errors[]": "error",
2227 "compilation.warnings[]": "warning",
2228 "chunk.modules[]": "module",
2229 "chunk.rootModules[]": "module",
2230 "chunk.origins[]": "chunkOrigin",
2231 "compilation.chunks[]": "chunk",
2232 "compilation.assets[]": "asset",
2233 "asset.related[]": "asset",
2234 "module.issuerPath[]": "moduleIssuer",
2235 "module.reasons[]": "moduleReason",
2236 "module.modules[]": "module",
2237 "module.children[]": "module",
2238 "moduleTrace[]": "moduleTraceItem",
2239 "moduleTraceItem.dependencies[]": "moduleTraceDependency"
2240};
2241
2242/**
2243 * @param {Object[]} items items to be merged
2244 * @returns {Object} an object
2245 */
2246const mergeToObject = items => {
2247 const obj = Object.create(null);
2248 for (const item of items) {
2249 obj[item.name] = item;
2250 }
2251 return obj;
2252};
2253
2254/** @type {Record<string, (items: Object[]) => any>} */
2255const MERGER = {
2256 "compilation.entrypoints": mergeToObject,
2257 "compilation.namedChunkGroups": mergeToObject
2258};
2259
2260class DefaultStatsFactoryPlugin {
2261 /**
2262 * Apply the plugin
2263 * @param {Compiler} compiler the compiler instance
2264 * @returns {void}
2265 */
2266 apply(compiler) {
2267 compiler.hooks.compilation.tap("DefaultStatsFactoryPlugin", compilation => {
2268 compilation.hooks.statsFactory.tap(
2269 "DefaultStatsFactoryPlugin",
2270 (stats, options, context) => {
2271 iterateConfig(SIMPLE_EXTRACTORS, options, (hookFor, fn) => {
2272 stats.hooks.extract
2273 .for(hookFor)
2274 .tap("DefaultStatsFactoryPlugin", (obj, data, ctx) =>
2275 fn(obj, data, ctx, options, stats)
2276 );
2277 });
2278 iterateConfig(FILTER, options, (hookFor, fn) => {
2279 stats.hooks.filter
2280 .for(hookFor)
2281 .tap("DefaultStatsFactoryPlugin", (item, ctx, idx, i) =>
2282 fn(item, ctx, options, idx, i)
2283 );
2284 });
2285 iterateConfig(FILTER_RESULTS, options, (hookFor, fn) => {
2286 stats.hooks.filterResults
2287 .for(hookFor)
2288 .tap("DefaultStatsFactoryPlugin", (item, ctx, idx, i) =>
2289 fn(item, ctx, options, idx, i)
2290 );
2291 });
2292 iterateConfig(SORTERS, options, (hookFor, fn) => {
2293 stats.hooks.sort
2294 .for(hookFor)
2295 .tap("DefaultStatsFactoryPlugin", (comparators, ctx) =>
2296 fn(comparators, ctx, options)
2297 );
2298 });
2299 iterateConfig(RESULT_SORTERS, options, (hookFor, fn) => {
2300 stats.hooks.sortResults
2301 .for(hookFor)
2302 .tap("DefaultStatsFactoryPlugin", (comparators, ctx) =>
2303 fn(comparators, ctx, options)
2304 );
2305 });
2306 iterateConfig(RESULT_GROUPERS, options, (hookFor, fn) => {
2307 stats.hooks.groupResults
2308 .for(hookFor)
2309 .tap("DefaultStatsFactoryPlugin", (groupConfigs, ctx) =>
2310 fn(groupConfigs, ctx, options)
2311 );
2312 });
2313 for (const key of Object.keys(ITEM_NAMES)) {
2314 const itemName = ITEM_NAMES[key];
2315 stats.hooks.getItemName
2316 .for(key)
2317 .tap("DefaultStatsFactoryPlugin", () => itemName);
2318 }
2319 for (const key of Object.keys(MERGER)) {
2320 const merger = MERGER[key];
2321 stats.hooks.merge.for(key).tap("DefaultStatsFactoryPlugin", merger);
2322 }
2323 if (options.children) {
2324 if (Array.isArray(options.children)) {
2325 stats.hooks.getItemFactory
2326 .for("compilation.children[].compilation")
2327 .tap("DefaultStatsFactoryPlugin", (comp, { _index: idx }) => {
2328 if (idx < options.children.length) {
2329 return compilation.createStatsFactory(
2330 compilation.createStatsOptions(
2331 options.children[idx],
2332 context
2333 )
2334 );
2335 }
2336 });
2337 } else if (options.children !== true) {
2338 const childFactory = compilation.createStatsFactory(
2339 compilation.createStatsOptions(options.children, context)
2340 );
2341 stats.hooks.getItemFactory
2342 .for("compilation.children[].compilation")
2343 .tap("DefaultStatsFactoryPlugin", () => {
2344 return childFactory;
2345 });
2346 }
2347 }
2348 }
2349 );
2350 });
2351 }
2352}
2353module.exports = DefaultStatsFactoryPlugin;
Note: See TracBrowser for help on using the repository browser.