看了官網(wǎng)和一些其它技術(shù)文章,我覺(jué)得webpack插件主要搞清楚幾個(gè)問(wèn)題:1. 他用來(lái)做為什么腔呜。2叁温,什么時(shí)候做。3.怎么做核畴。
webpack做了什么
監(jiān)聽(tīng)編譯中的事件膝但,把功能嵌入到webpack的編譯流程中
功能包括很多,比如說(shuō)谤草,輸出一些信息跟束,修改文件,或者修改文件名等等丑孩。
什么時(shí)候做
借一張圖說(shuō)話冀宴。
webpack編譯流程的每一步都會(huì)觸發(fā)事件,而plugin就是處理這些事件的温学。
那么它到底包括哪些事件略贮?這需要了解webpack的構(gòu)建流程;
- 校驗(yàn)配置文件 :讀取命令行傳入或者webpack.config.js文件仗岖,初始化本次構(gòu)建的配置參數(shù)
- 生成Compiler對(duì)象:執(zhí)行配置文件中的插件實(shí)例化語(yǔ)句new MyWebpackPlugin()逃延,為webpack事件流掛上自定義hooks
- 進(jìn)入entryOption階段:webpack開(kāi)始讀取配置的Entries,遞歸遍歷所有的入口文件
- run/watch:如果運(yùn)行在watch模式則執(zhí)行watch方法轧拄,否則執(zhí)行run方法
- compilation:創(chuàng)建Compilation對(duì)象回調(diào)compilation相關(guān)鉤子揽祥,依次進(jìn)入每一個(gè)入口文件(entry),使用loader對(duì)文件進(jìn)行編譯檩电。通過(guò)compilation我可以可以讀取到module的resource(資源路徑)拄丰、loaders(使用的loader)等信息府树。再將編譯好的文件內(nèi)容使用acorn解析生成AST靜態(tài)語(yǔ)法樹(shù)。然后遞歸料按、重復(fù)的執(zhí)行這個(gè)過(guò)程奄侠, 所有模塊和和依賴分析完成后,執(zhí)行 compilation 的 seal 方法對(duì)每個(gè) chunk 進(jìn)行整理站绪、優(yōu)化遭铺、封裝webpack_require來(lái)模擬模塊化操作.
- emit:所有文件的編譯及轉(zhuǎn)化都已經(jīng)完成丽柿,包含了最終輸出的資源恢准,我們可以在傳入事件回調(diào)的compilation.assets上拿到所需數(shù)據(jù),其中包括即將輸出的資源甫题、代碼塊Chunk等等信息馁筐。
怎么做
提供一個(gè)class或原型方法,必須包含apply方法坠非,該方法只在安裝插件被Webpack compiler執(zhí)行一次
class HelloPlugin{
// 在構(gòu)造函數(shù)中獲取用戶給該插件傳入的配置
constructor(options){
}
// Webpack 會(huì)調(diào)用 HelloPlugin 實(shí)例的 apply 方法給插件實(shí)例傳入 compiler 對(duì)象
apply(compiler) {
// 在emit階段插入鉤子函數(shù)敏沉,用于特定時(shí)機(jī)處理額外的邏輯;
compiler.hooks.emit.tap('HelloPlugin', (compilation) => {
// 在功能流程完成后可以調(diào)用 webpack 提供的回調(diào)函數(shù)炎码;
});
// 如果事件是異步的盟迟,會(huì)帶兩個(gè)參數(shù),第二個(gè)參數(shù)為回調(diào)函數(shù)潦闲,在插件處理完任務(wù)時(shí)需要調(diào)用回調(diào)函數(shù)通知webpack攒菠,才會(huì)進(jìn)入下一個(gè)處理流程。
compiler.plugin('emit',function(compilation, callback) {
// 支持處理邏輯
// 處理完畢后執(zhí)行 callback 以通知 Webpack
// 如果不執(zhí)行 callback歉闰,運(yùn)行流程將會(huì)一直卡在這不往下執(zhí)行
callback();
});
}
}
module.exports = HelloPlugin;
webpack中最核心的負(fù)責(zé)編譯的Compiler和負(fù)責(zé)創(chuàng)建bundles的Compilation都是Tapable的實(shí)例辖众,可以直接在 Compiler 和 Compilation 對(duì)象上廣播和監(jiān)聽(tīng)事件,方法如下:
/**
* 廣播事件
* event-name 為事件名稱和敬,注意不要和現(xiàn)有的事件重名
*/
compiler.apply('event-name',params);
compilation.apply('event-name',params);
/**
* 監(jiān)聽(tīng)事件
*/
compiler.plugin('event-name',function(params){});
compilation.plugin('event-name', function(params){});
apply方法中插入鉤子的一般形式如下:
// compiler提供了compiler.hooks凹炸,可以根據(jù)這些不同的時(shí)刻去讓插件做不同的事情。
compiler.hooks.階段.tap函數(shù)('插件名稱', (階段回調(diào)參數(shù)) => {
});
compiler.run(callback)
Compiler 和 Compilation 的區(qū)別
Compiler 代表了整個(gè) Webpack 從啟動(dòng)到關(guān)閉的生命周期昼弟,而 Compilation 只是代表了一次新的編譯啤它,只要文件有改動(dòng),compilation就會(huì)被重新創(chuàng)建舱痘。
Compiler鉤子
https://webpack.docschina.org/api/compiler-hooks/
Compilation鉤子
https://webpack.docschina.org/api/compilation-hooks/