DefaultStatsPresetPlugin.js 12 KB

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