一 、區別:
前面我們介紹了webpack里面的 loader 和 plugin ,這里來回顧一下:
* loader是文件加載器,能夠加載資源文件,並對文件進行一些處理,如編譯,壓縮 等,最終一起打包到指定的文件中。
* plugin賦予了webpack各種靈活的功能,如打包優化,資源管理,環境變量,注入等,目的是為了解決loader無法實現的功能。
從整體的運行機制上來看,如下圖所示:
從上圖可以看出:
* loader運行在項目打包之前;
* plugins運行在整個項目的編譯時期;
在Webpack運行的整個生命周期中會廣播出許多事件,Plugin會監聽這些事件,在合適的事件通過 webpack 提供的 api 改變輸出結果。
對於 loader 而言,它實質上是一個轉換器,將A文件編譯成B文件,操作的是 文件 ,比如將A文件編譯成B文件,單純的是一個文件轉換過程。
二、編寫loader
在編寫 loader 之前,我們需要先理解 loader 的本質,loader 的本質是一個函數,函數中的 this 作為上下文會被 webpack 填充,因此我們不能將 loader 為一個箭頭函數。
函數接受一個參數,這個參數為 webpack 傳遞給 loader 的文件源內容。
函數中的 this 是 webpack 提供的對象,能夠獲取當前 loader 所需要的各種信息。
函數中有異步操作或者是同步操作的時候,異步操作會通過 this.callback 返回,返回值要為 string 或者 Buffer 。
代碼如下:

// 導出一個函數,source為webpack傳遞給loader的文件源內容 module.exports = function(source) { const content = doSomeThing2JsString(source); // 如果 loader 配置了 options 對象,那么this.query將指向 options const options = this.query; // 可以用作解析其他模塊路徑的上下文 console.log('this.context'); /* * this.callback 參數: * error:Error | null,當 loader 出錯時向外拋出一個 error * content:String | Buffer,經過 loader 編譯后需要導出的內容 * sourceMap:為方便調試生成的編譯后內容的 source map * ast:本次編譯生成的 AST 靜態語法樹,之后執行的 loader 可以直接使用這個 AST,進而省去重復生成 AST 的過程 */ this.callback(null, content); // 異步 return content; // 同步 }
注意:
一般在做 loader 的功能裝換的時候,保持功能單一,避免做多種功能。
三、編寫plugin
由於 webpack 基於發布訂閱模式,在運行的生命周期中會廣播出許多事件,插件會通過監聽這些事件,就可以在特定的階段執行自己的插件任務。
webpack 編譯會創建兩個核心對象:
* compiler :包含了 webpack 環境所有的 配置信息,包括了 options,loader,plugin,和 webpack 整個生命周期有關的鈎子。
* compilation: 作為 plugin 內置事件回調函數的參數,包含了當前的 模塊資源,編譯生成資源,變化的文件 以及 被 跟蹤的文件 的狀態信息,當檢測到了一個文件發生了改變的時候,就會生成一個新的 Compilation 對象。
如果要創建自己的 plugin,也需要遵循一定的規范:
* 插件必須是一個函數或者是一個包含了 apply 方法的對象,這樣才能夠訪問 Compiler 對象。
* 傳給每一個插件的 compiler 和 compilation 對象都是同一個應用,因此不建議修改。
class MyPlugin { // Webpack 會調用 MyPlugin 實例的 apply 方法給插件實例傳入 compiler 對象 apply (compiler) { // 找到合適的事件鈎子,實現自己的插件功能 compiler.hooks.emit.tap('MyPlugin', compilation => { // compilation: 當前打包構建流程的上下文 console.log(compilation); // do something... }) } }
在 emit 事件發生的時候,代表源文件的轉換和組裝已經完成,可以讀取到最終將輸出的 資源,代碼塊,模塊,依賴,並且可以修改輸出資源的內容。
轉自:https://mp.weixin.qq.com/s/U5J6nCANyKx3olFTzRVr6g