DefaultStatsFactoryPlugin.js 70 KB

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