Реализовать подключаемый модуль веб-пакета, удаляющий console.log.

Webpack

Для целей этой статьи реализуйте проект, который можно удалить изconsole.logПлагин веб-пакета. Возьми это, мы можем научиться писать плагин 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.jsonbuildЗаказ

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

В этот момент мы бежимyarn buildMain.js будет упакован в каталог dist. Мы используем узел для выполнения этого файла, и он выведет hello world

node dist/main.js

Если вывод успешен, значит, среда настроена.

Структура каталогов выглядит следующим образом (у вас может не быть README.md, но это нормально):

Для удобства наш пользовательский плагин помещен в файл webpack.config.js.

Переключитесь на webpack.config.js, и мы создадим новый класс в качестве нашего пользовательского плагина.

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 от пользовательского плагина в консоли. Это показывает, что наш пользовательский плагин был успешно добавлен.

Что нам нужно сделать дальше, так это поставить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Подобно нашей манипуляции с DOMdocument.addEventListener('click', ()=>{}). То есть мы хотим что-то сделать после завершения компиляции. На самом деле жизненных циклов много, можно нажатьэта ссылка

компилятор.hooks.done.tap Первым параметром этой функции является строка, в данном случае RemoveLogs. Он более полезен при отладке, вы можете назвать его произвольно, и он не должен соответствовать имени класса, второй параметр — это функция, которая будет выполняться в этом жизненном цикле.

Для кнопки мы можем использоватьaddEventListenerДобавьте несколько событий кликов, здесь вы можете добавить столько событий, сколько хотите. Однако здесь мы просто добавляем один.

Далее мы улучшаем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");
        });
    });
}

Но в это время будет сообщено об ошибке, т.к. имя файла в это время получает альтернативное значение, а именно строку '[имя]', можете попробовать сами. Нам также нужно добавить функцию ловушки, чтобы получить реальное имя файла в это время.

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, вы обнаружите, что у нас больше нет вывода.

Таким образом, мы реализовали один из самых простых плагинов вебпака, как вы думаете, это не сложно :)

Некоторые студенты в комментариях сказали, что обычное сопоставление используется для удаления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()]
}