Webpack 自定义 Plugin 实现(构建时输出文件列表)
请手写一个自定义 Webpack Plugin,在构建完成后输出所有生成的文件名和大小到一个 summary.json 文件中。
回答
小字辈
// FileListPlugin.js
const fs = require('fs');
const path = require('path');
class FileListPlugin {
constructor(options = {}) {
this.filename = options.filename || 'filelist.json';
}
apply(compiler) {
// emit 钩子在生成资源到 output 目录之前触发
compiler.hooks.emit.tapAsync('FileListPlugin', (compilation, callback) => {
// compilation.assets 包含所有即将输出的文件
const fileList = [];
for (const [filename, asset] of Object.entries(compilation.assets)) {
fileList.push({
name: filename,
size: asset.size(),
sizeFormatted: `${(asset.size() / 1024).toFixed(2)} KB`,
});
}
// 按大小降序排列
fileList.sort((a, b) => b.size - a.size);
// 生成 summary 资源
const content = JSON.stringify({
total: fileList.length,
totalSize: fileList.reduce((sum, f) => sum + f.size, 0),
files: fileList,
timestamp: new Date().toISOString(),
}, null, 2);
// 添加到 compilation.assets 输出
compilation.assets[this.filename] = {
source: () => content,
size: () => content.length,
};
callback();
});
// done 钩子在构建完全结束后触发
compiler.hooks.done.tap('FileListPlugin', (stats) => {
console.log(`📦 文件列表已生成: ${this.filename}`);
});
}
}
module.exports = FileListPlugin;
使用:
const FileListPlugin = require('./plugins/FileListPlugin');
module.exports = {
plugins: [
new FileListPlugin({ filename: 'summary.json' }),
],
};
生命周期钩子:
compile/thisCompilation/compilation— 编译阶段make— 开始模块构建emit— 输出资源前(可修改 assets)afterEmit— 输出完成后done— 构建完成