DefaultStatsPresetPlugin.js 12 KB

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