1. 簡介
插件向第三方開發(fā)者提供了 webpack 引擎中完整的能力。使用階段式的構(gòu)建回調(diào)洒嗤,開發(fā)者可以引入它們自己的行為到 webpack 構(gòu)建流程中。插件能夠 鉤入(hook) 到在每個編譯(compilation)中觸發(fā)的所有關(guān)鍵事件。在編譯的每一步,插件都具備完全訪問 compiler
對象的能力单寂,如果情況合適,還可以訪問當前 compilation
對象吐辙。
創(chuàng)建插件比創(chuàng)建 loader 更加高級宣决,因為你將需要理解一些 webpack 底層的內(nèi)部特性來做相應(yīng)的鉤子。
2. 創(chuàng)建插件
webpack
插件由以下組成:
- 命名的 JavaScript 函數(shù)或 JavaScript 類
- 在插件函數(shù)或類的 prototype 上定義一個
apply
方法昏苏。 - 指定一個需要綁定的 event hook尊沸。
- 處理 webpack 內(nèi)部實例的特定數(shù)據(jù)。
- 功能完成后調(diào)用 webpack 提供的回調(diào)贤惯。
// A JavaScript class.
class MyExampleWebpackPlugin {
// Define `apply` as its prototype method which is supplied with compiler as its argument
apply(compiler) {
// Specify the event hook to attach to
compiler.hooks.emit.tapAsync(
'MyExampleWebpackPlugin',
(compilation, callback) => {
console.log('This is an example plugin!');
console.log('Here’s the `compilation` object which represents a single build of assets:', compilation);
// Manipulate the build using the plugin API provided by webpack
compilation.addModule(/* ... */);
callback();
}
);
}
}
3. 基礎(chǔ)的 plugin 結(jié)構(gòu)
插件是在其原型上擁有 apply 方法的實例化對象洼专。在安裝插件時,webpack編譯器會調(diào)用這個apply方法一次孵构。apply方法有一個對底層webpack編譯器的引用屁商,它授予對編譯器回調(diào)的訪問權(quán)。一個簡單的插件結(jié)構(gòu)如下:
class HelloWorldPlugin {
apply(compiler) {
compiler.hooks.done.tap('Hello World Plugin', (
stats /* stats is passed as an argument when done hook is tapped. */
) => {
console.log('Hello World!');
});
}
}
module.exports = HelloWorldPlugin;
這里回調(diào)函數(shù)的參數(shù) stats 其實結(jié)構(gòu)如下:
然后颈墅,要安裝這個插件棒假,只需要在你的 webpack 配置的 plugin 數(shù)組中添加一個實例:
// webpack.config.js
var HelloWorldPlugin = require('hello-world');
module.exports = {
// ... configuration settings here ...
plugins: [new HelloWorldPlugin({ options: true })]
};
還可以使用' schema-utils '來驗證通過插件 options 選項傳遞的參數(shù)。這里有一個例子:
import validateOptions from 'schema-utils';
// schema for options object
const schema = {
type: 'object',
properties: {
test: {
type: 'string'
}
}
};
export default class HelloWorldPlugin {
constructor(options = {}){
validateOptions(schema, options, {
name: 'hello-world-plugin', // 報錯時精盅,輸出的插件名名稱。其他配置項參考 schema-utils 文檔
});
}
apply(compiler) {}
}
4. Compiler 和 Compilation
在插件開發(fā)中最重要的兩個資源就是 compiler 和 compilation 對象谜酒。理解它們的角色是擴展 webpack 引擎重要的第一步叹俏。
compiler
對象代表了完整的 webpack 環(huán)境配置。這個對象在啟動 webpack 時被一次性建立僻族,并配置好所有可操作的設(shè)置粘驰,包括 options屡谐,loader 和 plugin。當在 webpack 環(huán)境中應(yīng)用一個插件時蝌数,插件將收到此 compiler 對象的引用愕掏。可以使用它來訪問 webpack 的主環(huán)境顶伞。compilation
對象代表了一次資源版本構(gòu)建饵撑。當運行 webpack 開發(fā)環(huán)境中間件時,每當檢測到一個文件變化唆貌,就會創(chuàng)建一個新的 compilation滑潘,從而生成一組新的編譯資源。一個 compilation 對象表現(xiàn)了當前的模塊資源锨咙、編譯生成資源语卤、變化的文件、以及被跟蹤依賴的狀態(tài)信息酪刀。compilation 對象也提供了很多關(guān)鍵時機的回調(diào)粹舵,以供插件做自定義處理時選擇使用。
這兩個組件是任何 webpack 插件不可或缺的部分(特別是 compilation
)骂倘,因此眼滤,開發(fā)者在閱讀源碼,并熟悉它們之后稠茂,會感到獲益匪淺:
class HelloCompilationPlugin {
apply(compiler) {
// Tap into compilation hook which gives compilation as argument to the callback function
compiler.hooks.compilation.tap('HelloCompilationPlugin', compilation => {
// Now we can tap into various hooks available through compilation
compilation.hooks.optimize.tap('HelloCompilationPlugin', () => {
console.log('Assets are being optimized.');
});
});
}
}
module.exports = HelloCompilationPlugin;
有關(guān)compiler柠偶、compillation 和其他重要對象的鉤子列表,請參閱plugins API文檔睬关。
參考
writing-a-plugin
創(chuàng)建插件
api/plugins/
cn/api/plugins/
schema-utils