UnusedDefinesPlugin.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Alexander Akait @alexander-akait
  4. */
  5. "use strict";
  6. const { VALUE_DEP_PREFIX, getDeclaredKeys } = require("../DefinePlugin");
  7. const UnusedDefinesWarning = require("../errors/UnusedDefinesWarning");
  8. /** @import { PerformanceOptions } from "../../declarations/WebpackOptions" */
  9. /** @import Compiler from "../Compiler" */
  10. /** @import { NormalModuleBuildInfo } from "../NormalModule" */
  11. const PLUGIN_NAME = "UnusedDefinesPlugin";
  12. class UnusedDefinesPlugin {
  13. /**
  14. * Creates an instance of UnusedDefinesPlugin.
  15. * @param {PerformanceOptions} options the plugin options
  16. */
  17. constructor(options) {
  18. /** @type {PerformanceOptions["hints"]} */
  19. this.hints = options.hints;
  20. }
  21. /**
  22. * Applies the plugin by registering its hooks on the compiler.
  23. * @param {Compiler} compiler the compiler instance
  24. * @returns {void}
  25. */
  26. apply(compiler) {
  27. const hints = this.hints;
  28. compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
  29. compilation.hooks.afterSeal.tap(PLUGIN_NAME, () => {
  30. const declared = getDeclaredKeys(compilation);
  31. if (declared === undefined || declared.size === 0) return;
  32. // Nothing was parsed, so no key could be substituted — an empty build is
  33. // not evidence that a key is unused.
  34. if (compilation.modules.size === 0) return;
  35. /** @type {Set<string>} */
  36. const used = new Set();
  37. for (const module of compilation.modules) {
  38. const buildInfo =
  39. /** @type {NormalModuleBuildInfo} */
  40. (module.buildInfo);
  41. if (!buildInfo || !buildInfo.valueDependencies) continue;
  42. // Survives the persistent cache: `valueDependencies` is serialized
  43. // with the module, so a restored module answers without rebuilding.
  44. for (const name of buildInfo.valueDependencies.keys()) {
  45. if (name.startsWith(VALUE_DEP_PREFIX)) {
  46. used.add(name.slice(VALUE_DEP_PREFIX.length));
  47. }
  48. }
  49. }
  50. const unused = [];
  51. for (const key of declared) {
  52. if (!used.has(key)) unused.push(key);
  53. }
  54. if (unused.length === 0) return;
  55. unused.sort();
  56. const warning = new UnusedDefinesWarning(unused);
  57. if (hints === "error") {
  58. compilation.errors.push(warning);
  59. } else if (hints === "stats") {
  60. compilation.hints.push(warning);
  61. } else {
  62. compilation.warnings.push(warning);
  63. }
  64. });
  65. });
  66. }
  67. }
  68. module.exports = UnusedDefinesPlugin;