DefaultStatsPrinterPlugin.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /** @typedef {import("../Compiler")} Compiler */
  7. /** @typedef {import("./StatsPrinter")} StatsPrinter */
  8. /** @typedef {import("./StatsPrinter").StatsPrinterContext} StatsPrinterContext */
  9. const DATA_URI_CONTENT_LENGTH = 16;
  10. const plural = (n, singular, plural) => (n === 1 ? singular : plural);
  11. /**
  12. * @param {Record<string, number>} sizes sizes by source type
  13. * @param {Object} options options
  14. * @param {(number) => string=} options.formatSize size formatter
  15. * @returns {string} text
  16. */
  17. const printSizes = (sizes, { formatSize = n => `${n}` }) => {
  18. const keys = Object.keys(sizes);
  19. if (keys.length > 1) {
  20. return keys.map(key => `${formatSize(sizes[key])} (${key})`).join(" ");
  21. } else if (keys.length === 1) {
  22. return formatSize(sizes[keys[0]]);
  23. }
  24. };
  25. const getResourceName = resource => {
  26. const dataUrl = /^data:[^,]+,/.exec(resource);
  27. if (!dataUrl) return resource;
  28. const len = dataUrl[0].length + DATA_URI_CONTENT_LENGTH;
  29. if (resource.length < len) return resource;
  30. return `${resource.slice(
  31. 0,
  32. Math.min(resource.length - /* '..'.length */ 2, len)
  33. )}..`;
  34. };
  35. const getModuleName = name => {
  36. const [, prefix, resource] = /^(.*!)?([^!]*)$/.exec(name);
  37. return [prefix, getResourceName(resource)];
  38. };
  39. const mapLines = (str, fn) => str.split("\n").map(fn).join("\n");
  40. /**
  41. * @param {number} n a number
  42. * @returns {string} number as two digit string, leading 0
  43. */
  44. const twoDigit = n => (n >= 10 ? `${n}` : `0${n}`);
  45. const isValidId = id => {
  46. return typeof id === "number" || id;
  47. };
  48. const moreCount = (list, count) => {
  49. return list && list.length > 0 ? `+ ${count}` : `${count}`;
  50. };
  51. /** @type {Record<string, (thing: any, context: StatsPrinterContext, printer: StatsPrinter) => string | void>} */
  52. const SIMPLE_PRINTERS = {
  53. "compilation.summary!": (
  54. _,
  55. {
  56. type,
  57. bold,
  58. green,
  59. red,
  60. yellow,
  61. formatDateTime,
  62. formatTime,
  63. compilation: {
  64. name,
  65. hash,
  66. version,
  67. time,
  68. builtAt,
  69. errorsCount,
  70. warningsCount
  71. }
  72. }
  73. ) => {
  74. const root = type === "compilation.summary!";
  75. const warningsMessage =
  76. warningsCount > 0
  77. ? yellow(
  78. `${warningsCount} ${plural(warningsCount, "warning", "warnings")}`
  79. )
  80. : "";
  81. const errorsMessage =
  82. errorsCount > 0
  83. ? red(`${errorsCount} ${plural(errorsCount, "error", "errors")}`)
  84. : "";
  85. const timeMessage = root && time ? ` in ${formatTime(time)}` : "";
  86. const hashMessage = hash ? ` (${hash})` : "";
  87. const builtAtMessage =
  88. root && builtAt ? `${formatDateTime(builtAt)}: ` : "";
  89. const versionMessage = root && version ? `webpack ${version}` : "";
  90. const nameMessage =
  91. root && name
  92. ? bold(name)
  93. : name
  94. ? `Child ${bold(name)}`
  95. : root
  96. ? ""
  97. : "Child";
  98. const subjectMessage =
  99. nameMessage && versionMessage
  100. ? `${nameMessage} (${versionMessage})`
  101. : versionMessage || nameMessage || "webpack";
  102. let statusMessage;
  103. if (errorsMessage && warningsMessage) {
  104. statusMessage = `compiled with ${errorsMessage} and ${warningsMessage}`;
  105. } else if (errorsMessage) {
  106. statusMessage = `compiled with ${errorsMessage}`;
  107. } else if (warningsMessage) {
  108. statusMessage = `compiled with ${warningsMessage}`;
  109. } else if (errorsCount === 0 && warningsCount === 0) {
  110. statusMessage = `compiled ${green("successfully")}`;
  111. } else {
  112. statusMessage = `compiled`;
  113. }
  114. if (
  115. builtAtMessage ||
  116. versionMessage ||
  117. errorsMessage ||
  118. warningsMessage ||
  119. (errorsCount === 0 && warningsCount === 0) ||
  120. timeMessage ||
  121. hashMessage
  122. )
  123. return `${builtAtMessage}${subjectMessage} ${statusMessage}${timeMessage}${hashMessage}`;
  124. },
  125. "compilation.filteredWarningDetailsCount": count =>
  126. count
  127. ? `${count} ${plural(
  128. count,
  129. "warning has",
  130. "warnings have"
  131. )} detailed information that is not shown.\nUse 'stats.errorDetails: true' resp. '--stats-error-details' to show it.`
  132. : undefined,
  133. "compilation.filteredErrorDetailsCount": (count, { yellow }) =>
  134. count
  135. ? yellow(
  136. `${count} ${plural(
  137. count,
  138. "error has",
  139. "errors have"
  140. )} detailed information that is not shown.\nUse 'stats.errorDetails: true' resp. '--stats-error-details' to show it.`
  141. )
  142. : undefined,
  143. "compilation.env": (env, { bold }) =>
  144. env
  145. ? `Environment (--env): ${bold(JSON.stringify(env, null, 2))}`
  146. : undefined,
  147. "compilation.publicPath": (publicPath, { bold }) =>
  148. `PublicPath: ${bold(publicPath || "(none)")}`,
  149. "compilation.entrypoints": (entrypoints, context, printer) =>
  150. Array.isArray(entrypoints)
  151. ? undefined
  152. : printer.print(context.type, Object.values(entrypoints), {
  153. ...context,
  154. chunkGroupKind: "Entrypoint"
  155. }),
  156. "compilation.namedChunkGroups": (namedChunkGroups, context, printer) => {
  157. if (!Array.isArray(namedChunkGroups)) {
  158. const {
  159. compilation: { entrypoints }
  160. } = context;
  161. let chunkGroups = Object.values(namedChunkGroups);
  162. if (entrypoints) {
  163. chunkGroups = chunkGroups.filter(
  164. group =>
  165. !Object.prototype.hasOwnProperty.call(entrypoints, group.name)
  166. );
  167. }
  168. return printer.print(context.type, chunkGroups, {
  169. ...context,
  170. chunkGroupKind: "Chunk Group"
  171. });
  172. }
  173. },
  174. "compilation.assetsByChunkName": () => "",
  175. "compilation.filteredModules": (
  176. filteredModules,
  177. { compilation: { modules } }
  178. ) =>
  179. filteredModules > 0
  180. ? `${moreCount(modules, filteredModules)} ${plural(
  181. filteredModules,
  182. "module",
  183. "modules"
  184. )}`
  185. : undefined,
  186. "compilation.filteredAssets": (filteredAssets, { compilation: { assets } }) =>
  187. filteredAssets > 0
  188. ? `${moreCount(assets, filteredAssets)} ${plural(
  189. filteredAssets,
  190. "asset",
  191. "assets"
  192. )}`
  193. : undefined,
  194. "compilation.logging": (logging, context, printer) =>
  195. Array.isArray(logging)
  196. ? undefined
  197. : printer.print(
  198. context.type,
  199. Object.entries(logging).map(([name, value]) => ({ ...value, name })),
  200. context
  201. ),
  202. "compilation.warningsInChildren!": (_, { yellow, compilation }) => {
  203. if (
  204. !compilation.children &&
  205. compilation.warningsCount > 0 &&
  206. compilation.warnings
  207. ) {
  208. const childWarnings =
  209. compilation.warningsCount - compilation.warnings.length;
  210. if (childWarnings > 0) {
  211. return yellow(
  212. `${childWarnings} ${plural(
  213. childWarnings,
  214. "WARNING",
  215. "WARNINGS"
  216. )} in child compilations${
  217. compilation.children
  218. ? ""
  219. : " (Use 'stats.children: true' resp. '--stats-children' for more details)"
  220. }`
  221. );
  222. }
  223. }
  224. },
  225. "compilation.errorsInChildren!": (_, { red, compilation }) => {
  226. if (
  227. !compilation.children &&
  228. compilation.errorsCount > 0 &&
  229. compilation.errors
  230. ) {
  231. const childErrors = compilation.errorsCount - compilation.errors.length;
  232. if (childErrors > 0) {
  233. return red(
  234. `${childErrors} ${plural(
  235. childErrors,
  236. "ERROR",
  237. "ERRORS"
  238. )} in child compilations${
  239. compilation.children
  240. ? ""
  241. : " (Use 'stats.children: true' resp. '--stats-children' for more details)"
  242. }`
  243. );
  244. }
  245. }
  246. },
  247. "asset.type": type => type,
  248. "asset.name": (name, { formatFilename, asset: { isOverSizeLimit } }) =>
  249. formatFilename(name, isOverSizeLimit),
  250. "asset.size": (
  251. size,
  252. { asset: { isOverSizeLimit }, yellow, green, formatSize }
  253. ) => (isOverSizeLimit ? yellow(formatSize(size)) : formatSize(size)),
  254. "asset.emitted": (emitted, { green, formatFlag }) =>
  255. emitted ? green(formatFlag("emitted")) : undefined,
  256. "asset.comparedForEmit": (comparedForEmit, { yellow, formatFlag }) =>
  257. comparedForEmit ? yellow(formatFlag("compared for emit")) : undefined,
  258. "asset.cached": (cached, { green, formatFlag }) =>
  259. cached ? green(formatFlag("cached")) : undefined,
  260. "asset.isOverSizeLimit": (isOverSizeLimit, { yellow, formatFlag }) =>
  261. isOverSizeLimit ? yellow(formatFlag("big")) : undefined,
  262. "asset.info.immutable": (immutable, { green, formatFlag }) =>
  263. immutable ? green(formatFlag("immutable")) : undefined,
  264. "asset.info.javascriptModule": (javascriptModule, { formatFlag }) =>
  265. javascriptModule ? formatFlag("javascript module") : undefined,
  266. "asset.info.sourceFilename": (sourceFilename, { formatFlag }) =>
  267. sourceFilename
  268. ? formatFlag(
  269. sourceFilename === true
  270. ? "from source file"
  271. : `from: ${sourceFilename}`
  272. )
  273. : undefined,
  274. "asset.info.development": (development, { green, formatFlag }) =>
  275. development ? green(formatFlag("dev")) : undefined,
  276. "asset.info.hotModuleReplacement": (
  277. hotModuleReplacement,
  278. { green, formatFlag }
  279. ) => (hotModuleReplacement ? green(formatFlag("hmr")) : undefined),
  280. "asset.separator!": () => "\n",
  281. "asset.filteredRelated": (filteredRelated, { asset: { related } }) =>
  282. filteredRelated > 0
  283. ? `${moreCount(related, filteredRelated)} related ${plural(
  284. filteredRelated,
  285. "asset",
  286. "assets"
  287. )}`
  288. : undefined,
  289. "asset.filteredChildren": (filteredChildren, { asset: { children } }) =>
  290. filteredChildren > 0
  291. ? `${moreCount(children, filteredChildren)} ${plural(
  292. filteredChildren,
  293. "asset",
  294. "assets"
  295. )}`
  296. : undefined,
  297. assetChunk: (id, { formatChunkId }) => formatChunkId(id),
  298. assetChunkName: name => name,
  299. assetChunkIdHint: name => name,
  300. "module.type": type => (type !== "module" ? type : undefined),
  301. "module.id": (id, { formatModuleId }) =>
  302. isValidId(id) ? formatModuleId(id) : undefined,
  303. "module.name": (name, { bold }) => {
  304. const [prefix, resource] = getModuleName(name);
  305. return `${prefix || ""}${bold(resource || "")}`;
  306. },
  307. "module.identifier": identifier => undefined,
  308. "module.layer": (layer, { formatLayer }) =>
  309. layer ? formatLayer(layer) : undefined,
  310. "module.sizes": printSizes,
  311. "module.chunks[]": (id, { formatChunkId }) => formatChunkId(id),
  312. "module.depth": (depth, { formatFlag }) =>
  313. depth !== null ? formatFlag(`depth ${depth}`) : undefined,
  314. "module.cacheable": (cacheable, { formatFlag, red }) =>
  315. cacheable === false ? red(formatFlag("not cacheable")) : undefined,
  316. "module.orphan": (orphan, { formatFlag, yellow }) =>
  317. orphan ? yellow(formatFlag("orphan")) : undefined,
  318. "module.runtime": (runtime, { formatFlag, yellow }) =>
  319. runtime ? yellow(formatFlag("runtime")) : undefined,
  320. "module.optional": (optional, { formatFlag, yellow }) =>
  321. optional ? yellow(formatFlag("optional")) : undefined,
  322. "module.dependent": (dependent, { formatFlag, cyan }) =>
  323. dependent ? cyan(formatFlag("dependent")) : undefined,
  324. "module.built": (built, { formatFlag, yellow }) =>
  325. built ? yellow(formatFlag("built")) : undefined,
  326. "module.codeGenerated": (codeGenerated, { formatFlag, yellow }) =>
  327. codeGenerated ? yellow(formatFlag("code generated")) : undefined,
  328. "module.buildTimeExecuted": (buildTimeExecuted, { formatFlag, green }) =>
  329. buildTimeExecuted ? green(formatFlag("build time executed")) : undefined,
  330. "module.cached": (cached, { formatFlag, green }) =>
  331. cached ? green(formatFlag("cached")) : undefined,
  332. "module.assets": (assets, { formatFlag, magenta }) =>
  333. assets && assets.length
  334. ? magenta(
  335. formatFlag(
  336. `${assets.length} ${plural(assets.length, "asset", "assets")}`
  337. )
  338. )
  339. : undefined,
  340. "module.warnings": (warnings, { formatFlag, yellow }) =>
  341. warnings === true
  342. ? yellow(formatFlag("warnings"))
  343. : warnings
  344. ? yellow(
  345. formatFlag(`${warnings} ${plural(warnings, "warning", "warnings")}`)
  346. )
  347. : undefined,
  348. "module.errors": (errors, { formatFlag, red }) =>
  349. errors === true
  350. ? red(formatFlag("errors"))
  351. : errors
  352. ? red(formatFlag(`${errors} ${plural(errors, "error", "errors")}`))
  353. : undefined,
  354. "module.providedExports": (providedExports, { formatFlag, cyan }) => {
  355. if (Array.isArray(providedExports)) {
  356. if (providedExports.length === 0) return cyan(formatFlag("no exports"));
  357. return cyan(formatFlag(`exports: ${providedExports.join(", ")}`));
  358. }
  359. },
  360. "module.usedExports": (usedExports, { formatFlag, cyan, module }) => {
  361. if (usedExports !== true) {
  362. if (usedExports === null) return cyan(formatFlag("used exports unknown"));
  363. if (usedExports === false) return cyan(formatFlag("module unused"));
  364. if (Array.isArray(usedExports)) {
  365. if (usedExports.length === 0)
  366. return cyan(formatFlag("no exports used"));
  367. const providedExportsCount = Array.isArray(module.providedExports)
  368. ? module.providedExports.length
  369. : null;
  370. if (
  371. providedExportsCount !== null &&
  372. providedExportsCount === usedExports.length
  373. ) {
  374. return cyan(formatFlag("all exports used"));
  375. } else {
  376. return cyan(
  377. formatFlag(`only some exports used: ${usedExports.join(", ")}`)
  378. );
  379. }
  380. }
  381. }
  382. },
  383. "module.optimizationBailout[]": (optimizationBailout, { yellow }) =>
  384. yellow(optimizationBailout),
  385. "module.issuerPath": (issuerPath, { module }) =>
  386. module.profile ? undefined : "",
  387. "module.profile": profile => undefined,
  388. "module.filteredModules": (filteredModules, { module: { modules } }) =>
  389. filteredModules > 0
  390. ? `${moreCount(modules, filteredModules)} nested ${plural(
  391. filteredModules,
  392. "module",
  393. "modules"
  394. )}`
  395. : undefined,
  396. "module.filteredReasons": (filteredReasons, { module: { reasons } }) =>
  397. filteredReasons > 0
  398. ? `${moreCount(reasons, filteredReasons)} ${plural(
  399. filteredReasons,
  400. "reason",
  401. "reasons"
  402. )}`
  403. : undefined,
  404. "module.filteredChildren": (filteredChildren, { module: { children } }) =>
  405. filteredChildren > 0
  406. ? `${moreCount(children, filteredChildren)} ${plural(
  407. filteredChildren,
  408. "module",
  409. "modules"
  410. )}`
  411. : undefined,
  412. "module.separator!": () => "\n",
  413. "moduleIssuer.id": (id, { formatModuleId }) => formatModuleId(id),
  414. "moduleIssuer.profile.total": (value, { formatTime }) => formatTime(value),
  415. "moduleReason.type": type => type,
  416. "moduleReason.userRequest": (userRequest, { cyan }) =>
  417. cyan(getResourceName(userRequest)),
  418. "moduleReason.moduleId": (moduleId, { formatModuleId }) =>
  419. isValidId(moduleId) ? formatModuleId(moduleId) : undefined,
  420. "moduleReason.module": (module, { magenta }) => magenta(module),
  421. "moduleReason.loc": loc => loc,
  422. "moduleReason.explanation": (explanation, { cyan }) => cyan(explanation),
  423. "moduleReason.active": (active, { formatFlag }) =>
  424. active ? undefined : formatFlag("inactive"),
  425. "moduleReason.resolvedModule": (module, { magenta }) => magenta(module),
  426. "moduleReason.filteredChildren": (
  427. filteredChildren,
  428. { moduleReason: { children } }
  429. ) =>
  430. filteredChildren > 0
  431. ? `${moreCount(children, filteredChildren)} ${plural(
  432. filteredChildren,
  433. "reason",
  434. "reasons"
  435. )}`
  436. : undefined,
  437. "module.profile.total": (value, { formatTime }) => formatTime(value),
  438. "module.profile.resolving": (value, { formatTime }) =>
  439. `resolving: ${formatTime(value)}`,
  440. "module.profile.restoring": (value, { formatTime }) =>
  441. `restoring: ${formatTime(value)}`,
  442. "module.profile.integration": (value, { formatTime }) =>
  443. `integration: ${formatTime(value)}`,
  444. "module.profile.building": (value, { formatTime }) =>
  445. `building: ${formatTime(value)}`,
  446. "module.profile.storing": (value, { formatTime }) =>
  447. `storing: ${formatTime(value)}`,
  448. "module.profile.additionalResolving": (value, { formatTime }) =>
  449. value ? `additional resolving: ${formatTime(value)}` : undefined,
  450. "module.profile.additionalIntegration": (value, { formatTime }) =>
  451. value ? `additional integration: ${formatTime(value)}` : undefined,
  452. "chunkGroup.kind!": (_, { chunkGroupKind }) => chunkGroupKind,
  453. "chunkGroup.separator!": () => "\n",
  454. "chunkGroup.name": (name, { bold }) => bold(name),
  455. "chunkGroup.isOverSizeLimit": (isOverSizeLimit, { formatFlag, yellow }) =>
  456. isOverSizeLimit ? yellow(formatFlag("big")) : undefined,
  457. "chunkGroup.assetsSize": (size, { formatSize }) =>
  458. size ? formatSize(size) : undefined,
  459. "chunkGroup.auxiliaryAssetsSize": (size, { formatSize }) =>
  460. size ? `(${formatSize(size)})` : undefined,
  461. "chunkGroup.filteredAssets": (n, { chunkGroup: { assets } }) =>
  462. n > 0
  463. ? `${moreCount(assets, n)} ${plural(n, "asset", "assets")}`
  464. : undefined,
  465. "chunkGroup.filteredAuxiliaryAssets": (
  466. n,
  467. { chunkGroup: { auxiliaryAssets } }
  468. ) =>
  469. n > 0
  470. ? `${moreCount(auxiliaryAssets, n)} auxiliary ${plural(
  471. n,
  472. "asset",
  473. "assets"
  474. )}`
  475. : undefined,
  476. "chunkGroup.is!": () => "=",
  477. "chunkGroupAsset.name": (asset, { green }) => green(asset),
  478. "chunkGroupAsset.size": (size, { formatSize, chunkGroup }) =>
  479. chunkGroup.assets.length > 1 ||
  480. (chunkGroup.auxiliaryAssets && chunkGroup.auxiliaryAssets.length > 0)
  481. ? formatSize(size)
  482. : undefined,
  483. "chunkGroup.children": (children, context, printer) =>
  484. Array.isArray(children)
  485. ? undefined
  486. : printer.print(
  487. context.type,
  488. Object.keys(children).map(key => ({
  489. type: key,
  490. children: children[key]
  491. })),
  492. context
  493. ),
  494. "chunkGroupChildGroup.type": type => `${type}:`,
  495. "chunkGroupChild.assets[]": (file, { formatFilename }) =>
  496. formatFilename(file),
  497. "chunkGroupChild.chunks[]": (id, { formatChunkId }) => formatChunkId(id),
  498. "chunkGroupChild.name": name => (name ? `(name: ${name})` : undefined),
  499. "chunk.id": (id, { formatChunkId }) => formatChunkId(id),
  500. "chunk.files[]": (file, { formatFilename }) => formatFilename(file),
  501. "chunk.names[]": name => name,
  502. "chunk.idHints[]": name => name,
  503. "chunk.runtime[]": name => name,
  504. "chunk.sizes": (sizes, context) => printSizes(sizes, context),
  505. "chunk.parents[]": (parents, context) =>
  506. context.formatChunkId(parents, "parent"),
  507. "chunk.siblings[]": (siblings, context) =>
  508. context.formatChunkId(siblings, "sibling"),
  509. "chunk.children[]": (children, context) =>
  510. context.formatChunkId(children, "child"),
  511. "chunk.childrenByOrder": (childrenByOrder, context, printer) =>
  512. Array.isArray(childrenByOrder)
  513. ? undefined
  514. : printer.print(
  515. context.type,
  516. Object.keys(childrenByOrder).map(key => ({
  517. type: key,
  518. children: childrenByOrder[key]
  519. })),
  520. context
  521. ),
  522. "chunk.childrenByOrder[].type": type => `${type}:`,
  523. "chunk.childrenByOrder[].children[]": (id, { formatChunkId }) =>
  524. isValidId(id) ? formatChunkId(id) : undefined,
  525. "chunk.entry": (entry, { formatFlag, yellow }) =>
  526. entry ? yellow(formatFlag("entry")) : undefined,
  527. "chunk.initial": (initial, { formatFlag, yellow }) =>
  528. initial ? yellow(formatFlag("initial")) : undefined,
  529. "chunk.rendered": (rendered, { formatFlag, green }) =>
  530. rendered ? green(formatFlag("rendered")) : undefined,
  531. "chunk.recorded": (recorded, { formatFlag, green }) =>
  532. recorded ? green(formatFlag("recorded")) : undefined,
  533. "chunk.reason": (reason, { yellow }) => (reason ? yellow(reason) : undefined),
  534. "chunk.filteredModules": (filteredModules, { chunk: { modules } }) =>
  535. filteredModules > 0
  536. ? `${moreCount(modules, filteredModules)} chunk ${plural(
  537. filteredModules,
  538. "module",
  539. "modules"
  540. )}`
  541. : undefined,
  542. "chunk.separator!": () => "\n",
  543. "chunkOrigin.request": request => request,
  544. "chunkOrigin.moduleId": (moduleId, { formatModuleId }) =>
  545. isValidId(moduleId) ? formatModuleId(moduleId) : undefined,
  546. "chunkOrigin.moduleName": (moduleName, { bold }) => bold(moduleName),
  547. "chunkOrigin.loc": loc => loc,
  548. "error.compilerPath": (compilerPath, { bold }) =>
  549. compilerPath ? bold(`(${compilerPath})`) : undefined,
  550. "error.chunkId": (chunkId, { formatChunkId }) =>
  551. isValidId(chunkId) ? formatChunkId(chunkId) : undefined,
  552. "error.chunkEntry": (chunkEntry, { formatFlag }) =>
  553. chunkEntry ? formatFlag("entry") : undefined,
  554. "error.chunkInitial": (chunkInitial, { formatFlag }) =>
  555. chunkInitial ? formatFlag("initial") : undefined,
  556. "error.file": (file, { bold }) => bold(file),
  557. "error.moduleName": (moduleName, { bold }) => {
  558. return moduleName.includes("!")
  559. ? `${bold(moduleName.replace(/^(\s|\S)*!/, ""))} (${moduleName})`
  560. : `${bold(moduleName)}`;
  561. },
  562. "error.loc": (loc, { green }) => green(loc),
  563. "error.message": (message, { bold, formatError }) =>
  564. message.includes("\u001b[") ? message : bold(formatError(message)),
  565. "error.details": (details, { formatError }) => formatError(details),
  566. "error.stack": stack => stack,
  567. "error.moduleTrace": moduleTrace => undefined,
  568. "error.separator!": () => "\n",
  569. "loggingEntry(error).loggingEntry.message": (message, { red }) =>
  570. mapLines(message, x => `<e> ${red(x)}`),
  571. "loggingEntry(warn).loggingEntry.message": (message, { yellow }) =>
  572. mapLines(message, x => `<w> ${yellow(x)}`),
  573. "loggingEntry(info).loggingEntry.message": (message, { green }) =>
  574. mapLines(message, x => `<i> ${green(x)}`),
  575. "loggingEntry(log).loggingEntry.message": (message, { bold }) =>
  576. mapLines(message, x => ` ${bold(x)}`),
  577. "loggingEntry(debug).loggingEntry.message": message =>
  578. mapLines(message, x => ` ${x}`),
  579. "loggingEntry(trace).loggingEntry.message": message =>
  580. mapLines(message, x => ` ${x}`),
  581. "loggingEntry(status).loggingEntry.message": (message, { magenta }) =>
  582. mapLines(message, x => `<s> ${magenta(x)}`),
  583. "loggingEntry(profile).loggingEntry.message": (message, { magenta }) =>
  584. mapLines(message, x => `<p> ${magenta(x)}`),
  585. "loggingEntry(profileEnd).loggingEntry.message": (message, { magenta }) =>
  586. mapLines(message, x => `</p> ${magenta(x)}`),
  587. "loggingEntry(time).loggingEntry.message": (message, { magenta }) =>
  588. mapLines(message, x => `<t> ${magenta(x)}`),
  589. "loggingEntry(group).loggingEntry.message": (message, { cyan }) =>
  590. mapLines(message, x => `<-> ${cyan(x)}`),
  591. "loggingEntry(groupCollapsed).loggingEntry.message": (message, { cyan }) =>
  592. mapLines(message, x => `<+> ${cyan(x)}`),
  593. "loggingEntry(clear).loggingEntry": () => " -------",
  594. "loggingEntry(groupCollapsed).loggingEntry.children": () => "",
  595. "loggingEntry.trace[]": trace =>
  596. trace ? mapLines(trace, x => `| ${x}`) : undefined,
  597. "moduleTraceItem.originName": originName => originName,
  598. loggingGroup: loggingGroup =>
  599. loggingGroup.entries.length === 0 ? "" : undefined,
  600. "loggingGroup.debug": (flag, { red }) => (flag ? red("DEBUG") : undefined),
  601. "loggingGroup.name": (name, { bold }) => bold(`LOG from ${name}`),
  602. "loggingGroup.separator!": () => "\n",
  603. "loggingGroup.filteredEntries": filteredEntries =>
  604. filteredEntries > 0 ? `+ ${filteredEntries} hidden lines` : undefined,
  605. "moduleTraceDependency.loc": loc => loc
  606. };
  607. /** @type {Record<string, string | Function>} */
  608. const ITEM_NAMES = {
  609. "compilation.assets[]": "asset",
  610. "compilation.modules[]": "module",
  611. "compilation.chunks[]": "chunk",
  612. "compilation.entrypoints[]": "chunkGroup",
  613. "compilation.namedChunkGroups[]": "chunkGroup",
  614. "compilation.errors[]": "error",
  615. "compilation.warnings[]": "error",
  616. "compilation.logging[]": "loggingGroup",
  617. "compilation.children[]": "compilation",
  618. "asset.related[]": "asset",
  619. "asset.children[]": "asset",
  620. "asset.chunks[]": "assetChunk",
  621. "asset.auxiliaryChunks[]": "assetChunk",
  622. "asset.chunkNames[]": "assetChunkName",
  623. "asset.chunkIdHints[]": "assetChunkIdHint",
  624. "asset.auxiliaryChunkNames[]": "assetChunkName",
  625. "asset.auxiliaryChunkIdHints[]": "assetChunkIdHint",
  626. "chunkGroup.assets[]": "chunkGroupAsset",
  627. "chunkGroup.auxiliaryAssets[]": "chunkGroupAsset",
  628. "chunkGroupChild.assets[]": "chunkGroupAsset",
  629. "chunkGroupChild.auxiliaryAssets[]": "chunkGroupAsset",
  630. "chunkGroup.children[]": "chunkGroupChildGroup",
  631. "chunkGroupChildGroup.children[]": "chunkGroupChild",
  632. "module.modules[]": "module",
  633. "module.children[]": "module",
  634. "module.reasons[]": "moduleReason",
  635. "moduleReason.children[]": "moduleReason",
  636. "module.issuerPath[]": "moduleIssuer",
  637. "chunk.origins[]": "chunkOrigin",
  638. "chunk.modules[]": "module",
  639. "loggingGroup.entries[]": logEntry =>
  640. `loggingEntry(${logEntry.type}).loggingEntry`,
  641. "loggingEntry.children[]": logEntry =>
  642. `loggingEntry(${logEntry.type}).loggingEntry`,
  643. "error.moduleTrace[]": "moduleTraceItem",
  644. "moduleTraceItem.dependencies[]": "moduleTraceDependency"
  645. };
  646. const ERROR_PREFERRED_ORDER = [
  647. "compilerPath",
  648. "chunkId",
  649. "chunkEntry",
  650. "chunkInitial",
  651. "file",
  652. "separator!",
  653. "moduleName",
  654. "loc",
  655. "separator!",
  656. "message",
  657. "separator!",
  658. "details",
  659. "separator!",
  660. "stack",
  661. "separator!",
  662. "missing",
  663. "separator!",
  664. "moduleTrace"
  665. ];
  666. /** @type {Record<string, string[]>} */
  667. const PREFERRED_ORDERS = {
  668. compilation: [
  669. "name",
  670. "hash",
  671. "version",
  672. "time",
  673. "builtAt",
  674. "env",
  675. "publicPath",
  676. "assets",
  677. "filteredAssets",
  678. "entrypoints",
  679. "namedChunkGroups",
  680. "chunks",
  681. "modules",
  682. "filteredModules",
  683. "children",
  684. "logging",
  685. "warnings",
  686. "warningsInChildren!",
  687. "filteredWarningDetailsCount",
  688. "errors",
  689. "errorsInChildren!",
  690. "filteredErrorDetailsCount",
  691. "summary!",
  692. "needAdditionalPass"
  693. ],
  694. asset: [
  695. "type",
  696. "name",
  697. "size",
  698. "chunks",
  699. "auxiliaryChunks",
  700. "emitted",
  701. "comparedForEmit",
  702. "cached",
  703. "info",
  704. "isOverSizeLimit",
  705. "chunkNames",
  706. "auxiliaryChunkNames",
  707. "chunkIdHints",
  708. "auxiliaryChunkIdHints",
  709. "related",
  710. "filteredRelated",
  711. "children",
  712. "filteredChildren"
  713. ],
  714. "asset.info": [
  715. "immutable",
  716. "sourceFilename",
  717. "javascriptModule",
  718. "development",
  719. "hotModuleReplacement"
  720. ],
  721. chunkGroup: [
  722. "kind!",
  723. "name",
  724. "isOverSizeLimit",
  725. "assetsSize",
  726. "auxiliaryAssetsSize",
  727. "is!",
  728. "assets",
  729. "filteredAssets",
  730. "auxiliaryAssets",
  731. "filteredAuxiliaryAssets",
  732. "separator!",
  733. "children"
  734. ],
  735. chunkGroupAsset: ["name", "size"],
  736. chunkGroupChildGroup: ["type", "children"],
  737. chunkGroupChild: ["assets", "chunks", "name"],
  738. module: [
  739. "type",
  740. "name",
  741. "identifier",
  742. "id",
  743. "layer",
  744. "sizes",
  745. "chunks",
  746. "depth",
  747. "cacheable",
  748. "orphan",
  749. "runtime",
  750. "optional",
  751. "dependent",
  752. "built",
  753. "codeGenerated",
  754. "cached",
  755. "assets",
  756. "failed",
  757. "warnings",
  758. "errors",
  759. "children",
  760. "filteredChildren",
  761. "providedExports",
  762. "usedExports",
  763. "optimizationBailout",
  764. "reasons",
  765. "filteredReasons",
  766. "issuerPath",
  767. "profile",
  768. "modules",
  769. "filteredModules"
  770. ],
  771. moduleReason: [
  772. "active",
  773. "type",
  774. "userRequest",
  775. "moduleId",
  776. "module",
  777. "resolvedModule",
  778. "loc",
  779. "explanation",
  780. "children",
  781. "filteredChildren"
  782. ],
  783. "module.profile": [
  784. "total",
  785. "separator!",
  786. "resolving",
  787. "restoring",
  788. "integration",
  789. "building",
  790. "storing",
  791. "additionalResolving",
  792. "additionalIntegration"
  793. ],
  794. chunk: [
  795. "id",
  796. "runtime",
  797. "files",
  798. "names",
  799. "idHints",
  800. "sizes",
  801. "parents",
  802. "siblings",
  803. "children",
  804. "childrenByOrder",
  805. "entry",
  806. "initial",
  807. "rendered",
  808. "recorded",
  809. "reason",
  810. "separator!",
  811. "origins",
  812. "separator!",
  813. "modules",
  814. "separator!",
  815. "filteredModules"
  816. ],
  817. chunkOrigin: ["request", "moduleId", "moduleName", "loc"],
  818. error: ERROR_PREFERRED_ORDER,
  819. warning: ERROR_PREFERRED_ORDER,
  820. "chunk.childrenByOrder[]": ["type", "children"],
  821. loggingGroup: [
  822. "debug",
  823. "name",
  824. "separator!",
  825. "entries",
  826. "separator!",
  827. "filteredEntries"
  828. ],
  829. loggingEntry: ["message", "trace", "children"]
  830. };
  831. const itemsJoinOneLine = items => items.filter(Boolean).join(" ");
  832. const itemsJoinOneLineBrackets = items =>
  833. items.length > 0 ? `(${items.filter(Boolean).join(" ")})` : undefined;
  834. const itemsJoinMoreSpacing = items => items.filter(Boolean).join("\n\n");
  835. const itemsJoinComma = items => items.filter(Boolean).join(", ");
  836. const itemsJoinCommaBrackets = items =>
  837. items.length > 0 ? `(${items.filter(Boolean).join(", ")})` : undefined;
  838. const itemsJoinCommaBracketsWithName = name => items =>
  839. items.length > 0
  840. ? `(${name}: ${items.filter(Boolean).join(", ")})`
  841. : undefined;
  842. /** @type {Record<string, (items: string[]) => string>} */
  843. const SIMPLE_ITEMS_JOINER = {
  844. "chunk.parents": itemsJoinOneLine,
  845. "chunk.siblings": itemsJoinOneLine,
  846. "chunk.children": itemsJoinOneLine,
  847. "chunk.names": itemsJoinCommaBrackets,
  848. "chunk.idHints": itemsJoinCommaBracketsWithName("id hint"),
  849. "chunk.runtime": itemsJoinCommaBracketsWithName("runtime"),
  850. "chunk.files": itemsJoinComma,
  851. "chunk.childrenByOrder": itemsJoinOneLine,
  852. "chunk.childrenByOrder[].children": itemsJoinOneLine,
  853. "chunkGroup.assets": itemsJoinOneLine,
  854. "chunkGroup.auxiliaryAssets": itemsJoinOneLineBrackets,
  855. "chunkGroupChildGroup.children": itemsJoinComma,
  856. "chunkGroupChild.assets": itemsJoinOneLine,
  857. "chunkGroupChild.auxiliaryAssets": itemsJoinOneLineBrackets,
  858. "asset.chunks": itemsJoinComma,
  859. "asset.auxiliaryChunks": itemsJoinCommaBrackets,
  860. "asset.chunkNames": itemsJoinCommaBracketsWithName("name"),
  861. "asset.auxiliaryChunkNames": itemsJoinCommaBracketsWithName("auxiliary name"),
  862. "asset.chunkIdHints": itemsJoinCommaBracketsWithName("id hint"),
  863. "asset.auxiliaryChunkIdHints":
  864. itemsJoinCommaBracketsWithName("auxiliary id hint"),
  865. "module.chunks": itemsJoinOneLine,
  866. "module.issuerPath": items =>
  867. items
  868. .filter(Boolean)
  869. .map(item => `${item} ->`)
  870. .join(" "),
  871. "compilation.errors": itemsJoinMoreSpacing,
  872. "compilation.warnings": itemsJoinMoreSpacing,
  873. "compilation.logging": itemsJoinMoreSpacing,
  874. "compilation.children": items => indent(itemsJoinMoreSpacing(items), " "),
  875. "moduleTraceItem.dependencies": itemsJoinOneLine,
  876. "loggingEntry.children": items =>
  877. indent(items.filter(Boolean).join("\n"), " ", false)
  878. };
  879. const joinOneLine = items =>
  880. items
  881. .map(item => item.content)
  882. .filter(Boolean)
  883. .join(" ");
  884. const joinInBrackets = items => {
  885. const res = [];
  886. let mode = 0;
  887. for (const item of items) {
  888. if (item.element === "separator!") {
  889. switch (mode) {
  890. case 0:
  891. case 1:
  892. mode += 2;
  893. break;
  894. case 4:
  895. res.push(")");
  896. mode = 3;
  897. break;
  898. }
  899. }
  900. if (!item.content) continue;
  901. switch (mode) {
  902. case 0:
  903. mode = 1;
  904. break;
  905. case 1:
  906. res.push(" ");
  907. break;
  908. case 2:
  909. res.push("(");
  910. mode = 4;
  911. break;
  912. case 3:
  913. res.push(" (");
  914. mode = 4;
  915. break;
  916. case 4:
  917. res.push(", ");
  918. break;
  919. }
  920. res.push(item.content);
  921. }
  922. if (mode === 4) res.push(")");
  923. return res.join("");
  924. };
  925. const indent = (str, prefix, noPrefixInFirstLine) => {
  926. const rem = str.replace(/\n([^\n])/g, "\n" + prefix + "$1");
  927. if (noPrefixInFirstLine) return rem;
  928. const ind = str[0] === "\n" ? "" : prefix;
  929. return ind + rem;
  930. };
  931. const joinExplicitNewLine = (items, indenter) => {
  932. let firstInLine = true;
  933. let first = true;
  934. return items
  935. .map(item => {
  936. if (!item || !item.content) return;
  937. let content = indent(item.content, first ? "" : indenter, !firstInLine);
  938. if (firstInLine) {
  939. content = content.replace(/^\n+/, "");
  940. }
  941. if (!content) return;
  942. first = false;
  943. const noJoiner = firstInLine || content.startsWith("\n");
  944. firstInLine = content.endsWith("\n");
  945. return noJoiner ? content : " " + content;
  946. })
  947. .filter(Boolean)
  948. .join("")
  949. .trim();
  950. };
  951. const joinError =
  952. error =>
  953. (items, { red, yellow }) =>
  954. `${error ? red("ERROR") : yellow("WARNING")} in ${joinExplicitNewLine(
  955. items,
  956. ""
  957. )}`;
  958. /** @type {Record<string, (items: ({ element: string, content: string })[], context: StatsPrinterContext) => string>} */
  959. const SIMPLE_ELEMENT_JOINERS = {
  960. compilation: items => {
  961. const result = [];
  962. let lastNeedMore = false;
  963. for (const item of items) {
  964. if (!item.content) continue;
  965. const needMoreSpace =
  966. item.element === "warnings" ||
  967. item.element === "filteredWarningDetailsCount" ||
  968. item.element === "errors" ||
  969. item.element === "filteredErrorDetailsCount" ||
  970. item.element === "logging";
  971. if (result.length !== 0) {
  972. result.push(needMoreSpace || lastNeedMore ? "\n\n" : "\n");
  973. }
  974. result.push(item.content);
  975. lastNeedMore = needMoreSpace;
  976. }
  977. if (lastNeedMore) result.push("\n");
  978. return result.join("");
  979. },
  980. asset: items =>
  981. joinExplicitNewLine(
  982. items.map(item => {
  983. if (
  984. (item.element === "related" || item.element === "children") &&
  985. item.content
  986. ) {
  987. return {
  988. ...item,
  989. content: `\n${item.content}\n`
  990. };
  991. }
  992. return item;
  993. }),
  994. " "
  995. ),
  996. "asset.info": joinOneLine,
  997. module: (items, { module }) => {
  998. let hasName = false;
  999. return joinExplicitNewLine(
  1000. items.map(item => {
  1001. switch (item.element) {
  1002. case "id":
  1003. if (module.id === module.name) {
  1004. if (hasName) return false;
  1005. if (item.content) hasName = true;
  1006. }
  1007. break;
  1008. case "name":
  1009. if (hasName) return false;
  1010. if (item.content) hasName = true;
  1011. break;
  1012. case "providedExports":
  1013. case "usedExports":
  1014. case "optimizationBailout":
  1015. case "reasons":
  1016. case "issuerPath":
  1017. case "profile":
  1018. case "children":
  1019. case "modules":
  1020. if (item.content) {
  1021. return {
  1022. ...item,
  1023. content: `\n${item.content}\n`
  1024. };
  1025. }
  1026. break;
  1027. }
  1028. return item;
  1029. }),
  1030. " "
  1031. );
  1032. },
  1033. chunk: items => {
  1034. let hasEntry = false;
  1035. return (
  1036. "chunk " +
  1037. joinExplicitNewLine(
  1038. items.filter(item => {
  1039. switch (item.element) {
  1040. case "entry":
  1041. if (item.content) hasEntry = true;
  1042. break;
  1043. case "initial":
  1044. if (hasEntry) return false;
  1045. break;
  1046. }
  1047. return true;
  1048. }),
  1049. " "
  1050. )
  1051. );
  1052. },
  1053. "chunk.childrenByOrder[]": items => `(${joinOneLine(items)})`,
  1054. chunkGroup: items => joinExplicitNewLine(items, " "),
  1055. chunkGroupAsset: joinOneLine,
  1056. chunkGroupChildGroup: joinOneLine,
  1057. chunkGroupChild: joinOneLine,
  1058. // moduleReason: (items, { moduleReason }) => {
  1059. // let hasName = false;
  1060. // return joinOneLine(
  1061. // items.filter(item => {
  1062. // switch (item.element) {
  1063. // case "moduleId":
  1064. // if (moduleReason.moduleId === moduleReason.module && item.content)
  1065. // hasName = true;
  1066. // break;
  1067. // case "module":
  1068. // if (hasName) return false;
  1069. // break;
  1070. // case "resolvedModule":
  1071. // return (
  1072. // moduleReason.module !== moduleReason.resolvedModule &&
  1073. // item.content
  1074. // );
  1075. // }
  1076. // return true;
  1077. // })
  1078. // );
  1079. // },
  1080. moduleReason: (items, { moduleReason }) => {
  1081. let hasName = false;
  1082. return joinExplicitNewLine(
  1083. items.map(item => {
  1084. switch (item.element) {
  1085. case "moduleId":
  1086. if (moduleReason.moduleId === moduleReason.module && item.content)
  1087. hasName = true;
  1088. break;
  1089. case "module":
  1090. if (hasName) return false;
  1091. break;
  1092. case "resolvedModule":
  1093. if (moduleReason.module === moduleReason.resolvedModule)
  1094. return false;
  1095. break;
  1096. case "children":
  1097. if (item.content) {
  1098. return {
  1099. ...item,
  1100. content: `\n${item.content}\n`
  1101. };
  1102. }
  1103. break;
  1104. }
  1105. return item;
  1106. }),
  1107. " "
  1108. );
  1109. },
  1110. "module.profile": joinInBrackets,
  1111. moduleIssuer: joinOneLine,
  1112. chunkOrigin: items => "> " + joinOneLine(items),
  1113. "errors[].error": joinError(true),
  1114. "warnings[].error": joinError(false),
  1115. loggingGroup: items => joinExplicitNewLine(items, "").trimEnd(),
  1116. moduleTraceItem: items => " @ " + joinOneLine(items),
  1117. moduleTraceDependency: joinOneLine
  1118. };
  1119. const AVAILABLE_COLORS = {
  1120. bold: "\u001b[1m",
  1121. yellow: "\u001b[1m\u001b[33m",
  1122. red: "\u001b[1m\u001b[31m",
  1123. green: "\u001b[1m\u001b[32m",
  1124. cyan: "\u001b[1m\u001b[36m",
  1125. magenta: "\u001b[1m\u001b[35m"
  1126. };
  1127. const AVAILABLE_FORMATS = {
  1128. formatChunkId: (id, { yellow }, direction) => {
  1129. switch (direction) {
  1130. case "parent":
  1131. return `<{${yellow(id)}}>`;
  1132. case "sibling":
  1133. return `={${yellow(id)}}=`;
  1134. case "child":
  1135. return `>{${yellow(id)}}<`;
  1136. default:
  1137. return `{${yellow(id)}}`;
  1138. }
  1139. },
  1140. formatModuleId: id => `[${id}]`,
  1141. formatFilename: (filename, { green, yellow }, oversize) =>
  1142. (oversize ? yellow : green)(filename),
  1143. formatFlag: flag => `[${flag}]`,
  1144. formatLayer: layer => `(in ${layer})`,
  1145. formatSize: require("../SizeFormatHelpers").formatSize,
  1146. formatDateTime: (dateTime, { bold }) => {
  1147. const d = new Date(dateTime);
  1148. const x = twoDigit;
  1149. const date = `${d.getFullYear()}-${x(d.getMonth() + 1)}-${x(d.getDate())}`;
  1150. const time = `${x(d.getHours())}:${x(d.getMinutes())}:${x(d.getSeconds())}`;
  1151. return `${date} ${bold(time)}`;
  1152. },
  1153. formatTime: (
  1154. time,
  1155. { timeReference, bold, green, yellow, red },
  1156. boldQuantity
  1157. ) => {
  1158. const unit = " ms";
  1159. if (timeReference && time !== timeReference) {
  1160. const times = [
  1161. timeReference / 2,
  1162. timeReference / 4,
  1163. timeReference / 8,
  1164. timeReference / 16
  1165. ];
  1166. if (time < times[3]) return `${time}${unit}`;
  1167. else if (time < times[2]) return bold(`${time}${unit}`);
  1168. else if (time < times[1]) return green(`${time}${unit}`);
  1169. else if (time < times[0]) return yellow(`${time}${unit}`);
  1170. else return red(`${time}${unit}`);
  1171. } else {
  1172. return `${boldQuantity ? bold(time) : time}${unit}`;
  1173. }
  1174. },
  1175. formatError: (message, { green, yellow, red }) => {
  1176. if (message.includes("\u001b[")) return message;
  1177. const highlights = [
  1178. { regExp: /(Did you mean .+)/g, format: green },
  1179. {
  1180. regExp: /(Set 'mode' option to 'development' or 'production')/g,
  1181. format: green
  1182. },
  1183. { regExp: /(\(module has no exports\))/g, format: red },
  1184. { regExp: /\(possible exports: (.+)\)/g, format: green },
  1185. { regExp: /(?:^|\n)(.* doesn't exist)/g, format: red },
  1186. { regExp: /('\w+' option has not been set)/g, format: red },
  1187. {
  1188. regExp: /(Emitted value instead of an instance of Error)/g,
  1189. format: yellow
  1190. },
  1191. { regExp: /(Used? .+ instead)/gi, format: yellow },
  1192. { regExp: /\b(deprecated|must|required)\b/g, format: yellow },
  1193. {
  1194. regExp: /\b(BREAKING CHANGE)\b/gi,
  1195. format: red
  1196. },
  1197. {
  1198. regExp:
  1199. /\b(error|failed|unexpected|invalid|not found|not supported|not available|not possible|not implemented|doesn't support|conflict|conflicting|not existing|duplicate)\b/gi,
  1200. format: red
  1201. }
  1202. ];
  1203. for (const { regExp, format } of highlights) {
  1204. message = message.replace(regExp, (match, content) => {
  1205. return match.replace(content, format(content));
  1206. });
  1207. }
  1208. return message;
  1209. }
  1210. };
  1211. const RESULT_MODIFIER = {
  1212. "module.modules": result => {
  1213. return indent(result, "| ");
  1214. }
  1215. };
  1216. const createOrder = (array, preferredOrder) => {
  1217. const originalArray = array.slice();
  1218. const set = new Set(array);
  1219. const usedSet = new Set();
  1220. array.length = 0;
  1221. for (const element of preferredOrder) {
  1222. if (element.endsWith("!") || set.has(element)) {
  1223. array.push(element);
  1224. usedSet.add(element);
  1225. }
  1226. }
  1227. for (const element of originalArray) {
  1228. if (!usedSet.has(element)) {
  1229. array.push(element);
  1230. }
  1231. }
  1232. return array;
  1233. };
  1234. class DefaultStatsPrinterPlugin {
  1235. /**
  1236. * Apply the plugin
  1237. * @param {Compiler} compiler the compiler instance
  1238. * @returns {void}
  1239. */
  1240. apply(compiler) {
  1241. compiler.hooks.compilation.tap("DefaultStatsPrinterPlugin", compilation => {
  1242. compilation.hooks.statsPrinter.tap(
  1243. "DefaultStatsPrinterPlugin",
  1244. (stats, options, context) => {
  1245. // Put colors into context
  1246. stats.hooks.print
  1247. .for("compilation")
  1248. .tap("DefaultStatsPrinterPlugin", (compilation, context) => {
  1249. for (const color of Object.keys(AVAILABLE_COLORS)) {
  1250. let start;
  1251. if (options.colors) {
  1252. if (
  1253. typeof options.colors === "object" &&
  1254. typeof options.colors[color] === "string"
  1255. ) {
  1256. start = options.colors[color];
  1257. } else {
  1258. start = AVAILABLE_COLORS[color];
  1259. }
  1260. }
  1261. if (start) {
  1262. context[color] = str =>
  1263. `${start}${
  1264. typeof str === "string"
  1265. ? str.replace(
  1266. /((\u001b\[39m|\u001b\[22m|\u001b\[0m)+)/g,
  1267. `$1${start}`
  1268. )
  1269. : str
  1270. }\u001b[39m\u001b[22m`;
  1271. } else {
  1272. context[color] = str => str;
  1273. }
  1274. }
  1275. for (const format of Object.keys(AVAILABLE_FORMATS)) {
  1276. context[format] = (content, ...args) =>
  1277. AVAILABLE_FORMATS[format](content, context, ...args);
  1278. }
  1279. context.timeReference = compilation.time;
  1280. });
  1281. for (const key of Object.keys(SIMPLE_PRINTERS)) {
  1282. stats.hooks.print
  1283. .for(key)
  1284. .tap("DefaultStatsPrinterPlugin", (obj, ctx) =>
  1285. SIMPLE_PRINTERS[key](obj, ctx, stats)
  1286. );
  1287. }
  1288. for (const key of Object.keys(PREFERRED_ORDERS)) {
  1289. const preferredOrder = PREFERRED_ORDERS[key];
  1290. stats.hooks.sortElements
  1291. .for(key)
  1292. .tap("DefaultStatsPrinterPlugin", (elements, context) => {
  1293. createOrder(elements, preferredOrder);
  1294. });
  1295. }
  1296. for (const key of Object.keys(ITEM_NAMES)) {
  1297. const itemName = ITEM_NAMES[key];
  1298. stats.hooks.getItemName
  1299. .for(key)
  1300. .tap(
  1301. "DefaultStatsPrinterPlugin",
  1302. typeof itemName === "string" ? () => itemName : itemName
  1303. );
  1304. }
  1305. for (const key of Object.keys(SIMPLE_ITEMS_JOINER)) {
  1306. const joiner = SIMPLE_ITEMS_JOINER[key];
  1307. stats.hooks.printItems
  1308. .for(key)
  1309. .tap("DefaultStatsPrinterPlugin", joiner);
  1310. }
  1311. for (const key of Object.keys(SIMPLE_ELEMENT_JOINERS)) {
  1312. const joiner = SIMPLE_ELEMENT_JOINERS[key];
  1313. stats.hooks.printElements
  1314. .for(key)
  1315. .tap("DefaultStatsPrinterPlugin", joiner);
  1316. }
  1317. for (const key of Object.keys(RESULT_MODIFIER)) {
  1318. const modifier = RESULT_MODIFIER[key];
  1319. stats.hooks.result
  1320. .for(key)
  1321. .tap("DefaultStatsPrinterPlugin", modifier);
  1322. }
  1323. }
  1324. );
  1325. });
  1326. }
  1327. }
  1328. module.exports = DefaultStatsPrinterPlugin;