深入了解Webpack---编写plugin

webpack plugin能够 钩入(hook) 到在每个编译(compilation)中触发的所有关键事件。在编译的每一步,插件都具备完全访问 compiler 对象的能力。使用阶段式的构建回调,开发者可以引入它们自己的行为到 webpack 构建流程中。

官方文档:

插件构成:

  • 一个 JavaScript class或JavaScript function
  • 在它的原型上定义 apply 方法=》将 `apply` 定义为其原型方法,此方法以 compiler 作为参数
  • 指定一个触及到 webpack 本身的 事件钩子=》指定要附加到的事件钩子函数
  • 操作 webpack 内部的实例特定数据。
  • 在实现功能后调用 webpack 提供的 callback。

插件流程说明:插件是由一个构造函数(此构造函数上的 prototype 对象具有 apply 方法)的所实例化出来的。这个 apply 方法在安装插件时,会被 webpack compiler 调用一次。apply 方法可以接收一个 webpack compiler 对象的引用,从而可以在回调函数中访问到 compiler 对象。

compiler compilation点击链接查看事件钩子分类):

  • Compiler 模块是 webpack 的主要引擎,它通过 CLI 传递的所有选项, 或者 Node API,创建出一个 compilation 实例。 它扩展(extend)自 Tapable 类,用来注册和调用插件。 大多数面向用户的插件会首先在 Compiler 上注册。
  • Compilation 模块会被 Compiler 用来创建新的 compilation 对象(或新的 build 对象)。 compilation 实例能够访问所有的模块和它们的依赖(大部分是循环依赖)。 它会对应用程序的依赖图中所有模块, 进行字面上的编译(literal compilation)。 在编译阶段,模块会被加载(load)、封存(seal)、优化(optimize)、 分块(chunk)、哈希(hash)和重新创建(restore)。

简单案例:插件是一个类,实现在dist文件中打包后生成一个copyright.txt文件

//copyright-webpack-plugin.js:
class CopyrightWebpackPlugin {
  constructor() {
    console.log("插件被使用了");
  }
  apply(compiler) {}
}
module.exports = CopyrightWebpackPlugin;

//webpack.config.js:
const copyrightWebpackPlugin = require("./plugins/copyright-webpack-plugin");
module.exports = {
    ...
    plugins: [new copyrightWebpackPlugin()]
}

运行结果如下:

传参:plugin的constructor函数会接受一个options参数,即插件传入的对象

 plugins: [
      new copyrightWebpackPlugin({
          name: "camille"
      })
]

//copyright-webpack-plugin.js:
 constructor(options) {
     console.log("-----options-------", options);
}

如下可以看到接收到的参数:

Tapable:tapable 这个小型 library 是 webpack 的一个核心工具,以提供类似的插件接口。webpack 中许多对象扩展自 Tapable 类。这个类暴露 tap, tapAsync 和 tapPromise 方法。Tapable 提供了 hooks 。compiler hooks 分别记录了 Tapable 内在的钩子,指出哪些 tap 方法可用。根据你触发到 tap 事件,插件可能会以不同的方式运行。

tap、tapAsync、tapPromise:apply中接收compiler,之后可以使用某些钩子通过compiler.hooks.某些钩子,之后再通过.tap触及到这些钩子。

  • tap(触及) 某些 hooks,同步的,异步钩子需使用tapAsync 方法或 tapPromise 方法。
  • tapAsync 方法 tap 插件时,需要调用 callback,此 callback 将作为最后一个参数传入函数。
  • tapPromise 方法 tap 插件时,需要返回一个 promise,此 promise 将在异步任务完成时 resolve。
//copyright-webpack-plugin.js:
class CopyrightWebpackPlugin {
  apply(compiler) {  //compiler:webpack的实例
      //compiler.hooks钩子,类似于react中的生命周期函数
      
      //一个新的编译(compilation)创建之后,钩入(hook into) compiler,同步钩子
       compiler.hooks.compile.tap("CopyrightWebpackPlugin", compilation => {
           console.log("-----compile assets-------", compilation.assets);
      });

      //emit:生成资源到 output 目录之前,异步的
      //compilation:存放的只是跟这次打包相关的所有内容,与compiler存在差异,compiler配置的内容,包括打包的所有相关内容,
      compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, callback) => {
        console.log("-----assets-------", compilation.assets);
        callback();
      })
  }
}
module.exports = CopyrightWebpackPlugin;

class HelloAsyncPlugin {
  apply(compiler) {
    compiler.hooks.emit.tapPromise('HelloAsyncPlugin', compilation => {
      // 返回一个 Promise,在我们的异步任务完成时 resolve……
      return new Promise((resolve, reject) => {
        setTimeout(function() {
          console.log('异步工作完成……');
          resolve();
        }, 1000);
      });
    });
  }
}

 运行结果如下:继上面编写的两个loader处理后,如下顺序

还可以自定义的钩子函数、Reporting Progress:prints progress messages

像compilation中有assets中,那么想知道其内都有哪些内容,在代码里console.log()查看,太麻烦,可以借助node调试工具帮助我们快速查看里的内容

node-nightly:https://webpack.docschina.org/contribute/debugging/#devtools

案例实现:

compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, callback) => {
     //输出compilation.assets查看只有main.js
     //新添加输出资源:copyright.text=》这种方式只是演示,Compilation.assets will be frozen in future, No more changes should happen to Compilation.assets after sealing the Compilation.
     compilation.assets['copyright.text'] = {
            source: function() {
                return "copyright by Camille!";
            },
            size: function(){
                return 21; //"copyright by Camille!"; 21个字节
            }
      }
      callback();
})

猜你喜欢

转载自blog.csdn.net/CamilleZJ/article/details/117172451
今日推荐