UNPKG

webpack

Version:

Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.

1,611 lines (1,568 loc) 70.7 kB
/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const util = require("util"); const ModuleDependency = require("../dependencies/ModuleDependency"); const formatLocation = require("../formatLocation"); const { LogType } = require("../logging/Logger"); const AggressiveSplittingPlugin = require("../optimize/AggressiveSplittingPlugin"); const SizeLimitsPlugin = require("../performance/SizeLimitsPlugin"); const { countIterable } = require("../util/IterableHelpers"); const { compareLocations, compareChunksById, compareNumbers, compareIds, concatComparators, compareSelect, compareModulesByIdentifier } = require("../util/comparators"); const { makePathsRelative, parseResource } = require("../util/identifier"); /** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("../Chunk")} Chunk */ /** @typedef {import("../ChunkGroup")} ChunkGroup */ /** @typedef {import("../ChunkGroup").OriginRecord} OriginRecord */ /** @typedef {import("../Compilation")} Compilation */ /** @typedef {import("../Compilation").Asset} Asset */ /** @typedef {import("../Compilation").AssetInfo} AssetInfo */ /** @typedef {import("../Compilation").NormalizedStatsOptions} NormalizedStatsOptions */ /** @typedef {import("../Compiler")} Compiler */ /** @typedef {import("../Dependency")} Dependency */ /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */ /** @typedef {import("../Module")} Module */ /** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */ /** @typedef {import("../ModuleProfile")} ModuleProfile */ /** @typedef {import("../RequestShortener")} RequestShortener */ /** @typedef {import("../WebpackError")} WebpackError */ /** @template T @typedef {import("../util/comparators").Comparator<T>} Comparator<T> */ /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */ /** @typedef {import("../util/smartGrouping").GroupConfig<any, object>} GroupConfig */ /** @typedef {import("./StatsFactory")} StatsFactory */ /** @typedef {import("./StatsFactory").StatsFactoryContext} StatsFactoryContext */ /** @typedef {KnownStatsCompilation & Record<string, any>} StatsCompilation */ /** * @typedef {Object} KnownStatsCompilation * @property {any=} env * @property {string=} name * @property {string=} hash * @property {string=} version * @property {number=} time * @property {number=} builtAt * @property {boolean=} needAdditionalPass * @property {string=} publicPath * @property {string=} outputPath * @property {Record<string, string[]>=} assetsByChunkName * @property {StatsAsset[]=} assets * @property {number=} filteredAssets * @property {StatsChunk[]=} chunks * @property {StatsModule[]=} modules * @property {number=} filteredModules * @property {Record<string, StatsChunkGroup>=} entrypoints * @property {Record<string, StatsChunkGroup>=} namedChunkGroups * @property {StatsError[]=} errors * @property {number=} errorsCount * @property {StatsError[]=} warnings * @property {number=} warningsCount * @property {StatsCompilation[]=} children * @property {Record<string, StatsLogging>=} logging */ /** @typedef {KnownStatsLogging & Record<string, any>} StatsLogging */ /** * @typedef {Object} KnownStatsLogging * @property {StatsLoggingEntry[]} entries * @property {number} filteredEntries * @property {boolean} debug */ /** @typedef {KnownStatsLoggingEntry & Record<string, any>} StatsLoggingEntry */ /** * @typedef {Object} KnownStatsLoggingEntry * @property {string} type * @property {string} message * @property {string[]=} trace * @property {StatsLoggingEntry[]=} children * @property {any[]=} args * @property {number=} time */ /** @typedef {KnownStatsAsset & Record<string, any>} StatsAsset */ /** * @typedef {Object} KnownStatsAsset * @property {string} type * @property {string} name * @property {AssetInfo} info * @property {number} size * @property {boolean} emitted * @property {boolean} comparedForEmit * @property {boolean} cached * @property {StatsAsset[]=} related * @property {(string|number)[]=} chunkNames * @property {(string|number)[]=} chunkIdHints * @property {(string|number)[]=} chunks * @property {(string|number)[]=} auxiliaryChunkNames * @property {(string|number)[]=} auxiliaryChunks * @property {(string|number)[]=} auxiliaryChunkIdHints * @property {number=} filteredRelated * @property {boolean=} isOverSizeLimit */ /** @typedef {KnownStatsChunkGroup & Record<string, any>} StatsChunkGroup */ /** * @typedef {Object} KnownStatsChunkGroup * @property {string=} name * @property {(string|number)[]=} chunks * @property {({ name: string, size?: number })[]=} assets * @property {number=} filteredAssets * @property {number=} assetsSize * @property {({ name: string, size?: number })[]=} auxiliaryAssets * @property {number=} filteredAuxiliaryAssets * @property {number=} auxiliaryAssetsSize * @property {{ [x: string]: StatsChunkGroup[] }=} children * @property {{ [x: string]: string[] }=} childAssets * @property {boolean=} isOverSizeLimit */ /** @typedef {KnownStatsModule & Record<string, any>} StatsModule */ /** * @typedef {Object} KnownStatsModule * @property {string=} type * @property {string=} moduleType * @property {string=} layer * @property {string=} identifier * @property {string=} name * @property {string=} nameForCondition * @property {number=} index * @property {number=} preOrderIndex * @property {number=} index2 * @property {number=} postOrderIndex * @property {number=} size * @property {{[x: string]: number}=} sizes * @property {boolean=} cacheable * @property {boolean=} built * @property {boolean=} codeGenerated * @property {boolean=} buildTimeExecuted * @property {boolean=} cached * @property {boolean=} optional * @property {boolean=} orphan * @property {string|number=} id * @property {string|number=} issuerId * @property {(string|number)[]=} chunks * @property {(string|number)[]=} assets * @property {boolean=} dependent * @property {string=} issuer * @property {string=} issuerName * @property {StatsModuleIssuer[]=} issuerPath * @property {boolean=} failed * @property {number=} errors * @property {number=} warnings * @property {StatsProfile=} profile * @property {StatsModuleReason[]=} reasons * @property {(boolean | string[])=} usedExports * @property {string[]=} providedExports * @property {string[]=} optimizationBailout * @property {number=} depth * @property {StatsModule[]=} modules * @property {number=} filteredModules * @property {ReturnType<Source["source"]>=} source */ /** @typedef {KnownStatsProfile & Record<string, any>} StatsProfile */ /** * @typedef {Object} KnownStatsProfile * @property {number} total * @property {number} resolving * @property {number} restoring * @property {number} building * @property {number} integration * @property {number} storing * @property {number} additionalResolving * @property {number} additionalIntegration * @property {number} factory * @property {number} dependencies */ /** @typedef {KnownStatsModuleIssuer & Record<string, any>} StatsModuleIssuer */ /** * @typedef {Object} KnownStatsModuleIssuer * @property {string=} identifier * @property {string=} name * @property {(string|number)=} id * @property {StatsProfile=} profile */ /** @typedef {KnownStatsModuleReason & Record<string, any>} StatsModuleReason */ /** * @typedef {Object} KnownStatsModuleReason * @property {string=} moduleIdentifier * @property {string=} module * @property {string=} moduleName * @property {string=} resolvedModuleIdentifier * @property {string=} resolvedModule * @property {string=} type * @property {boolean} active * @property {string=} explanation * @property {string=} userRequest * @property {string=} loc * @property {(string|number)=} moduleId * @property {(string|number)=} resolvedModuleId */ /** @typedef {KnownStatsChunk & Record<string, any>} StatsChunk */ /** * @typedef {Object} KnownStatsChunk * @property {boolean} rendered * @property {boolean} initial * @property {boolean} entry * @property {boolean} recorded * @property {string=} reason * @property {number} size * @property {Record<string, number>=} sizes * @property {string[]=} names * @property {string[]=} idHints * @property {string[]=} runtime * @property {string[]=} files * @property {string[]=} auxiliaryFiles * @property {string} hash * @property {Record<string, (string|number)[]>=} childrenByOrder * @property {(string|number)=} id * @property {(string|number)[]=} siblings * @property {(string|number)[]=} parents * @property {(string|number)[]=} children * @property {StatsModule[]=} modules * @property {number=} filteredModules * @property {StatsChunkOrigin[]=} origins */ /** @typedef {KnownStatsChunkOrigin & Record<string, any>} StatsChunkOrigin */ /** * @typedef {Object} KnownStatsChunkOrigin * @property {string=} module * @property {string=} moduleIdentifier * @property {string=} moduleName * @property {string=} loc * @property {string=} request * @property {(string|number)=} moduleId */ /** @typedef {KnownStatsModuleTraceItem & Record<string, any>} StatsModuleTraceItem */ /** * @typedef {Object} KnownStatsModuleTraceItem * @property {string=} originIdentifier * @property {string=} originName * @property {string=} moduleIdentifier * @property {string=} moduleName * @property {StatsModuleTraceDependency[]=} dependencies * @property {(string|number)=} originId * @property {(string|number)=} moduleId */ /** @typedef {KnownStatsModuleTraceDependency & Record<string, any>} StatsModuleTraceDependency */ /** * @typedef {Object} KnownStatsModuleTraceDependency * @property {string=} loc */ /** @typedef {KnownStatsError & Record<string, any>} StatsError */ /** * @typedef {Object} KnownStatsError * @property {string} message * @property {string=} chunkName * @property {boolean=} chunkEntry * @property {boolean=} chunkInitial * @property {string=} file * @property {string=} moduleIdentifier * @property {string=} moduleName * @property {string=} loc * @property {string|number=} chunkId * @property {string|number=} moduleId * @property {StatsModuleTraceItem[]=} moduleTrace * @property {any=} details * @property {string=} stack */ /** @typedef {Asset & { type: string, related: PreprocessedAsset[] }} PreprocessedAsset */ /** * @template T * @template O * @typedef {Record<string, (object: O, data: T, context: StatsFactoryContext, options: NormalizedStatsOptions, factory: StatsFactory) => void>} ExtractorsByOption */ /** * @typedef {Object} SimpleExtractors * @property {ExtractorsByOption<Compilation, StatsCompilation>} compilation * @property {ExtractorsByOption<PreprocessedAsset, StatsAsset>} asset * @property {ExtractorsByOption<PreprocessedAsset, StatsAsset>} asset$visible * @property {ExtractorsByOption<{ name: string, chunkGroup: ChunkGroup }, StatsChunkGroup>} chunkGroup * @property {ExtractorsByOption<Module, StatsModule>} module * @property {ExtractorsByOption<Module, StatsModule>} module$visible * @property {ExtractorsByOption<Module, StatsModuleIssuer>} moduleIssuer * @property {ExtractorsByOption<ModuleProfile, StatsProfile>} profile * @property {ExtractorsByOption<ModuleGraphConnection, StatsModuleReason>} moduleReason * @property {ExtractorsByOption<Chunk, StatsChunk>} chunk * @property {ExtractorsByOption<OriginRecord, StatsChunkOrigin>} chunkOrigin * @property {ExtractorsByOption<WebpackError, StatsError>} error * @property {ExtractorsByOption<WebpackError, StatsError>} warning * @property {ExtractorsByOption<{ origin: Module, module: Module }, StatsModuleTraceItem>} moduleTraceItem * @property {ExtractorsByOption<Dependency, StatsModuleTraceDependency>} moduleTraceDependency */ /** * @template T * @template I * @param {Iterable<T>} items items to select from * @param {function(T): Iterable<I>} selector selector function to select values from item * @returns {I[]} array of values */ const uniqueArray = (items, selector) => { /** @type {Set<I>} */ const set = new Set(); for (const item of items) { for (const i of selector(item)) { set.add(i); } } return Array.from(set); }; /** * @template T * @template I * @param {Iterable<T>} items items to select from * @param {function(T): Iterable<I>} selector selector function to select values from item * @param {Comparator<I>} comparator comparator function * @returns {I[]} array of values */ const uniqueOrderedArray = (items, selector, comparator) => { return uniqueArray(items, selector).sort(comparator); }; /** @template T @template R @typedef {{ [P in keyof T]: R }} MappedValues<T, R> */ /** * @template T * @template R * @param {T} obj object to be mapped * @param {function(T[keyof T], keyof T): R} fn mapping function * @returns {MappedValues<T, R>} mapped object */ const mapObject = (obj, fn) => { const newObj = Object.create(null); for (const key of Object.keys(obj)) { newObj[key] = fn(obj[key], /** @type {keyof T} */ (key)); } return newObj; }; /** * @param {Compilation} compilation the compilation * @param {function(Compilation, string): any[]} getItems get items * @returns {number} total number */ const countWithChildren = (compilation, getItems) => { let count = getItems(compilation, "").length; for (const child of compilation.children) { count += countWithChildren(child, (c, type) => getItems(c, `.children[].compilation${type}`) ); } return count; }; /** @type {ExtractorsByOption<WebpackError | string, StatsError>} */ const EXTRACT_ERROR = { _: (object, error, context, { requestShortener }) => { // TODO webpack 6 disallow strings in the errors/warnings list if (typeof error === "string") { object.message = error; } else { if (error.chunk) { object.chunkName = error.chunk.name; object.chunkEntry = error.chunk.hasRuntime(); object.chunkInitial = error.chunk.canBeInitial(); } if (error.file) { object.file = error.file; } if (error.module) { object.moduleIdentifier = error.module.identifier(); object.moduleName = error.module.readableIdentifier(requestShortener); } if (error.loc) { object.loc = formatLocation(error.loc); } object.message = error.message; } }, ids: (object, error, { compilation: { chunkGraph } }) => { if (typeof error !== "string") { if (error.chunk) { object.chunkId = error.chunk.id; } if (error.module) { object.moduleId = chunkGraph.getModuleId(error.module); } } }, moduleTrace: (object, error, context, options, factory) => { if (typeof error !== "string" && error.module) { const { type, compilation: { moduleGraph } } = context; /** @type {Set<Module>} */ const visitedModules = new Set(); const moduleTrace = []; let current = error.module; while (current) { if (visitedModules.has(current)) break; // circular (technically impossible, but how knows) visitedModules.add(current); const origin = moduleGraph.getIssuer(current); if (!origin) break; moduleTrace.push({ origin, module: current }); current = origin; } object.moduleTrace = factory.create( `${type}.moduleTrace`, moduleTrace, context ); } }, errorDetails: ( object, error, { type, compilation, cachedGetErrors, cachedGetWarnings }, { errorDetails } ) => { if ( typeof error !== "string" && (errorDetails === true || (type.endsWith(".error") && cachedGetErrors(compilation).length < 3)) ) { object.details = error.details; } }, errorStack: (object, error) => { if (typeof error !== "string") { object.stack = error.stack; } } }; /** @type {SimpleExtractors} */ const SIMPLE_EXTRACTORS = { compilation: { _: (object, compilation, context, options) => { if (!context.makePathsRelative) { context.makePathsRelative = makePathsRelative.bindContextCache( compilation.compiler.context, compilation.compiler.root ); } if (!context.cachedGetErrors) { const map = new WeakMap(); context.cachedGetErrors = compilation => { return ( map.get(compilation) || (errors => (map.set(compilation, errors), errors))( compilation.getErrors() ) ); }; } if (!context.cachedGetWarnings) { const map = new WeakMap(); context.cachedGetWarnings = compilation => { return ( map.get(compilation) || (warnings => (map.set(compilation, warnings), warnings))( compilation.getWarnings() ) ); }; } if (compilation.name) { object.name = compilation.name; } if (compilation.needAdditionalPass) { object.needAdditionalPass = true; } const { logging, loggingDebug, loggingTrace } = options; if (logging || (loggingDebug && loggingDebug.length > 0)) { const util = require("util"); object.logging = {}; let acceptedTypes; let collapsedGroups = false; switch (logging) { default: acceptedTypes = new Set(); break; case "error": acceptedTypes = new Set([LogType.error]); break; case "warn": acceptedTypes = new Set([LogType.error, LogType.warn]); break; case "info": acceptedTypes = new Set([ LogType.error, LogType.warn, LogType.info ]); break; case "log": acceptedTypes = new Set([ LogType.error, LogType.warn, LogType.info, LogType.log, LogType.group, LogType.groupEnd, LogType.groupCollapsed, LogType.clear ]); break; case "verbose": acceptedTypes = new Set([ LogType.error, LogType.warn, LogType.info, LogType.log, LogType.group, LogType.groupEnd, LogType.groupCollapsed, LogType.profile, LogType.profileEnd, LogType.time, LogType.status, LogType.clear ]); collapsedGroups = true; break; } const cachedMakePathsRelative = makePathsRelative.bindContextCache( options.context, compilation.compiler.root ); let depthInCollapsedGroup = 0; for (const [origin, logEntries] of compilation.logging) { const debugMode = loggingDebug.some(fn => fn(origin)); if (logging === false && !debugMode) continue; /** @type {KnownStatsLoggingEntry[]} */ const groupStack = []; /** @type {KnownStatsLoggingEntry[]} */ const rootList = []; let currentList = rootList; let processedLogEntries = 0; for (const entry of logEntries) { let type = entry.type; if (!debugMode && !acceptedTypes.has(type)) continue; // Expand groups in verbose and debug modes if ( type === LogType.groupCollapsed && (debugMode || collapsedGroups) ) type = LogType.group; if (depthInCollapsedGroup === 0) { processedLogEntries++; } if (type === LogType.groupEnd) { groupStack.pop(); if (groupStack.length > 0) { currentList = groupStack[groupStack.length - 1].children; } else { currentList = rootList; } if (depthInCollapsedGroup > 0) depthInCollapsedGroup--; continue; } let message = undefined; if (entry.type === LogType.time) { message = `${entry.args[0]}: ${ entry.args[1] * 1000 + entry.args[2] / 1000000 } ms`; } else if (entry.args && entry.args.length > 0) { message = util.format(entry.args[0], ...entry.args.slice(1)); } /** @type {KnownStatsLoggingEntry} */ const newEntry = { ...entry, type, message, trace: loggingTrace ? entry.trace : undefined, children: type === LogType.group || type === LogType.groupCollapsed ? [] : undefined }; currentList.push(newEntry); if (newEntry.children) { groupStack.push(newEntry); currentList = newEntry.children; if (depthInCollapsedGroup > 0) { depthInCollapsedGroup++; } else if (type === LogType.groupCollapsed) { depthInCollapsedGroup = 1; } } } let name = cachedMakePathsRelative(origin).replace(/\|/g, " "); if (name in object.logging) { let i = 1; while (`${name}#${i}` in object.logging) { i++; } name = `${name}#${i}`; } object.logging[name] = { entries: rootList, filteredEntries: logEntries.length - processedLogEntries, debug: debugMode }; } } }, hash: (object, compilation) => { object.hash = compilation.hash; }, version: object => { object.version = require("../../package.json").version; }, env: (object, compilation, context, { _env }) => { object.env = _env; }, timings: (object, compilation) => { object.time = compilation.endTime - compilation.startTime; }, builtAt: (object, compilation) => { object.builtAt = compilation.endTime; }, publicPath: (object, compilation) => { object.publicPath = compilation.getPath( compilation.outputOptions.publicPath ); }, outputPath: (object, compilation) => { object.outputPath = compilation.outputOptions.path; }, assets: (object, compilation, context, options, factory) => { const { type } = context; /** @type {Map<string, Chunk[]>} */ const compilationFileToChunks = new Map(); /** @type {Map<string, Chunk[]>} */ const compilationAuxiliaryFileToChunks = new Map(); for (const chunk of compilation.chunks) { for (const file of chunk.files) { let array = compilationFileToChunks.get(file); if (array === undefined) { array = []; compilationFileToChunks.set(file, array); } array.push(chunk); } for (const file of chunk.auxiliaryFiles) { let array = compilationAuxiliaryFileToChunks.get(file); if (array === undefined) { array = []; compilationAuxiliaryFileToChunks.set(file, array); } array.push(chunk); } } /** @type {Map<string, PreprocessedAsset>} */ const assetMap = new Map(); /** @type {Set<PreprocessedAsset>} */ const assets = new Set(); for (const asset of compilation.getAssets()) { /** @type {PreprocessedAsset} */ const item = { ...asset, type: "asset", related: undefined }; assets.add(item); assetMap.set(asset.name, item); } for (const item of assetMap.values()) { const related = item.info.related; if (!related) continue; for (const type of Object.keys(related)) { const relatedEntry = related[type]; const deps = Array.isArray(relatedEntry) ? relatedEntry : [relatedEntry]; for (const dep of deps) { const depItem = assetMap.get(dep); if (!depItem) continue; assets.delete(depItem); depItem.type = type; item.related = item.related || []; item.related.push(depItem); } } } object.assetsByChunkName = {}; for (const [file, chunks] of compilationFileToChunks) { for (const chunk of chunks) { const name = chunk.name; if (!name) continue; if ( !Object.prototype.hasOwnProperty.call( object.assetsByChunkName, name ) ) { object.assetsByChunkName[name] = []; } object.assetsByChunkName[name].push(file); } } const groupedAssets = factory.create( `${type}.assets`, Array.from(assets), { ...context, compilationFileToChunks, compilationAuxiliaryFileToChunks } ); const limited = spaceLimited(groupedAssets, options.assetsSpace); object.assets = limited.children; object.filteredAssets = limited.filteredChildren; }, chunks: (object, compilation, context, options, factory) => { const { type } = context; object.chunks = factory.create( `${type}.chunks`, Array.from(compilation.chunks), context ); }, modules: (object, compilation, context, options, factory) => { const { type } = context; const array = Array.from(compilation.modules); const groupedModules = factory.create(`${type}.modules`, array, context); const limited = spaceLimited(groupedModules, options.modulesSpace); object.modules = limited.children; object.filteredModules = limited.filteredChildren; }, entrypoints: ( object, compilation, context, { entrypoints, chunkGroups, chunkGroupAuxiliary, chunkGroupChildren }, factory ) => { const { type } = context; const array = Array.from(compilation.entrypoints, ([key, value]) => ({ name: key, chunkGroup: value })); if (entrypoints === "auto" && !chunkGroups) { if (array.length > 5) return; if ( !chunkGroupChildren && array.every(({ chunkGroup }) => { if (chunkGroup.chunks.length !== 1) return false; const chunk = chunkGroup.chunks[0]; return ( chunk.files.size === 1 && (!chunkGroupAuxiliary || chunk.auxiliaryFiles.size === 0) ); }) ) { return; } } object.entrypoints = factory.create( `${type}.entrypoints`, array, context ); }, chunkGroups: (object, compilation, context, options, factory) => { const { type } = context; const array = Array.from( compilation.namedChunkGroups, ([key, value]) => ({ name: key, chunkGroup: value }) ); object.namedChunkGroups = factory.create( `${type}.namedChunkGroups`, array, context ); }, errors: (object, compilation, context, options, factory) => { const { type, cachedGetErrors } = context; object.errors = factory.create( `${type}.errors`, cachedGetErrors(compilation), context ); }, errorsCount: (object, compilation, { cachedGetErrors }) => { object.errorsCount = countWithChildren(compilation, c => cachedGetErrors(c) ); }, warnings: (object, compilation, context, options, factory) => { const { type, cachedGetWarnings } = context; object.warnings = factory.create( `${type}.warnings`, cachedGetWarnings(compilation), context ); }, warningsCount: ( object, compilation, context, { warningsFilter }, factory ) => { const { type, cachedGetWarnings } = context; object.warningsCount = countWithChildren(compilation, (c, childType) => { if (!warningsFilter && warningsFilter.length === 0) return cachedGetWarnings(c); return factory .create(`${type}${childType}.warnings`, cachedGetWarnings(c), context) .filter(warning => { const warningString = Object.keys(warning) .map(key => `${warning[key]}`) .join("\n"); return !warningsFilter.some(filter => filter(warning, warningString) ); }); }); }, errorDetails: ( object, compilation, { cachedGetErrors, cachedGetWarnings }, { errorDetails, errors, warnings } ) => { if (errorDetails === "auto") { if (warnings) { const warnings = cachedGetWarnings(compilation); object.filteredWarningDetailsCount = warnings .map(e => typeof e !== "string" && e.details) .filter(Boolean).length; } if (errors) { const errors = cachedGetErrors(compilation); if (errors.length >= 3) { object.filteredErrorDetailsCount = errors .map(e => typeof e !== "string" && e.details) .filter(Boolean).length; } } } }, children: (object, compilation, context, options, factory) => { const { type } = context; object.children = factory.create( `${type}.children`, compilation.children, context ); } }, asset: { _: (object, asset, context, options, factory) => { const { compilation } = context; object.type = asset.type; object.name = asset.name; object.size = asset.source.size(); object.emitted = compilation.emittedAssets.has(asset.name); object.comparedForEmit = compilation.comparedForEmitAssets.has( asset.name ); const cached = !object.emitted && !object.comparedForEmit; object.cached = cached; object.info = asset.info; if (!cached || options.cachedAssets) { Object.assign( object, factory.create(`${context.type}$visible`, asset, context) ); } } }, asset$visible: { _: ( object, asset, { compilation, compilationFileToChunks, compilationAuxiliaryFileToChunks } ) => { const chunks = compilationFileToChunks.get(asset.name) || []; const auxiliaryChunks = compilationAuxiliaryFileToChunks.get(asset.name) || []; object.chunkNames = uniqueOrderedArray( chunks, c => (c.name ? [c.name] : []), compareIds ); object.chunkIdHints = uniqueOrderedArray( chunks, c => Array.from(c.idNameHints), compareIds ); object.auxiliaryChunkNames = uniqueOrderedArray( auxiliaryChunks, c => (c.name ? [c.name] : []), compareIds ); object.auxiliaryChunkIdHints = uniqueOrderedArray( auxiliaryChunks, c => Array.from(c.idNameHints), compareIds ); object.filteredRelated = asset.related ? asset.related.length : undefined; }, relatedAssets: (object, asset, context, options, factory) => { const { type } = context; object.related = factory.create( `${type.slice(0, -8)}.related`, asset.related, context ); object.filteredRelated = asset.related ? asset.related.length - object.related.length : undefined; }, ids: ( object, asset, { compilationFileToChunks, compilationAuxiliaryFileToChunks } ) => { const chunks = compilationFileToChunks.get(asset.name) || []; const auxiliaryChunks = compilationAuxiliaryFileToChunks.get(asset.name) || []; object.chunks = uniqueOrderedArray(chunks, c => c.ids, compareIds); object.auxiliaryChunks = uniqueOrderedArray( auxiliaryChunks, c => c.ids, compareIds ); }, performance: (object, asset) => { object.isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(asset.source); } }, chunkGroup: { _: ( object, { name, chunkGroup }, { compilation, compilation: { moduleGraph, chunkGraph } }, { ids, chunkGroupAuxiliary, chunkGroupChildren, chunkGroupMaxAssets } ) => { const children = chunkGroupChildren && chunkGroup.getChildrenByOrders(moduleGraph, chunkGraph); /** * @param {string} name Name * @returns {{ name: string, size: number }} Asset object */ const toAsset = name => { const asset = compilation.getAsset(name); return { name, size: asset ? asset.info.size : -1 }; }; /** @type {(total: number, asset: { size: number }) => number} */ const sizeReducer = (total, { size }) => total + size; const assets = uniqueArray(chunkGroup.chunks, c => c.files).map(toAsset); const auxiliaryAssets = uniqueOrderedArray( chunkGroup.chunks, c => c.auxiliaryFiles, compareIds ).map(toAsset); const assetsSize = assets.reduce(sizeReducer, 0); const auxiliaryAssetsSize = auxiliaryAssets.reduce(sizeReducer, 0); /** @type {KnownStatsChunkGroup} */ const statsChunkGroup = { name, chunks: ids ? chunkGroup.chunks.map(c => c.id) : undefined, assets: assets.length <= chunkGroupMaxAssets ? assets : undefined, filteredAssets: assets.length <= chunkGroupMaxAssets ? 0 : assets.length, assetsSize, auxiliaryAssets: chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets ? auxiliaryAssets : undefined, filteredAuxiliaryAssets: chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets ? 0 : auxiliaryAssets.length, auxiliaryAssetsSize, children: children ? mapObject(children, groups => groups.map(group => { const assets = uniqueArray(group.chunks, c => c.files).map( toAsset ); const auxiliaryAssets = uniqueOrderedArray( group.chunks, c => c.auxiliaryFiles, compareIds ).map(toAsset); /** @type {KnownStatsChunkGroup} */ const childStatsChunkGroup = { name: group.name, chunks: ids ? group.chunks.map(c => c.id) : undefined, assets: assets.length <= chunkGroupMaxAssets ? assets : undefined, filteredAssets: assets.length <= chunkGroupMaxAssets ? 0 : assets.length, auxiliaryAssets: chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets ? auxiliaryAssets : undefined, filteredAuxiliaryAssets: chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets ? 0 : auxiliaryAssets.length }; return childStatsChunkGroup; }) ) : undefined, childAssets: children ? mapObject(children, groups => { /** @type {Set<string>} */ const set = new Set(); for (const group of groups) { for (const chunk of group.chunks) { for (const asset of chunk.files) { set.add(asset); } } } return Array.from(set); }) : undefined }; Object.assign(object, statsChunkGroup); }, performance: (object, { chunkGroup }) => { object.isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(chunkGroup); } }, module: { _: (object, module, context, options, factory) => { const { compilation, type } = context; const built = compilation.builtModules.has(module); const codeGenerated = compilation.codeGeneratedModules.has(module); const buildTimeExecuted = compilation.buildTimeExecutedModules.has(module); /** @type {{[x: string]: number}} */ const sizes = {}; for (const sourceType of module.getSourceTypes()) { sizes[sourceType] = module.size(sourceType); } /** @type {KnownStatsModule} */ const statsModule = { type: "module", moduleType: module.type, layer: module.layer, size: module.size(), sizes, built, codeGenerated, buildTimeExecuted, cached: !built && !codeGenerated }; Object.assign(object, statsModule); if (built || codeGenerated || options.cachedModules) { Object.assign( object, factory.create(`${type}$visible`, module, context) ); } } }, module$visible: { _: (object, module, context, { requestShortener }, factory) => { const { compilation, type, rootModules } = context; const { moduleGraph } = compilation; /** @type {Module[]} */ const path = []; const issuer = moduleGraph.getIssuer(module); let current = issuer; while (current) { path.push(current); current = moduleGraph.getIssuer(current); } path.reverse(); const profile = moduleGraph.getProfile(module); const errors = module.getErrors(); const errorsCount = errors !== undefined ? countIterable(errors) : 0; const warnings = module.getWarnings(); const warningsCount = warnings !== undefined ? countIterable(warnings) : 0; /** @type {{[x: string]: number}} */ const sizes = {}; for (const sourceType of module.getSourceTypes()) { sizes[sourceType] = module.size(sourceType); } /** @type {KnownStatsModule} */ const statsModule = { identifier: module.identifier(), name: module.readableIdentifier(requestShortener), nameForCondition: module.nameForCondition(), index: moduleGraph.getPreOrderIndex(module), preOrderIndex: moduleGraph.getPreOrderIndex(module), index2: moduleGraph.getPostOrderIndex(module), postOrderIndex: moduleGraph.getPostOrderIndex(module), cacheable: module.buildInfo.cacheable, optional: module.isOptional(moduleGraph), orphan: !type.endsWith("module.modules[].module$visible") && compilation.chunkGraph.getNumberOfModuleChunks(module) === 0, dependent: rootModules ? !rootModules.has(module) : undefined, issuer: issuer && issuer.identifier(), issuerName: issuer && issuer.readableIdentifier(requestShortener), issuerPath: issuer && factory.create(`${type.slice(0, -8)}.issuerPath`, path, context), failed: errorsCount > 0, errors: errorsCount, warnings: warningsCount }; Object.assign(object, statsModule); if (profile) { object.profile = factory.create( `${type.slice(0, -8)}.profile`, profile, context ); } }, ids: (object, module, { compilation: { chunkGraph, moduleGraph } }) => { object.id = chunkGraph.getModuleId(module); const issuer = moduleGraph.getIssuer(module); object.issuerId = issuer && chunkGraph.getModuleId(issuer); object.chunks = Array.from( chunkGraph.getOrderedModuleChunksIterable(module, compareChunksById), chunk => chunk.id ); }, moduleAssets: (object, module) => { object.assets = module.buildInfo.assets ? Object.keys(module.buildInfo.assets) : []; }, reasons: (object, module, context, options, factory) => { const { type, compilation: { moduleGraph } } = context; const groupsReasons = factory.create( `${type.slice(0, -8)}.reasons`, Array.from(moduleGraph.getIncomingConnections(module)), context ); const limited = spaceLimited(groupsReasons, options.reasonsSpace); object.reasons = limited.children; object.filteredReasons = limited.filteredChildren; }, usedExports: ( object, module, { runtime, compilation: { moduleGraph } } ) => { const usedExports = moduleGraph.getUsedExports(module, runtime); if (usedExports === null) { object.usedExports = null; } else if (typeof usedExports === "boolean") { object.usedExports = usedExports; } else { object.usedExports = Array.from(usedExports); } }, providedExports: (object, module, { compilation: { moduleGraph } }) => { const providedExports = moduleGraph.getProvidedExports(module); object.providedExports = Array.isArray(providedExports) ? providedExports : null; }, optimizationBailout: ( object, module, { compilation: { moduleGraph } }, { requestShortener } ) => { object.optimizationBailout = moduleGraph .getOptimizationBailout(module) .map(item => { if (typeof item === "function") return item(requestShortener); return item; }); }, depth: (object, module, { compilation: { moduleGraph } }) => { object.depth = moduleGraph.getDepth(module); }, nestedModules: (object, module, context, options, factory) => { const { type } = context; const innerModules = /** @type {Module & { modules?: Module[] }} */ ( module ).modules; if (Array.isArray(innerModules)) { const groupedModules = factory.create( `${type.slice(0, -8)}.modules`, innerModules, context ); const limited = spaceLimited( groupedModules, options.nestedModulesSpace ); object.modules = limited.children; object.filteredModules = limited.filteredChildren; } }, source: (object, module) => { const originalSource = module.originalSource(); if (originalSource) { object.source = originalSource.source(); } } }, profile: { _: (object, profile) => { /** @type {KnownStatsProfile} */ const statsProfile = { total: profile.factory + profile.restoring + profile.integration + profile.building + profile.storing, resolving: profile.factory, restoring: profile.restoring, building: profile.building, integration: profile.integration, storing: profile.storing, additionalResolving: profile.additionalFactories, additionalIntegration: profile.additionalIntegration, // TODO remove this in webpack 6 factory: profile.factory, // TODO remove this in webpack 6 dependencies: profile.additionalFactories }; Object.assign(object, statsProfile); } }, moduleIssuer: { _: (object, module, context, { requestShortener }, factory) => { const { compilation, type } = context; const { moduleGraph } = compilation; const profile = moduleGraph.getProfile(module); /** @type {KnownStatsModuleIssuer} */ const statsModuleIssuer = { identifier: module.identifier(), name: module.readableIdentifier(requestShortener) }; Object.assign(object, statsModuleIssuer); if (profile) { object.profile = factory.create(`${type}.profile`, profile, context); } }, ids: (object, module, { compilation: { chunkGraph } }) => { object.id = chunkGraph.getModuleId(module); } }, moduleReason: { _: (object, reason, { runtime }, { requestShortener }) => { const dep = reason.dependency; const moduleDep = dep && dep instanceof ModuleDependency ? dep : undefined; /** @type {KnownStatsModuleReason} */ const statsModuleReason = { moduleIdentifier: reason.originModule ? reason.originModule.identifier() : null, module: reason.originModule ? reason.originModule.readableIdentifier(requestShortener) : null, moduleName: reason.originModule ? reason.originModule.readableIdentifier(requestShortener) : null, resolvedModuleIdentifier: reason.resolvedOriginModule ? reason.resolvedOriginModule.identifier() : null, resolvedModule: reason.resolvedOriginModule ? reason.resolvedOriginModule.readableIdentifier(requestShortener) : null, type: reason.dependency ? reason.dependency.type : null, active: reason.isActive(runtime), explanation: reason.explanation, userRequest: (moduleDep && moduleDep.userRequest) || null }; Object.assign(object, statsModuleReason); if (reason.dependency) { const locInfo = formatLocation(reason.dependency.loc); if (locInfo) { object.loc = locInfo; } } }, ids: (object, reason, { compilation: { chunkGraph } }) => { object.moduleId = reason.originModule ? chunkGraph.getModuleId(reason.originModule) : null; object.resolvedModuleId = reason.resolvedOriginModule ? chunkGraph.getModuleId(reason.resolvedOriginModule) : null; } }, chunk: { _: (object, chunk, { makePathsRelative, compilation: { chunkGraph } }) => { const childIdByOrder = chunk.getChildIdsByOrders(chunkGraph); /** @type {KnownStatsChunk} */ const statsChunk = { rendered: chunk.rendered, initial: chunk.canBeInitial(), entry: chunk.hasRuntime(), recorded: AggressiveSplittingPlugin.wasChunkRecorded(chunk), reason: chunk.chunkReason, size: chunkGraph.getChunkModulesSize(chunk), sizes: chunkGraph.getChunkModulesSizes(chunk), names: chunk.name ? [chunk.name] : [], idHints: Array.from(chunk.idNameHints), runtime: chunk.runtime === undefined ? undefined : typeof chunk.runtime === "string" ? [makePathsRelative(chunk.runtime)] : Array.from(chunk.runtime.sort(), makePathsRelative), files: Array.from(chunk.files), auxiliaryFiles: Array.from(chunk.auxiliaryFiles).sort(compareIds), hash: chunk.renderedHash, childrenByOrder: childIdByOrder }; Object.assign(object, statsChunk); }, ids: (object, chunk) => { object.id = chunk.id; }, chunkRelations: (object, chunk, { compilation: { chunkGraph } }) => { /** @type {Set<string|number>} */ const parents = new Set(); /** @type {Set<string|number>} */ const children = new Set(); /** @type {Set<string|number>} */ const siblings = new Set(); for (const chunkGroup of chunk.groupsIterable) { for (const parentGroup of chunkGroup.parentsIterable) { for (const chunk of parentGroup.chunks) { parents.add(chunk.id); } } for (const childGroup of chunkGroup.childrenIterable) { for (const chunk of childGroup.chunks) { children.add(chunk.id); } } for (const sibling of chunkGroup.chunks) { if (sibling !== chunk) siblings.add(sibling.id); } } object.siblings = Array.from(siblings).sort(compareIds); object.parents = Array.from(parents).sort(compareIds); object.children = Array.from(children).sort(compareIds); }, chunkModules: (object, chunk, context, options, factory) => { const { type, compilation: { chunkGraph } } = context; const array = chunkGraph.getChunkModules(chunk); const groupedModules = factory.create(`${type}.modules`, array, { ...context, runtime: chunk.runtime, rootModules: new Set(chunkGraph.getChunkRootModules(chunk)) }); const limited = spaceLimited(groupedModules, options.chunkModulesSpace); object.modules = limited.children; object.filteredModules = limited.filteredChildren; }, chunkOrigins: (object, chunk, context, options, factory) => { const { type, compilation: { chunkGraph } } = context; /** @type {Set<string>} */ const originsKeySet = new Set(); const origins = []; for (const g of chunk.groupsIterable) { origins.push(...g.origins); } const array = origins.filter(origin => { const key = [ origin.module ? chunkGraph.getModuleId(origin.module) : undefined, formatLocation(origin.loc), origin.request ].join(); if (originsKeySet.has(key)) return false; originsKeySet.add(key); return true; }); object.origins = factory.create(`${type}.origins`, array, context); } }, chunkOrigin: { _: (object, origin, context, { requestShortener }) => { /** @type {KnownStatsChunkOrigin} */ const statsChunkOrigin = { module: origin.module ? origin.module.identifier() : "", moduleIdentifier: origin.module ? origin.module.identifier() : "", moduleName: origin.module ? origin.module.readableIdentifier(requestShortener) : "", loc: formatLocation(origin.loc), request: origin.request }; Object.assign(object, statsChunkOrigin); }, ids: (object, origin, { compilation: { chunkGraph } }) => { object.moduleId = origin.module ? chunkGraph.getModuleId(origin.module) : undefined; } }, error: EXTRACT_ERROR, warning: EXTRACT_ERROR, moduleTraceItem: { _: (object, { origin, module }, context, { requestShortener }, factory) => { const { type, compilation: { moduleGraph } } = context; object.originIdentifier = origin.identifier(); object.originName = origin.readableIdentifier(requestShortener); object.moduleIdentifier = module.identifier(); object.moduleName = module.readableIdentifier(requestShortener); const dependencies = Array.from( moduleGraph.getIncomingConnections(module) ) .filter(c => c.resolvedOriginModule === origin && c.dependency) .map(c => c.dependency); object.dependencies = factory.create( `${type}.dependencies`, Array.from(new Set(dependencies)), context ); }, ids: (object, { origin, module }, { compilation: { chunkGraph } }) => { object.originId = chunkGraph.getModuleId(origin); object.moduleId = chunkGraph.getModuleId(module); } }, moduleTraceDependency: { _: (object, dependency) => { object.loc = formatLocation(dependency.loc); } } }; /** @type {Record<string, Record<string, (thing: any, context: StatsFactoryContext, options: NormalizedStatsOptions) => boolean | undefined>>} */ const FILTER = { "module.reasons": { "!orphanModules": (reason, { compilation: { chunkGraph } }) => { if ( reason.originModule && chunkGraph.getNumberOfModuleChunks(reason.originModule) === 0 ) { return false; } } } }; /** @type {Record<string, Record<string, (thing: Object, context: StatsFactoryContext, options: NormalizedStatsOptions) => boolean | undefined>>} */ const FILTER_RESULTS = { "compilation.warnings": { warningsFilter: util.deprecate( (warning, context, { warningsFilter }) => { const warningString = Object.keys(warning) .map(key => `${warning[key]}`) .join("\n"); return !warningsFilter.some(filter => filter(warning, warningString)); }, "config.stats.warningsFilter is deprecated in favor of config.ignoreWarnings", "DEP_WEBPACK_STATS_WARNINGS_FILTER" ) } }; /** @type {Record<string, (comparators: Function[], context: StatsFactoryContext) => void>} */ const MODULES_SORTER = { _: (comparators, { compilation: { moduleGraph } }) => { comparators.push( compareSelect( /** * @param {Module} m module * @returns {number} depth */ m => moduleGraph.getDepth(m), compareNumbers ), compareSelect( /** * @param {Module} m module * @returns {number} index */ m => moduleGraph.getPreOrderIndex(m), compareNumbers ), compareSelect( /** * @param {Module} m module * @returns {string} identifier */ m => m.identifier(), compareIds ) ); } }; /** @type {Record<string, Record<string, (comparators: Function[], context: StatsFactoryContext) => void>>} */ const SORTERS = { "compilation.chunks": { _: comparators => { comparators.push(compareSelect(c => c.id, compareIds)); } }, "compilation.modules": MODULES_SORTER, "chunk.rootModules": MODULES_SORTER, "chunk.modules": MODULES_SORTER, "module.modules": MODULES_SORTER, "module.reasons": { _: (comparators, { compilation: { chunkGraph } }) => { comparators.push( compareSelect(x => x.originModule, compareModulesByIdentifier) ); comparators.push( compareSelect(x => x.resolvedOriginModule, compareModulesByIdentifier) ); comparators.push( compareSelect( x => x.dependency, concatComparators( compareSelect( /** * @param {Dependency} x dependency * @returns {DependencyLocation} location */ x => x.loc, compareLocations ), compareSelect(x => x.type, compareIds) ) ) ); } }, "chunk.origins": { _: (comparators, { compilation: { chunkGraph } }) => { comparators.push( compareSelect( origin => origin.module ? chunkGraph.getModuleId(origin.module) : undefined, compareIds ), compareSelect(origin => formatLocation(origin.loc), compareIds), compareSelect(origin => origin.request, compareIds) ); } } }; const getItemSize = item => { // Each item takes