在Webpack學習-工做原理(上)一文中咱們就已經介紹了Plugin
的基本概念,同時知道了webpack其實很像一條生產線,要通過一系列處理流程後才能將源文件轉換成咱們理想的輸出結果。而webpack構建過程當中,會在特定的時機廣播對應的事件,插件能夠監聽這些事件的發生,Plugin
在webpack構建流程中就是這樣的一個角色。同時咱們也介紹了不少整個構建流程會廣播的事件,那麼這篇文章咱們一塊兒詳細地學習一下如何編寫Plugin
。javascript
其實Plugin
本質上就是一個class,一個最基礎的Plugin
代碼以下:css
class BasePlugin {
// 構造函數,接收options配置
constructor(options) {
...
}
apply(compiler) {
// 在此處去監聽webpack廣播的全部事件
compiler.plugin('compilation', function(compilation) {
...
});
}
}
moudle.exports = BasePlugin;
複製代碼
咱們能夠再看看,webpack會怎麼配置Plugin
,java
module.exports = {
plugins: [
new BasePlugin(options)
]
}
複製代碼
咱們回憶一下,Webpack學習-工做原理(上)文章中們介紹過webpack的構建詳細流程,初始化的時候會去new Plugin()
,那麼即是會去實例化webpack配置plugins全部的插件,那麼第一步插件實例化就有了,而插件中的apply方法會在開始編譯時依次被調用,而且傳入Compiler對象(後面會深刻介紹),而後調用Compiler.run()開始編譯。webpack
- Compiler對象包含了Webpack環境全部的配置信息,包含options,loaders,plugins這些信息,這個對象在webpack啓動時被實例化,全局惟一,能夠簡單理解成就是webpack實例
- Compilation表明着一次新的編譯,包含當前的模塊資源、編譯生成的資源,變化的文件,以前咱們瞭解到compilation事件中compilation對象也會提供不少事件給插件作擴展,同時不少事件的的回調中都會將compilation傳入,以便使用
- Webpack的事件機制應用了觀察者模式,Compiler和Compilation同時繼承Taptable,因此能夠直接在Compiler和Compilation對象廣播和監聽事件,廣播事件
[Compiler | Compilation].apply('event-name', params)
,監聽事件[Compiler | Compilation].plugin('event-name', function(params){...})
,event-name不能和現有的事件重名
- 只要能拿到Compiler或是Compilation對象,就能廣播新的事件,供其餘插件使用
- Compiler或是Compilation對象爲同一個引用,一旦修改就會影響後面的插件
- 若是事件是異步的,會帶兩個參數,第二個參數爲回調函數,在插件處理完任務時須要調用回調函數通知webpack,纔會進入下一個處理流程。如:
compiler.plugin('emit',function(compilation, callback) {
// 支持處理邏輯
// 處理完畢後執行 callback 以通知 Webpack
// 若是不執行 callback,運行流程將會一直卡在這不往下執行
callback();
});
複製代碼
class Plugin {
apply(compiler) {
compiler.plugin('emit', function (compilation, callback) {
// compilation.chunks 存放全部代碼塊,是一個數組
compilation.chunks.forEach(function (chunk) {
// chunk 表明一個代碼塊
// 代碼塊由多個模塊組成,經過 chunk.forEachModule 能讀取組成代碼塊的每一個模塊
chunk.forEachModule(function (module) {
// module 表明一個模塊
// module.fileDependencies 存放當前模塊的全部依賴的文件路徑,是一個數組
module.fileDependencies.forEach(function (filepath) {
});
});
// Webpack 會根據 Chunk 去生成輸出的文件資源,每一個 Chunk 都對應一個及其以上的輸出文件
// 例如在 Chunk 中包含了 CSS 模塊而且使用了 ExtractTextPlugin 時,
// 該 Chunk 就會生成 .js 和 .css 兩個文件
chunk.files.forEach(function (filename) {
// compilation.assets 存放當前全部即將輸出的資源
// 調用一個輸出資源的 source() 方法能獲取到輸出資源的內容
let source = compilation.assets[filename].source();
});
});
// 這是一個異步事件,要記得調用 callback 通知 Webpack 本次事件監聽處理結束。
// 若是忘記了調用 callback,Webpack 將一直卡在這裏而不會日後執行。
callback();
})
}
}
複製代碼
// 當依賴的文件發生變化時會觸發 watch-run 事件
compiler.plugin('watch-run', (watching, callback) => {
// 獲取發生變化的文件列表
const changedFiles = watching.compiler.watchFileSystem.watcher.mtimes;
// changedFiles 格式爲鍵值對,鍵爲發生變化的文件路徑。
if (changedFiles[filePath] !== undefined) {
// filePath 對應的文件發生了變化
}
callback();
});
複製代碼
compiler.plugin('after-compile', (compilation, callback) => {
// 把 HTML 文件添加到文件依賴列表,好讓 Webpack 去監聽 HTML 模塊文件,在 HTML 模版文件發生變化時從新啓動一次編譯
compilation.fileDependencies.push(filePath);
callback();
});
複製代碼
// 設置 compilation.assets 的代碼以下:
compiler.plugin('emit', (compilation, callback) => {
// 設置名稱爲 fileName 的輸出資源
compilation.assets[fileName] = {
// 返回文件內容
source: () => {
// fileContent 既能夠是表明文本文件的字符串,也能夠是表明二進制文件的 Buffer
return fileContent;
},
// 返回文件大小
size: () => {
return Buffer.byteLength(fileContent, 'utf8');
}
};
callback();
});
// 讀取 compilation.assets 的代碼以下:
compiler.plugin('emit', (compilation, callback) => {
// 讀取名稱爲 fileName 的輸出資源
const asset = compilation.assets[fileName];
// 獲取輸出資源的內容
asset.source();
// 獲取輸出資源的文件大小
asset.size();
callback();
});
複製代碼
// 判斷當前配置使用使用了 ExtractTextPlugin,
// compiler 參數即爲 Webpack 在 apply(compiler) 中傳入的參數
function hasExtractTextPlugin(compiler) {
// 當前配置全部使用的插件列表
const plugins = compiler.options.plugins;
// 去 plugins 中尋找有沒有 ExtractTextPlugin 的實例
return plugins.find(plugin=>plugin.__proto__.constructor === ExtractTextPlugin) != null;
}
複製代碼
extract-text-webpack-plugin
插件進行斷點調試的截圖,能夠來看看這兩個分別打印出來的東西,通常狀況下,咱們是不須要去寫Plugin
,可是有時候咱們有些業務需求是沒有插件能夠知足的,那麼咱們便得須要本身去寫Plugin
,那瞭解Plugin
的一些相關知識點就是有必要的,咱們不必定要每一個鉤子或是API都至關熟,可是咱們須要思路,瞭解如何編寫Plugin
,也是有必要的,Plugin
中最重要的compiler和compilation,一個Plugin
插件也就是圍繞着這個去擴展,對應詳細內容能夠去webpack官網瞭解,compiler連接,compilation連接。web