美文网首页前端
为webpack编写一个plugin

为webpack编写一个plugin

作者: 守望星空l | 来源:发表于2020-02-07 02:27 被阅读0次

    0、基本概念

    插件是webpack的支柱功能,极大地强化了webpack的构建能力。

    webpack 插件由以下组成:
    • 一个 JavaScript 命名函数。
    • 在插件函数的 prototype 上定义一个 apply 方法。
    • 指定一个绑定到 webpack 自身的事件钩子
    • 处理 webpack 内部实例的特定数据。
    • 功能完成后调用 webpack 提供的回调。

    1、webpack Hooks

    一个简单的例子:
    function MyExampleWebpackPlugin() {
    };
    
    // 在插件函数的 prototype 上定义一个 `apply` 方法。
    MyExampleWebpackPlugin.prototype.apply = function(compiler) {
      // 指定一个挂载到 webpack 自身的事件钩子。
      compiler.plugin('webpacksEventHook', function(compilation, callback) {
        console.log("This is an example plugin!!!");
        // 功能完成后调用 webpack 提供的回调。
        callback();
      });
    };
    

    以上是编写一个插件的基本格式,关于 webpacksEventHook 可以查看文档 webpack 的 Hooks

    列举几种hooks:
    • entryOption SyncBailHook, webpack 处理完 entry 配置项后触发
    • afterPlugins SyncHook, 处理完初始化插件后触发
    • afterResolvers SyncHook, Resolve 安装完成后触发
    • environment SyncHook, environment 准备好后触发
    • emit AsyncSeriesHook, 输出文件到 output 目录之前触发
    hook的类型总结(引用一张网上的图片):
    1.png

    2、实际案例

    clean-webpack-plugin 插件大部分人应该用过,可以在构建项目时清理文件,下面来看一下 clean-webpack-plugin源码

    class CleanWebpackPlugin {
      // ...省略
      apply(compiler: Compiler) {
            if (!compiler.options.output || !compiler.options.output.path) {
                // eslint-disable-next-line no-console
                console.warn(
                    'clean-webpack-plugin: options.output.path not defined. Plugin disabled...',
                );
                return;
            }
            this.outputPath = compiler.options.output.path;
    
            /**
             * webpack 4+ comes with a new plugin system.
             *
             * Check for hooks in-order to support old plugin system
             */
            const hooks = compiler.hooks;
            if (this.cleanOnceBeforeBuildPatterns.length !== 0) {
                if (hooks) {
                    hooks.emit.tap('clean-webpack-plugin', (compilation) => {
                        this.handleInitial(compilation);
                    });
                } else {
                    compiler.plugin('emit', (compilation, callback) => {
                        try {
                            this.handleInitial(compilation);
    
                            callback();
                        } catch (error) {
                            callback(error);
                        }
                    });
                }
            }
            // ...省略
        }
    }
    

    可以看到它使用到了 emit 这个hook, 另外发现 webpack4+ 和 老版本的webpack 编写插件时的一些差异: 4+版本使用 compiler.hooks 老版本使用 compiler.plugin
    还有一些代码没有在这里展示,总体上删除文件就是调用了del.sync

    3、动手编写一个插件

    下面按照webpack官网给的例子,来实现一个插件,作用是在生成打包文件的目录额外生成一个文件,记录所有的打包文件。

    test-webpack-plugin.js :

    class TestWebpackPlugin {
      constructor(options) {
      }
    
      apply(compoiler) {
        compoiler.hooks.emit.tapAsync("TestWebpackPlugin", (compilation, cb) => {
         // 在生成文件中,创建一个头部字符串:
        var filelist = "build files:\n\n";
    
        // compilation.assets 存放所有生成的文件信息
        for (var filename in compilation.assets) {
          filelist += ("- "+ filename + "\n");
        }
    
        /* 将这个列表作为一个新的文件资源,插入到 webpack 构建中: 
         * 文件内容和文件长度需要通过source 和 size来定义
         */
        compilation.assets["filelist.md"] = {
          // 填充文件内容
          source: function() {
            return filelist;
          },
          // 文件长度
          size: function() {
            return filelist.length;
          }
        };
        cb();
        })
      }
    }
    
    module.exports = TestWebpackPlugin
    

    webpack.config.js:

    const path = require("path")
    const TestWebpackPlugin = require("./plugins/test-webpack-plugin")
    
    module.exports = {
        mode: "development",
        entry: {
            main: "./src/index.js"
        },
        output: {
            path: path.resolve(__dirname, "dist"),
            filename: "[name].[hash].js"
        },
        plugins: [
            new TestWebpackPlugin({ name: "测试参数"}) 
        ]
    }
    

    打包后dist目录多了一个文件:


    image.png

    相关文章

      网友评论

        本文标题:为webpack编写一个plugin

        本文链接:https://www.haomeiwen.com/subject/xgppxhtx.html