编写一个移除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:['*']
})],
};