webpack4.0各個擊破(7)—— plugin篇

webpack做爲前端最火的構建工具,是前端自動化工具鏈最重要的部分,使用門檻較高。本系列是筆者本身的學習記錄,比較基礎,但願經過問題 + 解決方式的模式,之前端構建中遇到的具體需求爲出發點,學習webpack工具中相應的處理辦法。(本篇中的參數配置及使用方式均基於webpack4.0版本javascript

一. plugin概述

1.1 Plugin的做用

plugin機制是webpack中另外一個核心概念,它基於事件流框架tapable,你能夠參考瀏覽器環境中的【DOM事件模型】【SPA模型中的生命週期鉤子】或是node環境中的【EventEmitter模塊】來理解其做用。plugin系統提供給開發者監聽webpack生命週期並在特定事件觸發時執行指定操做的能力。html

固然,要寫一個真正能實現必定功能的插件,你還須要瞭解CompilerCompilation這兩個概念,網上能夠找到很是多相關的文章(《webpack-docs/plugin》)。前端

1.2 Compiler

從表現上看,Compiler暴露了和webpack整個生命週期相關的鉤子,經過以下的方式訪問:java

//基本寫法
compiler.hooks.someHook.tap(...)
//若是但願在entry配置完畢後執行某個功能
compiler.hooks.entryOption.tap(...)
//若是但願在生成的資源輸出到output指定目錄以前執行某個功能
compiler.hooks.emit.tap(...)

webpack在重要的生命週期節點上都提供了事件鉤子,咱們能夠藉此加入一些自定義的功能。咱們來編寫一個插件,直觀地看看webpack中涉及的鉤子:node

//check-compiler-hooks-plugin.js
const pluginName = 'checkCompilerHooksPlugin';
module.exports = class checkCompilerHooksPlugin {
    apply(compiler){
        //打印出entryOption執行完畢時Compiler暴露的鉤子
        for(var hook of Object.keys(compiler.hooks)){
            console.log(hook);
        }
    }
}

能夠看到Compiler上可使用的鉤子(固然這種方式看到的鉤子和實際觸發順序無關):
webpack

注意上圖中Compiler.hooks暴露的事件鉤子中有一個compilation,下一小節將解釋它。git

1.3 Compilation

Compilation暴露了與模塊依賴有關的粒度更小的事件鉤子,官方文檔中的說法是模塊會經歷加載(loaded),封存(sealed),優化(optimized),分塊(chunked),哈希(hashed)和從新建立(restored)這幾個典型步驟,從上面的示例能夠看到,compilationCompiler生命週期中的一個步驟,使用compilation相關鉤子的通用寫法爲:github

compiler.hooks.compilation.tap('SomePlugin',function(compilation, callback){
    compilation.hooks.someOtherHook.tap('SomeOtherPlugin',function(){
        ....
    })
});

咱們仿照上面的方法就能夠查看到compilation對象上(compilation事件觸發時,在回調函數中取得的引用)暴露的事件鉤子。web

CompilerCompilation暴露的事件鉤子總數超過30個,具體信息能夠直接在官方文檔直接查詢API,在特定的階段鉤入想要添加的自定義功能。想要更好地理解plugin的做用機制,還須要瞭解webpack的整個生命週期以及事件流框架tapable.瀏覽器

二. 如何寫一個plugin

根據webpack官方文檔的說明,一個自定義的plugin須要包含:

  • 一個javascript命名函數
  • 插件函數的prototype上要有一個apply方法
  • 指定一個綁定到webpack自身的事件鉤子
  • 註冊一個回調函數來處理webpack實例中的指定數據
  • 處理完成後調用webpack提供的回調

官網給出了一個基本的結構示例:

//console-log-on-build-webpack-plugin.js
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
    apply(compiler){
        compiler.hooks.run.tap(pluginName, compilation=>{
           console.log('webpack構建過程開始'); 
        });
    }
}

將其添加到webpack插件中後能夠看到運行中觸發了傳入的回調函數:

四. 實戰

《webpack4.0各個擊破(4)——javascript & splitChunks》一文中,咱們使用splitChunks功能對初始模塊進行代碼分割,在爲多頁面應用模型的html入口插入script標籤時遇到了沒法自動插入的問題,那麼本節咱們用一個webpack-dispatch-chunk-plugin來解決一下這個問題。

處理的邏輯就是利用html-webpack-plugin暴露的更改資源標籤的事件鉤子htmlWebpackPluginAlterAssetTags來進行資源處理,此時資源已經離過模塊化和代碼分割並已經在名稱中加入了hash標記,只須要此時過濾掉名稱中含有vendors且不包含相應入口名稱的新的chunk便可,固然這只是一個基本功能,想要動態實現功能,還須要將上例中checkMap部分變爲對Compiler或是Compilation上對應屬性的引用,本篇再也不贅述。

【參考】

[1] webpack以內部運行機制》

相關文章
相關標籤/搜索