代码改变世界

webpack --- 自定义 webpack plugin

2019-10-17 09:56  *奋斗*  阅读(143)  评论(0)    收藏  举报

[Compiler.js]:

const {
    SyncHook,
    AsyncParallelHook
} = require('tapable');

class Compiler {
    constructor(options) {
        this.hooks = {
            accelerate: new SyncHook(["newSpeed"]),
            break: new SyncHook(),
            calculateRoutes: new AsyncParallelHook(["source", "target", "routesList"])
        };
        let plugins = options.plugins;
        if (plugins && plugins.length > 0) {
            plugins.forEach(plugin => plugin.apply(this));
        }
    }
    run() {
        console.time('cost'); // time start
        this.accelerate('hello')
        this.break()
        this.calculateRoutes('i', 'like', 'tapable')
    }
    accelerate(param) {
        this.hooks.accelerate.call(param);
    }
    break() {
        this.hooks.break.call();
    }
    calculateRoutes() {
        const args = Array.from(arguments)
        this.hooks.calculateRoutes.callAsync(...args, err => {
            console.timeEnd('cost');  // time end
            if (err) console.log(err)
        });
    }
}

module.exports = Compiler;

[MyPlugin.js]:

const Compiler = require('./Compiler') //

class MyPlugin{
    constructor() {

    }
    apply(compiler){//接受 compiler参数
        compiler.hooks.break.tap("WarningLampPlugin", () => console.log('WarningLampPlugin'));
        compiler.hooks.accelerate.tap("LoggerPlugin", newSpeed => console.log(`Accelerating to ${newSpeed}`));
        compiler.hooks.calculateRoutes.tapAsync("calculateRoutes tapAsync", (source, target, routesList, callback) => {
            setTimeout(() => {
                console.log(`tapAsync to ${source}${target}${routesList}`)
                callback();
            }, 2000)
        });
    }
}

class MyPluginEx{
    constructor() {

    }
    apply(compiler){ //接受 compiler参数
        compiler.hooks.break.tap("WarningLampPlugin", () => console.log('WarningLampPlugin'));
        compiler.hooks.accelerate.tap("LoggerPlugin", newSpeed => console.log(`Accelerating to ${newSpeed}`));
        compiler.hooks.calculateRoutes.tapAsync("calculateRoutes tapAsync", (source, target, routesList, callback) => {
            setTimeout(() => {
                console.log(`tapAsync to ${source}${target}${routesList}`)
                callback();
            }, 2000)
        });
    }
}

//这里类似于webpack.config.js的plugins配置
//向 plugins 属性传入 new 实例

const myPlugin = new MyPlugin();
const myPluginEx = new MyPluginEx();

const options = {
    plugins: [myPlugin, myPluginEx]
}
let compiler = new Compiler(options)
compiler.run();

个人总结:

1、Compiler.js 对 Webpack 进行了模拟。run( ) 中分别调用了不同的钩子函数(类似于生命周期钩子函数);

2、不同的钩子函数,在不同的插件初始化后,都可以对挂载的 handler 了进行依次执行,原理的理解可以参考组件的生命周期(不同时间段干不同的事情);

3、Compiler 可以同时初始化多个插件(插件数组,跟 webpack config 类似),实际上述代码可以在 vs code 中针对 MyPlugin.js 代码直接执行查看结果;

4、new SyncHook(["newSpeed"]) 中的 newSpeed 其实就是写在插件中的初始化钩子时的参数名,直接对应,有几个参数传递几个。

http://07lyt.com/2017/04/28/webpack%E6%B5%81%E7%A8%8B/  --- 图片来源