UNPKG

webpack

Version:

Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.

106 lines (90 loc) 3.04 kB
/* MIT License http://www.opensource.org/licenses/mit-license.php Author Alexander Akait @alexander-akait */ "use strict"; const UnusedRuleWarning = require("../errors/UnusedRuleWarning"); /** * @import { * RuleSetRule, * PerformanceOptions * } from "../../declarations/WebpackOptions" */ /** @import Compiler from "../Compiler" */ const PLUGIN_NAME = "UnusedRuleWarningPlugin"; // `NormalModuleFactory` compiles `[{ rules: defaultRules }, { rules: rules }]`, // so only this subtree belongs to the configuration. const USER_RULES_PATH = "ruleSet[1].rules"; /** * Names the rule the way its author would recognize it. `module.rules[7]` alone * is useless when a plugin injected the rule. * @param {RuleSetRule} rule the raw rule * @returns {string} a short descriptor, or an empty string when nothing identifies it */ const describeRule = (rule) => { for (const key of ["test", "include", "exclude", "resource", "mimetype"]) { const value = rule[/** @type {keyof RuleSetRule} */ (key)]; if (value instanceof RegExp) return ` (${key}: ${value})`; if (typeof value === "string") return ` (${key}: ${value})`; } if (typeof rule.loader === "string") return ` (loader: ${rule.loader})`; if (typeof rule.type === "string") return ` (type: ${rule.type})`; return ""; }; class UnusedRuleWarningPlugin { /** * Creates an instance of UnusedRuleWarningPlugin. * @param {PerformanceOptions} options the plugin options */ constructor(options) { /** @type {PerformanceOptions["hints"]} */ this.hints = options.hints; } /** * Applies the plugin by registering its hooks on the compiler. * @param {Compiler} compiler the compiler instance * @returns {void} */ apply(compiler) { const hints = this.hints; compiler.hooks.compilation.tap( PLUGIN_NAME, (compilation, { normalModuleFactory }) => { compilation.hooks.afterSeal.tap(PLUGIN_NAME, () => { // Nothing was factorized, so no rule could match — an empty build is // not evidence that a rule is unused. if (compilation.modules.size === 0) return; /** @type {string[]} */ const descriptions = []; for (const rule of normalModuleFactory.ruleSet.unusedRules()) { if (!rule.path.startsWith(USER_RULES_PATH)) continue; // A rule aimed at another compiler of a MultiCompiler is inactive // here by design, not by mistake. if ( rule.conditions.some( (condition) => condition.property === "compiler" ) ) { continue; } descriptions.push( `${rule.path.replace(USER_RULES_PATH, "module.rules")}${describeRule( rule.raw )}` ); } if (descriptions.length === 0) return; const warning = new UnusedRuleWarning(descriptions); if (hints === "error") { compilation.errors.push(warning); } else if (hints === "stats") { compilation.hints.push(warning); } else { compilation.warnings.push(warning); } }); } ); } } module.exports = UnusedRuleWarningPlugin;