Webpack:Plugin API

2023-05-11 14:13 更新

插件是 webpack 生態(tài)的關鍵部分, 它為社區(qū)用戶提供了一種強有力的方式來直接觸及 webpack 的編譯過程(compilation process)。 插件能夠 hook 到每一個編譯(compilation)中發(fā)出的關鍵事件中。 在編譯的每個階段中,插件都擁有對 ?compiler? 對象的完全訪問能力, 并且在合適的時機,還可以訪問當前的 ?compilation? 對象。

讓我們首先從 tapable 工具開始, 它為 webpack 插件接口提供了核心能力的。

Tapable

這個小型庫是 webpack 的一個核心工具,但也可用于其他地方, 以提供類似的插件接口。 在 webpack 中的許多對象都擴展自 ?Tapable? 類。 它對外暴露了 ?tap?,?tapAsync? 和 ?tapPromise? 等方法, 插件可以使用這些方法向 webpack 中注入自定義構(gòu)建的步驟,這些步驟將在構(gòu)建過程中觸發(fā)。

請查閱文檔了解更多知識。 理解上面的的三種 ?tap? 方法, 以及提供這些方法的鉤子(hooks)對于編寫插件來說是至關重要的。 那些擴展自 ?Tapable? 的對象(例如:compiler), 以及其提供的鉤子(hooks)和每個鉤子的類型(例如:?同步鉤子(SyncHook)?)值得關注。

插件類型

根據(jù)使用不同的鉤子(hooks)和 ?tap? 方法, 插件可以以多種不同的方式運行。 這個工作方式與 Tapable 提供的鉤子(hooks)密切相關。 compiler hooks 分別記錄了 Tapable 內(nèi)在的鉤子, 并指出哪些 tap 方法可用。

所以,依賴于使用的 ?tap? 方法的不同, 插件可能會以不同的方式運行。 例如:當你鉤入到 ?編譯(compile)? 階段時,只有同步的 ?tap? 方法可以使用。

compiler.hooks.compile.tap('MyPlugin', (params) => {
  console.log('以同步方式觸及 compile 鉤子。');
});

然而,對于可以使用 ?AsyncHook? 的 ?run? 階段, 則需使用 ?tapAsync? 或 ?tapPromise?(以及 ?tap?)方法。

compiler.hooks.run.tapAsync(
  'MyPlugin',
  (source, target, routesList, callback) => {
    console.log('以異步方式觸及運行鉤子。');
    callback();
  }
);

compiler.hooks.run.tapPromise('MyPlugin', (source, target, routesList) => {
  return new Promise((resolve) => setTimeout(resolve, 1000)).then(() => {
    console.log('以異步的方式觸發(fā)具有延遲操作的鉤子。');
  });
});

compiler.hooks.run.tapPromise(
  'MyPlugin',
  async (source, target, routesList) => {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    console.log('以異步的方式觸發(fā)具有延遲操作的鉤子。');
  }
);

這些需求(story)的含義在于, 我們可以有多種方式 hook 到 compiler 中,可以讓各種插件都以合適的方式去運行。

自定義鉤子

為了便于其他插件的編譯過程中可以 ?tap? 到, 你可以這樣做:

  1. Create a module-scope ?WeakMap? for compilation hooks:
    const compilationHooks = new WeakMap<Compilation, MyHooks>();
    
    interface MyHooks {
      custom: SyncHook<[number, string]>;
    }
  2. 在插件中創(chuàng)建一個靜態(tài)方法:
    static getCompilationHooks(compilation: Compilation) : MyHooks {
      let hooks = compilationHooks.get(compilation);
      if(hooks === undefined) {
        compilationHooks.set(compilation, hooks = {
          custom: new SyncHook()
        });
      }
      return hooks;
    }
  3. 像下面這樣在你的插件中調(diào)用鉤子函數(shù):
    const hooks = MyPlugin.getCompilationHooks(compilation);
    
    hooks.custom.call(1, 'hello');
  4. 其他插件也可以訪問你的自定義鉤子函數(shù):
    import MyPlugin from 'my-plugin';
    
    const hooks = MyPlugin.getCompilationHooks(compilation);
    
    hooks.custom.tap('OtherPlugin', (n, s) => {
      // magic
    });

再次聲明, 查看 ?tapable文檔 來了解更多不同的鉤子類(hook class),以及它們是如何工作的。

進度報告

插件能夠通過 ?ProgressPlugin? 這個在默認情況下將信息打印到標準錯誤輸出(stderr)的插件來進行進度報告。如果想要使用這個功能,只需要在使用 webpack CLI 的時候傳入 ?--progress? 參數(shù)。

如果想要自定義打印輸出,只需要傳遞不同的參數(shù)到 ?ProgressPlugin? 的? reportProgress? 方法。

如果想要報告進度,插件必須在 ?tap? 到 hook 的時候使用 ?context: true? 選項。

compiler.hooks.emit.tapAsync(
  {
    name: 'MyPlugin',
    context: true,
  },
  (context, compiler, callback) => {
    const reportProgress = context && context.reportProgress;
    if (reportProgress) reportProgress(0.95, 'Starting work');
    setTimeout(() => {
      if (reportProgress) reportProgress(0.95, 'Done work');
      callback();
    }, 1000);
  }
);

?reportProgress? 方法在被調(diào)用的時候會傳入以下的參數(shù):

reportProgress(percentage, ...args);
  • ?percentage?:此參數(shù)未使用。作為代替,?ProgressPlugin? 插件會基于當前的鉤子(hook)計算進度。
  • ?...args?:任意數(shù)量的字符串,這些字符串會傳遞給 ?ProgressPlugin? 插件并報告給用戶。

注意:

只有 compiler 和 compilation 鉤子的子集才支持 ?reportProgress? 方法。

日志

日志的 API 在 webpack 4.37 版本后提供支持。當 ?logging? 在 ?統(tǒng)計配置(stats configuration)? 中可用和(或)當 ?infrastructure logging? 可用的時候,插件會通過各自的記錄格式(stats,infrastructure)打印信息。

  • 插件可以使用 ?compilation.getLogger('PluginName')? 來做記錄。這種形式的記錄保存在統(tǒng)計數(shù)據(jù)(Stats)中并做相應的格式化。它能夠被用戶過濾和導出。
  • 插件也可以使用 ?compilation.getInfrastructureLogger('PluginName')? 來做記錄。使用 ?infrastructure? 的形式并不會被保存在統(tǒng)計數(shù)據(jù)(Stats)中,因此也不會被格式化。它通常直接將記錄載入到 console/dashboard/GUI 中。它能夠被用戶過濾。
  • 插件也可以使用特殊的降級邏輯 ?compilation.getLogger? ? ?compilation.getLogger('PluginName') : console? 來檢測是否支持記錄,以此來在不支持 ?compilation.getLogger? 方法的舊版本 webpack 中提供降級方法。

下一步

查看 ?compiler hooks? 部分, 了解所有可用的? compiler? 鉤子以及它們提供的參數(shù)的詳細列表。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號