Webpack中Loader和Plugin的區別和編寫思路

roc_guo發表於2021-05-19
導讀 由於webpack基於釋出訂閱模式,在執行的生命週期中會廣播出許多事件,外掛透過監聽這些事件,就可以在特定的階段執行自己的外掛任務

Webpack中Loader和Plugin的區別和編寫思路Webpack中Loader和Plugin的區別和編寫思路

一、區別

前面兩節我們有提到Loader與Plugin對應的概念,先來回顧下
Webpack中Loader和Plugin的區別和編寫思路Webpack中Loader和Plugin的區別和編寫思路
loader 是檔案載入器,能夠載入資原始檔,並對這些檔案進行一些處理,諸如編譯、壓縮等,最終一起打包到指定的檔案中
plugin 賦予了 webpack 各種靈活的功能,例如打包最佳化、資源管理、環境變數注入等,目的是解決 loader 無法實現的其他事
從整個執行時機上來看,如下圖所示:
Webpack中Loader和Plugin的區別和編寫思路Webpack中Loader和Plugin的區別和編寫思路
可以看到,兩者在執行時機上的區別:

loader 執行在打包檔案之前
plugins 在整個編譯週期都起作用
在Webpack 執行的生命週期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機透過Webpack提供的 API改變輸出結果

對於loader,實質是一個轉換器,將A檔案進行編譯形成B檔案,操作的是檔案,比如將A.scss或A.less轉變為B.css,單純的檔案轉換過程

二、編寫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的過程中,保持功能單一,避免做多種功能

如less檔案轉換成 css檔案也不是一步到位,而是 less-loader、css-loader、style-loader幾個 loader的鏈式呼叫才能完成轉換

三、編寫plugin

由於webpack基於釋出訂閱模式,在執行的生命週期中會廣播出許多事件,外掛透過監聽這些事件,就可以在特定的階段執行自己的外掛任務

在之前也瞭解過,webpack編譯會建立兩個核心物件:

compiler:包含了 webpack 環境的所有的配置資訊,包括 options,loader 和 plugin,和 webpack 整個生命週期相關的鉤子
compilation:作為 plugin 內建事件回撥函式的引數,包含了當前的模組資源、編譯生成資源、變化的檔案以及被跟蹤依賴的狀態資訊。當檢測到一個檔案變化,一次新的 Compilation 將被建立
如果自己要實現plugin,也需要遵循一定的規範:

外掛必須是一個函式或者是一個包含 apply 方法的物件,這樣才能訪問compiler例項
傳給每個外掛的 compiler 和 compilation 物件都是同一個引用,因此不建議修改
非同步的事件需要在外掛處理完任務時呼叫回撥函式通知 Webpack 進入下一個流程,不然會卡住
實現plugin的模板如下:

class MyPlugin { 
    // Webpack 會呼叫 MyPlugin 例項的 apply 方法給外掛例項傳入 compiler 物件 
  apply (compiler) { 
    // 找到合適的事件鉤子,實現自己的外掛功能 
    compiler.hooks.emit.tap('MyPlugin', compilation => { 
        // compilation: 當前打包構建流程的上下文 
        console.log(compilation); 
         
        // do something... 
    }) 
  } 
}

在 emit 事件發生時,代表原始檔的轉換和組裝已經完成,可以讀取到最終將輸出的資源、程式碼塊、模組及其依賴,並且可以修改輸出資源的內容

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2772868/,如需轉載,請註明出處,否則將追究法律責任。

相關文章