0烫饼、基本概念
插件是webpack的支柱功能,極大地強(qiáng)化了webpack的構(gòu)建能力倘屹。
webpack 插件由以下組成:
- 一個(gè) JavaScript 命名函數(shù)拍谐。
- 在插件函數(shù)的 prototype 上定義一個(gè)
apply
方法。- 指定一個(gè)綁定到 webpack 自身的事件鉤子砍濒。
- 處理 webpack 內(nèi)部實(shí)例的特定數(shù)據(jù)赶掖。
- 功能完成后調(diào)用 webpack 提供的回調(diào)。
1锐膜、webpack Hooks
一個(gè)簡單的例子:
function MyExampleWebpackPlugin() {
};
// 在插件函數(shù)的 prototype 上定義一個(gè) `apply` 方法种远。
MyExampleWebpackPlugin.prototype.apply = function(compiler) {
// 指定一個(gè)掛載到 webpack 自身的事件鉤子。
compiler.plugin('webpacksEventHook', function(compilation, callback) {
console.log("This is an example plugin!!!");
// 功能完成后調(diào)用 webpack 提供的回調(diào)拖陆。
callback();
});
};
以上是編寫一個(gè)插件的基本格式叹誉,關(guān)于 webpacksEventHook
可以查看文檔 webpack 的 Hooks
列舉幾種hooks:
entryOption
SyncBailHook, webpack 處理完 entry 配置項(xiàng)后觸發(fā)afterPlugins
SyncHook, 處理完初始化插件后觸發(fā)afterResolvers
SyncHook, Resolve 安裝完成后觸發(fā)environment
SyncHook, environment 準(zhǔn)備好后觸發(fā)emit
AsyncSeriesHook, 輸出文件到 output 目錄之前觸發(fā)
hook的類型總結(jié)(引用一張網(wǎng)上的圖片):
1.png
2、實(shí)際案例
clean-webpack-plugin
插件大部分人應(yīng)該用過斥难,可以在構(gòu)建項(xiàng)目時(shí)清理文件暑劝,下面來看一下 clean-webpack-plugin源碼 :
class CleanWebpackPlugin {
// ...省略
apply(compiler: Compiler) {
if (!compiler.options.output || !compiler.options.output.path) {
// eslint-disable-next-line no-console
console.warn(
'clean-webpack-plugin: options.output.path not defined. Plugin disabled...',
);
return;
}
this.outputPath = compiler.options.output.path;
/**
* webpack 4+ comes with a new plugin system.
*
* Check for hooks in-order to support old plugin system
*/
const hooks = compiler.hooks;
if (this.cleanOnceBeforeBuildPatterns.length !== 0) {
if (hooks) {
hooks.emit.tap('clean-webpack-plugin', (compilation) => {
this.handleInitial(compilation);
});
} else {
compiler.plugin('emit', (compilation, callback) => {
try {
this.handleInitial(compilation);
callback();
} catch (error) {
callback(error);
}
});
}
}
// ...省略
}
}
可以看到它使用到了 emit
這個(gè)hook该溯, 另外發(fā)現(xiàn) webpack4+ 和 老版本的webpack 編寫插件時(shí)的一些差異: 4+版本使用 compiler.hooks
老版本使用 compiler.plugin
朗伶。
還有一些代碼沒有在這里展示猾漫,總體上刪除文件就是調(diào)用了del.sync悯周。
3锐墙、動(dòng)手編寫一個(gè)插件
下面按照webpack官網(wǎng)給的例子之拨,來實(shí)現(xiàn)一個(gè)插件听想,作用是在生成打包文件的目錄額外生成一個(gè)文件穴肘,記錄所有的打包文件。
test-webpack-plugin.js :
class TestWebpackPlugin {
constructor(options) {
}
apply(compoiler) {
compoiler.hooks.emit.tapAsync("TestWebpackPlugin", (compilation, cb) => {
// 在生成文件中舔痕,創(chuàng)建一個(gè)頭部字符串:
var filelist = "build files:\n\n";
// compilation.assets 存放所有生成的文件信息
for (var filename in compilation.assets) {
filelist += ("- "+ filename + "\n");
}
/* 將這個(gè)列表作為一個(gè)新的文件資源评抚,插入到 webpack 構(gòu)建中:
* 文件內(nèi)容和文件長度需要通過source 和 size來定義
*/
compilation.assets["filelist.md"] = {
// 填充文件內(nèi)容
source: function() {
return filelist;
},
// 文件長度
size: function() {
return filelist.length;
}
};
cb();
})
}
}
module.exports = TestWebpackPlugin
webpack.config.js:
const path = require("path")
const TestWebpackPlugin = require("./plugins/test-webpack-plugin")
module.exports = {
mode: "development",
entry: {
main: "./src/index.js"
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].[hash].js"
},
plugins: [
new TestWebpackPlugin({ name: "測試參數(shù)"})
]
}
打包后dist目錄多了一個(gè)文件:
image.png