DefaultStatsPresetPlugin.js 11 KB

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