DefaultStatsPresetPlugin.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RequestShortener = require("../RequestShortener");
  7. /**
  8. * @import {
  9. * StatsOptions,
  10. * StatsValue
  11. * } from "../../declarations/WebpackOptions"
  12. */
  13. /**
  14. * @import Compilation, {
  15. * CreateStatsOptionsContext,
  16. * KnownNormalizedStatsOptions,
  17. * NormalizedStatsOptions
  18. * } from "../Compilation"
  19. */
  20. /** @import Compiler from "../Compiler" */
  21. /** @import { StatsError } from "./DefaultStatsFactoryPlugin" */
  22. /**
  23. * Processes the provided normalized stats option.
  24. * @param {Partial<NormalizedStatsOptions>} options options
  25. * @param {StatsOptions} defaults default options
  26. */
  27. const applyDefaults = (options, defaults) => {
  28. for (const _k of Object.keys(defaults)) {
  29. const key = /** @type {keyof StatsOptions} */ (_k);
  30. if (typeof options[key] === "undefined") {
  31. options[/** @type {keyof NormalizedStatsOptions} */ (key)] =
  32. defaults[key];
  33. }
  34. }
  35. };
  36. /** @typedef {{ [Key in Exclude<StatsValue, boolean | StatsOptions | "normal">]: StatsOptions }} NamedPresets */
  37. /** @type {NamedPresets} */
  38. const NAMED_PRESETS = {
  39. verbose: {
  40. hash: true,
  41. builtAt: true,
  42. relatedAssets: true,
  43. entrypoints: true,
  44. chunkGroups: true,
  45. chunkGroupResourceHints: true,
  46. ids: true,
  47. modules: false,
  48. chunks: true,
  49. chunkRelations: true,
  50. chunkModules: true,
  51. dependentModules: true,
  52. chunkOrigins: true,
  53. depth: true,
  54. env: true,
  55. reasons: true,
  56. usedExports: true,
  57. providedExports: true,
  58. optimizationBailout: true,
  59. errorDetails: true,
  60. errorStack: true,
  61. errorCause: true,
  62. errorErrors: true,
  63. publicPath: true,
  64. logging: "verbose",
  65. orphanModules: true,
  66. runtimeModules: true,
  67. exclude: false,
  68. errorsSpace: Infinity,
  69. warningsSpace: Infinity,
  70. modulesSpace: Infinity,
  71. chunkModulesSpace: Infinity,
  72. assetsSpace: Infinity,
  73. reasonsSpace: Infinity,
  74. children: true
  75. },
  76. detailed: {
  77. hash: true,
  78. builtAt: true,
  79. relatedAssets: true,
  80. entrypoints: true,
  81. chunkGroups: true,
  82. ids: true,
  83. chunks: true,
  84. chunkRelations: true,
  85. chunkModules: false,
  86. chunkOrigins: true,
  87. depth: true,
  88. usedExports: true,
  89. providedExports: true,
  90. optimizationBailout: true,
  91. errorDetails: true,
  92. errorCause: true,
  93. errorErrors: true,
  94. publicPath: true,
  95. logging: true,
  96. runtimeModules: true,
  97. exclude: false,
  98. errorsSpace: 1000,
  99. warningsSpace: 1000,
  100. modulesSpace: 1000,
  101. assetsSpace: 1000,
  102. reasonsSpace: 1000
  103. },
  104. minimal: {
  105. all: false,
  106. version: true,
  107. timings: true,
  108. modules: true,
  109. errorsSpace: 0,
  110. warningsSpace: 0,
  111. modulesSpace: 0,
  112. assets: true,
  113. assetsSpace: 0,
  114. errors: true,
  115. errorsCount: true,
  116. warnings: true,
  117. warningsCount: true,
  118. logging: "warn"
  119. },
  120. "errors-only": {
  121. all: false,
  122. errors: true,
  123. errorsCount: true,
  124. errorsSpace: Infinity,
  125. moduleTrace: true,
  126. logging: "error"
  127. },
  128. "errors-warnings": {
  129. all: false,
  130. errors: true,
  131. errorsCount: true,
  132. errorsSpace: Infinity,
  133. warnings: true,
  134. warningsCount: true,
  135. warningsSpace: Infinity,
  136. logging: "warn"
  137. },
  138. summary: {
  139. all: false,
  140. version: true,
  141. errorsCount: true,
  142. warningsCount: true
  143. },
  144. none: {
  145. all: false
  146. }
  147. };
  148. /**
  149. * Returns true when enabled, otherwise false.
  150. * @param {Partial<NormalizedStatsOptions>} all stats options
  151. * @returns {boolean} true when enabled, otherwise false
  152. */
  153. const NORMAL_ON = ({ all }) => all !== false;
  154. /**
  155. * Returns true when enabled, otherwise false.
  156. * @param {Partial<NormalizedStatsOptions>} all stats options
  157. * @returns {boolean} true when enabled, otherwise false
  158. */
  159. const NORMAL_OFF = ({ all }) => all === true;
  160. /**
  161. * Returns true when enabled, otherwise false.
  162. * @param {Partial<NormalizedStatsOptions>} all stats options
  163. * @param {CreateStatsOptionsContext} forToString stats options context
  164. * @returns {boolean} true when enabled, otherwise false
  165. */
  166. const ON_FOR_TO_STRING = ({ all }, { forToString }) =>
  167. forToString ? all !== false : all === true;
  168. /**
  169. * Returns true when enabled, otherwise false.
  170. * @param {Partial<NormalizedStatsOptions>} all stats options
  171. * @param {CreateStatsOptionsContext} forToString stats options context
  172. * @returns {boolean} true when enabled, otherwise false
  173. */
  174. const OFF_FOR_TO_STRING = ({ all }, { forToString }) =>
  175. forToString ? all === true : all !== false;
  176. /**
  177. * Auto for to string.
  178. * @param {Partial<NormalizedStatsOptions>} all stats options
  179. * @param {CreateStatsOptionsContext} forToString stats options context
  180. * @returns {boolean | "auto"} true when enabled, otherwise false
  181. */
  182. const AUTO_FOR_TO_STRING = ({ all }, { forToString }) => {
  183. if (all === false) return false;
  184. if (all === true) return true;
  185. if (forToString) return "auto";
  186. return true;
  187. };
  188. /** @typedef {keyof NormalizedStatsOptions} DefaultsKeys */
  189. /** @typedef {{ [Key in DefaultsKeys]: (options: Partial<NormalizedStatsOptions>, context: CreateStatsOptionsContext, compilation: Compilation) => NormalizedStatsOptions[Key] | RequestShortener }} Defaults */
  190. /** @type {Defaults} */
  191. const DEFAULTS = {
  192. context: (options, context, compilation) => compilation.compiler.context,
  193. requestShortener: (options, context, compilation) =>
  194. compilation.compiler.context === options.context
  195. ? compilation.requestShortener
  196. : new RequestShortener(
  197. /** @type {string} */
  198. (options.context),
  199. compilation.compiler.root
  200. ),
  201. performance: NORMAL_ON,
  202. hash: OFF_FOR_TO_STRING,
  203. env: NORMAL_OFF,
  204. version: NORMAL_ON,
  205. timings: NORMAL_ON,
  206. builtAt: OFF_FOR_TO_STRING,
  207. assets: NORMAL_ON,
  208. entrypoints: AUTO_FOR_TO_STRING,
  209. chunkGroups: OFF_FOR_TO_STRING,
  210. chunkGroupAuxiliary: OFF_FOR_TO_STRING,
  211. chunkGroupChildren: OFF_FOR_TO_STRING,
  212. chunkGroupResourceHints: OFF_FOR_TO_STRING,
  213. chunkGroupMaxAssets: (o, { forToString }) => (forToString ? 5 : Infinity),
  214. chunks: OFF_FOR_TO_STRING,
  215. chunkRelations: OFF_FOR_TO_STRING,
  216. chunkModules: ({ all, modules }) => {
  217. if (all === false) return false;
  218. if (all === true) return true;
  219. if (modules) return false;
  220. return true;
  221. },
  222. dependentModules: OFF_FOR_TO_STRING,
  223. chunkOrigins: OFF_FOR_TO_STRING,
  224. ids: OFF_FOR_TO_STRING,
  225. modules: ({ all, chunks, chunkModules }, { forToString }) => {
  226. if (all === false) return false;
  227. if (all === true) return true;
  228. if (forToString && chunks && chunkModules) return false;
  229. return true;
  230. },
  231. nestedModules: OFF_FOR_TO_STRING,
  232. groupModulesByType: ON_FOR_TO_STRING,
  233. groupModulesByCacheStatus: ON_FOR_TO_STRING,
  234. groupModulesByLayer: ON_FOR_TO_STRING,
  235. groupModulesByAttributes: ON_FOR_TO_STRING,
  236. groupModulesByPath: ON_FOR_TO_STRING,
  237. groupModulesByExtension: ON_FOR_TO_STRING,
  238. modulesSpace: (o, { forToString }) => (forToString ? 15 : Infinity),
  239. chunkModulesSpace: (o, { forToString }) => (forToString ? 10 : Infinity),
  240. nestedModulesSpace: (o, { forToString }) => (forToString ? 10 : Infinity),
  241. relatedAssets: OFF_FOR_TO_STRING,
  242. groupAssetsByEmitStatus: ON_FOR_TO_STRING,
  243. groupAssetsByInfo: ON_FOR_TO_STRING,
  244. groupAssetsByPath: ON_FOR_TO_STRING,
  245. groupAssetsByExtension: ON_FOR_TO_STRING,
  246. groupAssetsByChunk: ON_FOR_TO_STRING,
  247. assetsSpace: (o, { forToString }) => (forToString ? 15 : Infinity),
  248. orphanModules: OFF_FOR_TO_STRING,
  249. runtimeModules: ({ all, runtime }, { forToString }) =>
  250. runtime !== undefined
  251. ? runtime
  252. : forToString
  253. ? all === true
  254. : all !== false,
  255. cachedModules: ({ all, cached }, { forToString }) =>
  256. cached !== undefined ? cached : forToString ? all === true : all !== false,
  257. moduleAssets: OFF_FOR_TO_STRING,
  258. depth: OFF_FOR_TO_STRING,
  259. cachedAssets: OFF_FOR_TO_STRING,
  260. reasons: OFF_FOR_TO_STRING,
  261. reasonsSpace: (o, { forToString }) => (forToString ? 15 : Infinity),
  262. groupReasonsByOrigin: ON_FOR_TO_STRING,
  263. usedExports: OFF_FOR_TO_STRING,
  264. providedExports: OFF_FOR_TO_STRING,
  265. optimizationBailout: OFF_FOR_TO_STRING,
  266. children: OFF_FOR_TO_STRING,
  267. source: NORMAL_OFF,
  268. moduleTrace: NORMAL_ON,
  269. errors: NORMAL_ON,
  270. errorsCount: NORMAL_ON,
  271. errorDetails: AUTO_FOR_TO_STRING,
  272. errorStack: OFF_FOR_TO_STRING,
  273. errorCause: AUTO_FOR_TO_STRING,
  274. errorErrors: AUTO_FOR_TO_STRING,
  275. warnings: NORMAL_ON,
  276. warningsCount: NORMAL_ON,
  277. hints: NORMAL_ON,
  278. hintsCount: NORMAL_ON,
  279. publicPath: OFF_FOR_TO_STRING,
  280. logging: ({ all }, { forToString }) =>
  281. forToString && all !== false ? "info" : false,
  282. loggingDebug: () => [],
  283. loggingTrace: OFF_FOR_TO_STRING,
  284. excludeModules: () => [],
  285. excludeAssets: () => [],
  286. modulesSort: () => "depth",
  287. chunkModulesSort: () => "name",
  288. nestedModulesSort: () => false,
  289. chunksSort: () => false,
  290. assetsSort: () => "!size",
  291. outputPath: OFF_FOR_TO_STRING,
  292. colors: () => false
  293. };
  294. /**
  295. * Defines the normalize function type used by this module.
  296. * @template T
  297. * @typedef {(value: T, ...args: EXPECTED_ANY[]) => boolean} NormalizeFunction
  298. */
  299. /**
  300. * Returns normalize fn.
  301. * @template {string} T
  302. * @param {string | ({ test: (value: T) => boolean }) | NormalizeFunction<T> | boolean} item item to normalize
  303. * @returns {NormalizeFunction<T>} normalize fn
  304. */
  305. const normalizeFilter = (item) => {
  306. if (typeof item === "string") {
  307. const regExp = new RegExp(
  308. `[\\\\/]${item.replace(/[-[\]{}()*+?.\\^$|]/g, "\\$&")}([\\\\/]|$|!|\\?)`
  309. );
  310. return (ident) => regExp.test(/** @type {T} */ (ident));
  311. }
  312. if (item && typeof item === "object" && typeof item.test === "function") {
  313. return (ident) => item.test(ident);
  314. }
  315. if (typeof item === "boolean") {
  316. return () => item;
  317. }
  318. return /** @type {NormalizeFunction<T>} */ (item);
  319. };
  320. /** @typedef {keyof (KnownNormalizedStatsOptions | StatsOptions)} NormalizerKeys */
  321. /** @typedef {{ [Key in NormalizerKeys]?: (value: StatsOptions[Key]) => KnownNormalizedStatsOptions[Key] }} Normalizers */
  322. /**
  323. * Defines the warning filter fn callback.
  324. * @callback WarningFilterFn
  325. * @param {StatsError} warning warning
  326. * @param {string} warningString warning string
  327. * @returns {boolean} result
  328. */
  329. /** @type {Normalizers} */
  330. const NORMALIZER = {
  331. excludeModules: (value) => {
  332. if (!Array.isArray(value)) {
  333. value = value
  334. ? /** @type {KnownNormalizedStatsOptions["excludeModules"]} */ ([value])
  335. : [];
  336. }
  337. return value.map(normalizeFilter);
  338. },
  339. excludeAssets: (value) => {
  340. if (!Array.isArray(value)) {
  341. value = value ? [value] : [];
  342. }
  343. return value.map(normalizeFilter);
  344. },
  345. warningsFilter: (value) => {
  346. if (!Array.isArray(value)) {
  347. value = value ? [value] : [];
  348. }
  349. return value.map(
  350. /**
  351. * Handles the warnings filter callback for this hook.
  352. * @param {StatsOptions["warningsFilter"]} filter a warning filter
  353. * @returns {WarningFilterFn} result
  354. */
  355. (filter) => {
  356. if (typeof filter === "string") {
  357. return (warning, warningString) => warningString.includes(filter);
  358. }
  359. if (filter instanceof RegExp) {
  360. return (warning, warningString) => filter.test(warningString);
  361. }
  362. if (typeof filter === "function") {
  363. return filter;
  364. }
  365. throw new Error(
  366. `Can only filter warnings with Strings or RegExps. (Given: ${filter})`
  367. );
  368. }
  369. );
  370. },
  371. logging: (value) => {
  372. if (value === true) value = "log";
  373. return /** @type {KnownNormalizedStatsOptions["logging"]} */ (value);
  374. },
  375. loggingDebug: (value) => {
  376. if (!Array.isArray(value)) {
  377. value = value
  378. ? /** @type {KnownNormalizedStatsOptions["loggingDebug"]} */ ([value])
  379. : [];
  380. }
  381. return value.map(normalizeFilter);
  382. }
  383. };
  384. const PLUGIN_NAME = "DefaultStatsPresetPlugin";
  385. class DefaultStatsPresetPlugin {
  386. /**
  387. * Applies the plugin by registering its hooks on the compiler.
  388. * @param {Compiler} compiler the compiler instance
  389. * @returns {void}
  390. */
  391. apply(compiler) {
  392. compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
  393. for (const key of Object.keys(NAMED_PRESETS)) {
  394. const defaults = NAMED_PRESETS[/** @type {keyof NamedPresets} */ (key)];
  395. compilation.hooks.statsPreset
  396. .for(key)
  397. .tap(PLUGIN_NAME, (options, _context) => {
  398. applyDefaults(options, defaults);
  399. });
  400. }
  401. compilation.hooks.statsNormalize.tap(PLUGIN_NAME, (options, context) => {
  402. for (const key of Object.keys(DEFAULTS)) {
  403. if (options[key] === undefined) {
  404. options[key] = DEFAULTS[/** @type {DefaultsKeys} */ (key)](
  405. options,
  406. context,
  407. compilation
  408. );
  409. }
  410. }
  411. for (const key of Object.keys(NORMALIZER)) {
  412. options[key] =
  413. /** @type {NonNullable<Normalizers[keyof Normalizers]>} */
  414. (NORMALIZER[/** @type {NormalizerKeys} */ (key)])(options[key]);
  415. }
  416. });
  417. });
  418. }
  419. }
  420. module.exports = DefaultStatsPresetPlugin;