Webpack - 编写一个移除Console的Plugin

开发 · 2023-11-21 · 52 人浏览

编写一个移除Console的Plugin,并支持开启关闭

一些知识点

本质

Plguin就是一个类,所以webpack config中使用的时候都是以new的形式传入,并且会自动执行类中的apply方法

compiler/compliation

compiler就是webpack执行流程,它提供了许多钩子,允许我们做各种各样的事情,并且它是以Tapable工具库为底层来编写的一个容器对象

不同的生命周期示例

class Plugin1 {
  /**
   * 需要注意钩子本身是同步还是异步钩子
   * tab同步  tabAsync异步 tabPromise Promise异步
   */
  // 都会执行 apply方法
  apply(complier) {
    complier.hooks.emit.tap("Plugin1", (complation) => {
      console.log("emit.tap");
    });
    complier.hooks.emit.tapAsync("Plugin1", (complation, cb) => {
      setTimeout(() => {
        console.log("emit.tapAsync");
        cb();
      }, 1000);
    });
    complier.hooks.emit.tapPromise("Plugin1", (complation) => {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log("emit.tapPromise");
          resolve();
        }, 1000);
      });
    });
    complier.hooks.afterEmit.tap("Plugin1", (complation) => {
      console.log("afterEmit.tap");
    });

    complier.hooks.done.tap("Plugin1", (complation) => {
      console.log("done.tap");
    });
  }
}
module.exports = Plugin1;

完整实现

const consoleMethod = ["console", "window.console"];
let consoleAttr = [
  "assert",
  "clear",
  "context",
  "count",
  "countReset",
  "createTask",
  "debug",
  "dir",
  "dirxml",
  "error",
  "group",
  "groupCollapsed",
  "groupEnd",
  "info",
  "log",
  "memory",
  "profile",
  "profileEnd",
  "table",
  "time",
  "timeEnd",
  "timeLog",
  "timeStamp",
  "trace",
  "warn",
];

const defaultOptions = {
  // Enable plugin
  enable: true,
  // Collect options
  include: ["*"],
};

class cleanConsoleWebpackPlugin {
  constructor(options = defaultOptions) {
    // check object
    if (!this.isPlainObject(options)) {
      throw new Error(
        `webpack plugin - clean-console-plugin Only supported object options`
      );
    }

    // normalize options
    const { enable = true, include = ["*"] } = options;
    this.enable = enable;
    this.include = include;

    // check attr
    if (Array.isArray(include) && !include.includes("*")) {
      consoleAttr = include;
    }
    this.reg = new RegExp(
      "(" +
        consoleMethod.join("|") +
        ")\\.(" +
        consoleAttr.join("|") +
        ")\\(" +
        ".*" +
        "\\)" +
        ";*",
      "gi"
    );
  }
  apply(compiler) {
    // Webpack5
    if (compiler.hooks) {
      compiler.hooks.compilation.tap("cleanConsolePlugin", (compilation) => {
        if (this.enable) {
          compilation.hooks.processAssets.tapAsync(
            "cleanConsolePlugin",
            (module, cb) => {
              debugger;
              this.buildFile(module, compilation, cb);
            }
          );
        }
      });
    }
  }
  buildFile(assets, compilation, cb) {
    Object.entries(assets).forEach(([fileName, cacheSource]) => {
      let sourceCode = cacheSource.source();
      const map = cacheSource.map();

      sourceCode = sourceCode.replace(this.reg, "");
      compilation.assets[fileName] = {
        source: () => sourceCode,
        map: () => map,
        sourceAndMap: () => ({ source: sourceCode, map }),
        buffer: () => Buffer.from(sourceCode),
        size: () => Buffer.byteLength(sourceCode, "utf-8"),
      };
      cb();
    });
  }
  isPlainObject(val) {
    if (Object.prototype.toString.call(val) !== "[object Object]") return false;
    return true;
  }
}

module.exports = cleanConsoleWebpackPlugin;

使用它

const cleanConsoleWebpackPlugin = require("./plugins/cleanConsolePlugin");
module.exports = {
  plugins: [new cleanConsoleWebpackPlugin({
    enable:true,
    include:['*']
  })],
};
webpack
Theme Jasmine by Kent Liao