我們經常使用到webpack的插件功能,那如何開發一個自定義的插件呢?首先創建插件比創建 loader 更加高級,webpack 插件由以下組成:
- 一個 JavaScript 命名函數。
- 在插件函數的 prototype 上定義一個 apply 方法。
- 指定一個綁定到 webpack 自身的事件鈎子。
- 處理 webpack 內部實例的特定數據。
- 功能完成后調用 webpack 提供的回調。
下面就一點點的帶你開發一個自定義的webpack plugin.
先說說webpack插件中的兩位重要人物,Compiler和Compliation
- compiler 對象代表了完整的 webpack 環境配置。這個對象在啟動 webpack 時被一次性建立,並配置好所有可操作的設置,包括 options,loader 和 plugin。當在 webpack 環境中應用一個插件時,插件將收到此 compiler 對象的引用。可以使用它來訪問 webpack 的主環境。
- compilation 對象代表了一次資源版本構建。當運行 webpack 開發環境中間件時,每當檢測到一個文件變化,就會創建一個新的 compilation,從而生成一組新的編譯資源。一個 compilation 對象表現了當前的模塊資源、編譯生成資源、變化的文件、以及被跟蹤依賴的狀態信息。compilation 對象也提供了很多關鍵時機的回調,以供插件做自定義處理時選擇使用。
基礎插件架構
///src/plugins/helloPlugin.js // 命名函數。 function HelloPlugin(options) { // 使用 options 設置插件實例…… console.log(options); } //插件函數的 prototype 上定義一個 apply 方法 HelloPlugin.prototype.apply = compiler => { //hooks compiler.hooks.done.tap('HelloPlugin', status => { console.log(status.toJson()); }) // 舊版本的相關鈎子 //compiler.plugin('done' , () => { // console.log('hello world'); //}) // 設置回調來訪問 compilation 對象: //compiler.plugin('compilation', compilation => { // 現在,設置回調來訪問 compilation 中的步驟: // compilation.plugin('optimize', () => { console.log('optimize'); //}) //}) } module.exports = HelloPlugin
//webpack.config.js const HelloPlugin = require('./src/plugins/helloPlugin') plugins: [ new HelloPlugin({options:true}) ]
這樣基礎架構就搭建完成了.
認識一下事件鈎子
生命周期鈎子函數,是由 compiler 暴露,可以通過如下方式訪問:
compiler.hooks.someHook.tap(...)
取決於不同的鈎子類型,也可以在某些鈎子上訪問 tapAsync 和 tapPromise。
例如
// 在處理來自webpack選項的entry配置后調用 compiler.hooks.entryOption.tap('HelloPlugin', (context, entry) => { console.log(1,context, entry); })
也支持自定義鈎子函數
// 自定義hook const SyncHook = require('tapable').SyncHook; // 具有 `apply` 方法…… if (compiler.hooks.myCustomHook) throw new Error('Already in use'); compiler.hooks.myCustomHook = new SyncHook(['a', 'b', 'c']) // 在你想要觸發鈎子的位置/時機下調用…… compiler.hooks.myCustomHook.call(a, b, c);
學會了webpack的事件生命周期鈎子函數,那么下面我們就開始着手寫一個webpack插件.
生成一個展示打包完成后的文件列表,ok,直接上代碼
// 命名函數。 function HelloPlugin(options) { // 使用 options 設置插件實例…… console.log(options); } //插件函數的 prototype 上定義一個 apply 方法 HelloPlugin.prototype.apply = compiler => { // 在將資產釋放到輸出目錄后調用。 compiler.hooks.emit.tapAsync('HelloPlugin', (compilation, callback) => { let fileList = `## in this build:\n\n` console.log(compilation.assets); const assets = compilation.assets for(let key in assets){ console.log(key); fileList+=`${key}\n` } compilation.assets['fileList.md'] = { source:()=>{return fileList}, size:() => {return fileList.length} } callback() }) } module.exports = HelloPlugin
看,根據不同的webpack生命周期事件鈎子函數,處理不同的邏輯,就可以完成一個webpack的plugin了,你學會了嗎?
關於深入學習請參考:
如果覺得文章不錯,可以給小編發個紅包給予鼓勵.