webpack原理解析(三)plugin機制

背景

在以前的文章中,咱們瞭解到了webpack的打包機制和loader,loader 用於轉換某些類型的模塊,而plugin則能夠用於執行範圍更廣的任務。包括:打包優化,資源管理,注入環境變量。插件目的在於解決 loader 沒法實現的其餘事。因此咱們頗有必要探究一下webpack的plugin機制。前端

plugin是什麼

在 Webpack 運行的生命週期中會廣播出許多事件,Plugin 能夠監聽這些事件,在合適的時機經過 Webpack 提供的 API 改變輸出結果。plugin是一個擴展器,在webpack打包的過程當中,基於事件驅動的機制,監聽webpack打包過程當中的某些節點,從而執行普遍的任務。webpack

基本插件架構

一個插件由如下構成:git

  • 一個具名 JavaScript 函數。
  • 在它的原型上定義 apply 方法。
  • 指定一個觸及到 webpack 自己的 事件鉤子。
  • 操做 webpack 內部的實例特定數據。
  • 在實現功能後調用 webpack 提供的 callback。

首先是寫一個構造函數(此構造函數上的 prototype 對象具備 apply 方法),apply 方法能夠接收一個 webpack compiler 對象的引用,從而能夠在回調函數中訪問到 compiler 對象。再就是構造方法,接收配置中傳入的options(此構造方法根據須要可寫可不寫)。github

class ReadmeWebpackPlugin {
    constructor(options) {
         console.log(options)
    }

    apply(compiler){
      
    }
}
module.exports = ReadmeWebpackPlugin;
複製代碼

插件的使用:在webpack.config.js中的plugins 數組中添加一個實例web

const ReadmetWebpackPlugin = require('./plugins/readme-webpack-plugin')
plugins:[
    new ReadmetWebpackPlugin({
      name:'hfj'
    })
  ],
複製代碼

這裏傳入了一個參數,能夠在命令行看到是能夠打印出來的。數組

compiler 和 compilation

在插件開發中最重要的兩個資源就是 compiler 和 compilation 對象。理解它們的角色是擴展 webpack 引擎重要的第一步。bash

compiler能夠理解爲一個webpack的實例,該實例存儲了webpack配置、打包過程等一系列的內容。compiler提供了compiler.hooks,在爲 webpack 開發插件時,你可能須要知道每一個鉤子函數是在哪裏調用的,具體就能夠查閱官方文檔。這裏能夠看到有不少時刻,咱們能夠根據這些不一樣的時刻去讓插件作不一樣的事情。架構

compilation 模塊會被 compiler 用來建立新的編譯(或新的構建)。該實例存放的是本次打包編譯的內容。app

事件鉤子

當咱們決定在在compiler的某個肯定的hooks寫一些事情的時候,會發現hooks裏有異步鉤子和同步鉤子,隨便舉幾個例子:異步

當爲AsyncSeriesHook時,咱們使用tapAsync來tap插件,須要注意,咱們須要調用 callback,此 callback 將做爲最後一個參數傳入函數。

當爲SyncHook時,使用tap,而且再也不須要callback。 我會把同步和異步兩種狀況寫到後邊的實戰代碼中,能夠對比看一下

實戰

如今我須要本身寫一個插件,在webpack打包結束後把一個readme.txt放到dist目錄。 首先須要知道,這是怎樣的時刻,是的,是在webpack打包結束後,生成資源到 output 目錄以前。 經過查看文檔中的complier hook。Very good!有emit這個hook!同時發現,這個emit是AsyncSeriesHook,異步的,因此記得上文提到過的,使用它的tapAsync方法,而且要回調函數。 思路已經很清晰了,代碼寫起來!

class ReadmeWebpackPlugin {
    apply(compiler){
        compiler.hooks.emit.tapAsync('ReadmeWebpackPlugin',( compilation,callback ) => {
            console.log(compilation.assets)
            compilation.assets['readme.txt'] = {
                source:function(){
                    return 'readme'
                },
                size:function(){
                    return 6
                }
            }
            callback()
        })
    }
}
module.exports = ReadmeWebpackPlugin;
複製代碼

上述代碼中打印了compilation.assets,打包後的內容有哪些是放在compilation的assets屬性中的,因此咱們能夠依照上述增長鍵值對的方式再增長一個文件。 用一下:

//webpack.config.js
...其餘配置,
 plugins:[
    new ReadmetWebpackPlugin()
  ],
複製代碼

成功:

這樣,一個咱們本身的插件就完成了。 附該項目完整地址 附該項目完整地址

總結

若是你閱讀了webpack的源碼,你會發現,webpack中有很大的篇幅是基於plugin的機制編寫的,因此能夠說plugin是webapck的核心。好在咱們已經搞懂了webpack的plugin機制,已經能夠寫本身的插件了。

關注咱們

公衆號@前端論道
相關文章
相關標籤/搜索