外掛程式是 webpack 生態系統中的關鍵部分,並提供社群一個強大的方式來利用 webpack 的編譯程序。外掛程式能夠掛勾在每次編譯中觸發的主要事件。在每個步驟中,外掛程式都可以完全存取編譯器
,並在適用的情況下存取目前的編譯
。
讓我們從介紹tapable
工具程式開始,它提供了 webpack 外掛程式介面的核心。
這個小型函式庫是 webpack 中的核心實用程式,但也可以在其他地方使用,以提供類似的外掛介面。webpack 中的許多物件都延伸了 Tapable
類別。這個類別公開了 tap
、tapAsync
和 tapPromise
方法,外掛可以使用這些方法來注入自訂的建置步驟,這些步驟會在編譯過程中觸發。
請參閱 文件 以了解更多資訊。了解三個 tap
方法以及提供它們的掛鉤至關重要。會記錄延伸 Tapable
的物件(例如編譯器)、它們提供的掛鉤以及每個掛鉤的類型(例如 SyncHook
)。
根據使用的掛鉤和套用的 tap
方法,外掛可以以不同的方式運作。這種運作方式與 Tapable
提供的 掛鉤 密切相關。編譯器掛鉤 各自記錄底層 Tapable
掛鉤,指出哪些 tap
方法可用。
因此,根據您 tap
進入哪個事件,外掛的執行方式可能不同。例如,在掛入 compile
階段時,只能使用同步 tap
方法
compiler.hooks.compile.tap('MyPlugin', (params) => {
console.log('Synchronously tapping the compile hook.');
});
但是,對於使用 AsyncHook
的 run
,我們可以使用 tapAsync
或 tapPromise
(以及 tap
)
compiler.hooks.run.tapAsync(
'MyPlugin',
(source, target, routesList, callback) => {
console.log('Asynchronously tapping the run hook.');
callback();
}
);
compiler.hooks.run.tapPromise('MyPlugin', (source, target, routesList) => {
return new Promise((resolve) => setTimeout(resolve, 1000)).then(() => {
console.log('Asynchronously tapping the run hook with a delay.');
});
});
compiler.hooks.run.tapPromise(
'MyPlugin',
async (source, target, routesList) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log('Asynchronously tapping the run hook with a delay.');
}
);
這個故事的寓意是,有各種方式可以 hook
進入 compiler
,每個方式都允許您的外掛根據需要執行。
若要提供自訂掛勾供其他外掛程式進行 tap
編譯,您需要執行下列動作
為編譯掛勾建立模組範圍的 WeakMap
const compilationHooks = new WeakMap<Compilation, MyHooks>();
interface MyHooks {
custom: SyncHook<[number, string]>;
}
在您的外掛程式上建立靜態方法
static getCompilationHooks(compilation: Compilation) : MyHooks {
let hooks = compilationHooks.get(compilation);
if(hooks === undefined) {
compilationHooks.set(compilation, hooks = {
custom: new SyncHook()
});
}
return hooks;
}
在您的外掛程式中呼叫如下掛勾
const hooks = MyPlugin.getCompilationHooks(compilation);
hooks.custom.call(1, 'hello');
其他外掛程式也可以存取您的自訂掛勾
import MyPlugin from 'my-plugin';
const hooks = MyPlugin.getCompilationHooks(compilation);
hooks.custom.tap('OtherPlugin', (n, s) => {
// magic
});
再次查看 文件,以進一步了解不同的掛勾類別及其運作方式。
外掛程式可透過 ProgressPlugin
回報進度,預設會將進度訊息列印至 stderr。若要啟用進度回報,請在執行 webpack CLI 時傳遞 --progress
參數。
可以透過傳遞不同的參數至 ProgressPlugin
的 reportProgress
函數,自訂列印輸出。
若要回報進度,外掛程式必須使用 context: true
選項tap
進入掛勾
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
函數可以使用這些參數呼叫
reportProgress(percentage, ...args);
percentage
:此參數未使用;相反地,ProgressPlugin
會根據目前的掛勾計算百分比。...args
:任意數量的字串,將傳遞至 ProgressPlugin
處理常式,以回報給使用者。請注意,只有編譯器和編譯掛勾的子集支援 reportProgress
函數。請參閱 ProgressPlugin
以取得完整清單。
自 webpack 4.37 發布以來,日誌記錄 API 已可用。當在 統計資料設定
中啟用 logging
和/或啟用 基礎架構日誌記錄
時,外掛程式可能會記錄訊息,這些訊息將以各自的記錄器格式(統計資料、基礎架構)列印出來。
compilation.getLogger('PluginName')
進行日誌記錄。這種日誌記錄會儲存在統計資料中並進行相應的格式化。使用者可以過濾和匯出它。compiler.getInfrastructureLogger('PluginName')
進行日誌記錄。使用 基礎架構
日誌記錄不會儲存在統計資料中,因此不會進行格式化。它通常會直接記錄到控制台/儀表板/GUI。使用者可以過濾它。compilation.getLogger ? compilation.getLogger('PluginName') : console
,以便在使用不支援 compilation
物件上的 getLogger
方法的舊版 webpack 時提供後備。請參閱 編譯器掛鉤 部分,以取得所有可用的 compiler
掛鉤和它們提供的參數的詳細清單。