插件
插件通过在编译过程的不同阶段挂钩来扩展 mini-rspack 的功能。本页面记录了可用的插件以及如何创建自己的插件。
内置插件
mini-rspack 附带了一些内置插件:
EmitPlugin
EmitPlugin
生成一个包含所有资源列表的 assets.md
文件。
javascript
plugins: [
'EmitPlugin'
]
示例插件
HtmlWebpackPlugin
HtmlWebpackPlugin
生成一个包含打包 JavaScript 文件的 HTML 文件。
javascript
plugins: [
'HtmlWebpackPlugin'
]
BannerPlugin
BannerPlugin
在每个生成的文件顶部添加横幅。
javascript
plugins: [
'BannerPlugin'
]
CleanPlugin
CleanPlugin
在编译前清理输出目录。
javascript
plugins: [
'CleanPlugin'
]
创建自定义插件
您可以通过创建一个具有 apply
方法的 JavaScript 类来创建自己的插件,该方法接受一个编译器实例。
插件结构
javascript
class MyPlugin {
constructor(options) {
this.options = options || {};
}
apply(compiler) {
// 挂钩到编译器钩子
compiler.hooks.emit.tap('MyPlugin', (compilation) => {
// 修改编译
compilation.assets['my-file.txt'] = 'Generated by MyPlugin';
});
}
}
module.exports = MyPlugin;
可用钩子
mini-rspack 提供了几个插件可以挂钩的钩子:
run
:在编译开始前调用emit
:在将资源发送到输出目录之前调用done
:在编译完成时调用
示例:BannerPlugin 实现
以下是 BannerPlugin
的实现示例:
javascript
class BannerPlugin {
constructor(options) {
if (typeof options === 'string') {
this.banner = options;
} else {
this.options = {
banner: '',
entryOnly: false,
...options
};
this.banner = this.options.banner;
}
}
apply(compiler) {
// 挂钩到 emit 钩子
compiler.hooks.emit.tap('BannerPlugin', (compilation) => {
// 获取所有资源
const assets = compilation.assets;
// 遍历资源
Object.keys(assets).forEach(filename => {
// 跳过非 JavaScript 文件
if (!filename.endsWith('.js')) {
return;
}
// 如果 entryOnly 为 true 且这不是入口文件,则跳过
if (this.options && this.options.entryOnly) {
const isEntry = Object.keys(compilation.entries).some(entry =>
filename.startsWith(entry) || filename === `${entry}.js`
);
if (!isEntry) {
return;
}
}
// 获取原始源
const source = assets[filename];
// 在顶部添加横幅
const bannerComment = `/*!\n * ${this.banner}\n */\n`;
// 用新内容替换资源
compilation.assets[filename] = bannerComment + source;
});
});
}
}
module.exports = BannerPlugin;
示例:HtmlWebpackPlugin 实现
以下是 HtmlWebpackPlugin
的实现示例:
javascript
class HtmlWebpackPlugin {
constructor(options = {}) {
this.options = {
title: 'Mini Rspack App',
template: null,
filename: 'index.html',
...options
};
}
apply(compiler) {
// 挂钩到 emit 钩子
compiler.hooks.emit.tap('HtmlWebpackPlugin', (compilation) => {
// 生成 HTML 内容
const html = this.generateHtml(compilation);
// 将 HTML 文件添加到资源中
compilation.assets[this.options.filename] = html;
});
}
generateHtml(compilation) {
// 如果提供了模板,则使用它
if (this.options.template) {
const fs = require('fs');
let template = fs.readFileSync(this.options.template, 'utf8');
// 替换占位符
template = template.replace('<!-- title -->', this.options.title);
// 为所有入口点添加脚本标签
const scripts = Object.keys(compilation.assets)
.filter(asset => asset.endsWith('.js'))
.map(asset => `<script src="${asset}"></script>`)
.join('\n ');
return template.replace('<!-- scripts -->', scripts);
}
// 否则,生成一个基本的 HTML 文件
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>${this.options.title}</title>
</head>
<body>
<div id="app"></div>
${Object.keys(compilation.assets)
.filter(asset => asset.endsWith('.js'))
.map(asset => `<script src="${asset}"></script>`)
.join('\n ')}
</body>
</html>`;
}
}
module.exports = HtmlWebpackPlugin;
示例:CleanPlugin 实现
以下是 CleanPlugin
的实现示例:
javascript
class CleanPlugin {
constructor(options = {}) {
this.options = {
paths: [],
...options
};
}
apply(compiler) {
// 挂钩到 beforeRun 钩子
compiler.hooks.run.tap('CleanPlugin', () => {
const fs = require('fs');
const path = require('path');
// 从编译器选项获取输出路径
const outputPath = compiler.options.output.path;
// 如果没有提供特定路径,则清理整个输出目录
if (this.options.paths.length === 0) {
this.cleanDirectory(outputPath);
} else {
// 否则,只清理指定的路径
this.options.paths.forEach(relativePath => {
const fullPath = path.join(outputPath, relativePath);
this.cleanPath(fullPath);
});
}
});
}
cleanDirectory(directory) {
const fs = require('fs');
const path = require('path');
if (!fs.existsSync(directory)) {
return;
}
const files = fs.readdirSync(directory);
for (const file of files) {
const fullPath = path.join(directory, file);
this.cleanPath(fullPath);
}
}
cleanPath(fullPath) {
const fs = require('fs');
if (fs.existsSync(fullPath)) {
const stats = fs.statSync(fullPath);
if (stats.isDirectory()) {
// 递归清理子目录
this.cleanDirectory(fullPath);
// 删除目录本身
fs.rmdirSync(fullPath);
} else {
// 删除文件
fs.unlinkSync(fullPath);
}
}
}
}
module.exports = CleanPlugin;
使用插件
要使用插件,请将其添加到配置中的 plugins
数组中:
javascript
const { createCompiler } = require('mini-rspack');
const compiler = createCompiler({
// ...
plugins: [
'EmitPlugin',
'HtmlWebpackPlugin',
'BannerPlugin'
]
});