19 深入Plugin

深入Plugin

Loader是专注于不同类型模块的转换,某些功能是Loader无法实现的,就需要使用Plugin来实现。因为Webpack使用了Tapable,所以在构建的时候能够发出很多事件,而Plugin在收到自己感兴趣的事件后,就会执行相应的操作。

一个基础的插件结构如下:

  • 一个JavaScript命名函数。
  • 在插件函数的prototype上定义一个apply方法。
  • 指定一个绑定到Webpack自身的事件钩子。
  • 处理Webpack内部实例的特定数据。
  • 功能完成后调用Webpack提供的回调。
class Myplugin {
    constructor(options) {
        this.options = options;
    }
    apply(compiler) {
        compiler.hooks.emit.tap('Myplug', (compilation) => {
        })
    }
}
module.exports = Myplugin;

插件中一个必不可少的函数就是apply,这个apply方法在安装插件时,会被Webpack Compiler调用一次。apply方法可以接收一个Webpack Compiler对象的引用,从而可以在函数中访问到Compiler对象。

Compiler和Compilation

在插件开发中最重要的两个资源对象就是Compiler和Compilation 对象。理解它们的角色是扩展Webpack引擎重要的第一步。

Compiler对象代表了完整的Webpack环境配置。这个对象在启动Webpack时被一次性建立,并配置好所有可操作的设置,包括Options,Loader和Plugin。当在Webpack环境中应用一个插件时,插件将收到此Compiler对象的引用。可以使用它来访问Webpack的主环境。

Compilation对象代表了一次资源版本构建。当以监听模式运行Webpack时,每当检测到一个文件变化,就会创建一个新的Compilation,从而生成一组新的编译资源。一个Compilation对象包含了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。Compilation对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。

编写一个简单的Plugin

在编写插件之前,先看Webpack官网给出的一个插件编写的演示:

class FileListPlugin {
    constructor(options) {
        this.options = options;
    }
    apply(compiler) {
        compiler.hooks.emit.tapAsync('FileListPlugin', (compilation, callback) => {
            // 在生成文件中,创建一个头部字符串:
            let filelist = 'In this build:\n\n';
            // 遍历所有编译过的资源文件,
            // 对于每个文件名称,都添加一行内容。
            Object.entries(compilation.assets).forEach(([filename, proObj]) => {
                filelist += ('- ' + filename + ' ' + proObj.size() + '\n');
            })
            // 将这个列表作为一个新的文件资源,插入到 webpack 构建中:
            compilation.assets[this.options.filename] = {
                source: function () {
                    return filelist;
                },
                size: function () {
                    return filelist.length;
                }
            };
            callback();
        })
    }
}
module.exports = FileListPlugin;

该插件是严格按照插件的定义来实现的,其功能是生成一个统计输出资源信息的文件。

下面我们来实现一个在打包完成后,自动提交代码到Gi仓库的插件:

const shell = require("shelljs");
class MyPlugin {
    constructor(options) {
        this.options = options;
    }
    apply(compiler) {
        compiler.hooks.done.tap('MyPlugin', () => {
            shell.exec('git add .');
            shell.exec(`git commit 										  						 -m'${this.options.commitInfo}'`);
            shell.exec('git push');
        })
    }
}
module.exports = MyPlugin;

使用该插件之前,假设你的项目已经初始化好了Git的相关配置。该插件使用方式如下:

module.exports = {
    plugins: [
        new MyPlugin({
            commitInfo: '自定义插件使用'
        })
    ]
}

本章节提供案例源码下载:https://gitee.com/mvc_ydb/webpack/blob/master/deepPlugin.zip

上一篇:Filter实战——实现非法字符的过滤


下一篇:基于APPIUM测试微信公众号的UI自动化测试框架(结合Allure2测试报告框架)