3

实现一个移除 console.log 的 webpack 插件

 2 years ago
source link: https://www.geekjc.com/post/617e3f932d33c8599d4c2b52
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
关注本文作者公众号获取最新福利

实现一个移除 console.log 的 webpack 插件

时间: 10/31/2021作者: ylf-联合编辑浏览量: 2

本文目的,实现一个可以移除项目中 console.log 的 webpack 插件。借此,我们可以学习一下webpack 插件怎么写。

首先,我们需要初始化环境

yarn init -y
yarn add webpack webpack-cli -D

webpack.config.js 配置如下:

module.exports = {
    entry: './index.js',
    plugins: []
}

根目录下新建一个 index.js,内容如下:

console.log('hello world');

在 package.json 添加 build 命令

"scripts": {
    "build": "yarn webpack"
}

此时我们运行 yarn build 就会在 dist 目录打包出一个 main.js。我们使用 node 执行这个文件就会输出 hello world

node dist/main.js

如果成功输出,就说明环境已经配置好了。

目录结构如下(你可能没有 README.md,不过没有关系):

Snipaste_2021-10-31_15-12-14.png

为了方便期间,我们的自定义 Plugin 就放到 webpack.config.js 这个文件里。

切换到 webpack.config.js 我们新建一个类,作为我们的自定义 Plugin。

class RemoveLogs {
    constructor(options) {
        this.options = options
    }

    apply(compiler) {
        console.log("Hello from the custom plugin")
    };
}

module.exports = {
    entry: './index.js',
    plugins: [ new RemoveLogs()]
}

此时再运行 yarn build,你会在控制台看到 Hello from the custom plugin 这句话。这说明我们的自定义 Plugin 已经添加成功了。 我们接下来要做的,就是把我们代码里的 console.log 语句去掉,我们可以选择很多时机来做这件事。比如在即将开始编译的时候,而我们这里选择放在编译结束之后。

class RemoveLogs {
    constructor(options) {
        this.options = options
    }

    apply(compiler) {
        compiler.hooks.done.tap("RemoveLogs", stats => {
            console.log('我将要移除所有的 console')
            removeAllLogs(stats)
        });
    };
}

compiler.hooks.done 类似于我们 DOM 操作中的 document.addEventListener('click', ()=>{}) 。也就是说我们想在编译结束后要做什么事。其实还有非常多的生命周期,具体可以点击此链接

compiler.hooks.done.tap 这个函数的第一个参数是字符串,这里是 RemoveLogs。它在调试的时候比较有用,你可以随便起名,并不需要一定要对应 class 名;第二个参数是到了这个生命周期会执行的函数。 对于按钮我们可以使用 addEventListener添加多个 click 事件,在这里你也可以添加任意多的事件。不过,这里我们就只加一个就好了。 接下来我们完善 removeAllLogs 这个函数:

removeAllLogs(stats) {
    const { path, filename } = stats.compilation.options.output;
    let filePath = path + "/" + filename;

    fs.readFile(filePath, "utf8", (err, data) => {
        const rgx = /console.log\(['|"](.*?)['|"]\)/;
        const newData = data.replace(rgx, "");
        if (err) console.log(err);
        fs.writeFile(filePath, newData, function (err) {
            if (err) {
                return console.log(err)
            }
            console.log("Logs Removed");
        });
    });
}

但是此时运行会报错,因为这个时候的 filename 获取到的是一个替代值,具体来说,是字符串 '[name]',你可以自己运行试试看。我们还需要加一个钩子函数来获取此时真实的 filename。

compiler.hooks.compilation.tap('GetFileNamePlugin', compilation => {
    compilation.hooks.chunkIds.tap('GetFileNamePlugin', (c) => {
        this.filename = Array.from(c)[0].name
    });
});

此时我们的 removeAllLogs 也相应改变获取 filePath 的方式:

let filePath = (path + "/" + filename).replace(/\[name\]/g, this.filename);

到这里,我们就实现完毕了。试着运行 node dist/main.js,会发现我们已经没有任何输出了。

就这样,我们就实现完了一个最简单的 webpack 插件,有没有感觉并不是很难呢:)

评论里有同学说使用正则匹配来去除 console 的这种方法并不好,并且推荐在 babel 里做这件事,我在他的建议下找到了一个做这件事的 babel 插件: babel-plugin-transform-remove-console

同时它的源码在这:源码

因为这已经不是本文的主题了,就不在这里展开了,有兴趣的同学可以自己去研究~ 本篇文章的全部代码如下:

const fs = require('fs')

class RemoveLogs {
    constructor(options) {
        this.options = options
    }

    apply(compiler) {
        console.log(compiler.options.output);
        compiler.hooks.done.tap("RemoveLogs", stats => {
            try {
                this.removeAllLogs(stats);
            } catch (e) {
                console.log(e);
            }
        });

        compiler.hooks.compilation.tap('HelloCompilationPlugin', compilation => {
            compilation.hooks.chunkIds.tap('HelloCompilationPlugin', (c) => {
                this.filename = Array.from(c)[0].name
            });
        });
    };
    removeAllLogs(stats) {
        const { path, filename } = stats.compilation.options.output;
        let filePath = (path + "/" + filename).replace(/\[name\]/g, this.filename);

        try {
            fs.readFile(filePath, "utf8", (err, data) => {
                const rgx = /console.log\(['|"](.*?)['|"]\)/;
                const newData = data.replace(rgx, "");
                if (err) console.log(err);
                fs.writeFile(filePath, newData, function (err) {
                    if (err) {
                        console.log(err)
                    }
                    console.log("all logs Removed");
                });
            });
        } catch (e) {
            console.error(e)
        }

    }
}

module.exports = {
    entry: './index.js',
    plugins: [new RemoveLogs()]
}

其它可以清除console.log的方式

  1. 从语法树上处理
  2. console.log = function() {}
关注下面的标签,发现更多相似的文章

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK