插件系统
概述
file-ud.js 提供了强大的插件系统,允许你通过非侵入式的方式扩展上传功能。所有插件都实现 IUDPlugin 接口,可以在不修改核心代码的情况下添加新功能。
插件架构
file-ud.js 的插件架构分为三层:
| 层级 | 所在包 | 职责 |
|---|---|---|
| 核心传输层 | @file-ud.js/core | 管理 Uploader / Downloader、文件队列、进度、事件、暂停、恢复、取消等核心能力 |
| 插件协议层 | IUDPlugin / PluginContext | 定义插件名称、优先级、安装、文件选择、传输前、进度、成功、失败、销毁等生命周期 |
| 插件实现层 | @file-ud.js/plugins | 提供上传插件、下载插件、通用插件,也支持业务方自定义插件 |
整体执行链路:
text
FileUD.createUploader() / FileUD.createDownloader()
↓
transfer.use(plugin)
↓
plugin.install()
↓
onFileSelect / beforeTransfer
↓
文件上传或下载
↓
onProgress
↓
onSuccess / onError
↓
destroy()包入口设计
插件按使用场景拆分子入口,避免上传项目误引下载插件,也方便打包工具做 Tree Shaking。
| 场景 | 导入路径 | 适合放置的插件 |
|---|---|---|
| 上传专用 | @file-ud.js/plugins/uploader | 文件验证、图片压缩、水印、上传前处理 |
| 下载专用 | @file-ud.js/plugins/downloader | 下载重试、下载限速、保存策略 |
| 通用能力 | @file-ud.js/plugins/retry | 上传和下载都能使用的重试能力 |
| 基类 / 类型 | @file-ud.js/plugins | BasePlugin、公共插件基础设施 |
插件上下文
插件钩子会接收 PluginContext,用于读取当前传输实例和跨插件共享数据:
| 字段 | 说明 |
|---|---|
transfer | 当前 Uploader 或 Downloader 实例 |
file | 当前正在处理的文件对象 |
config | 当前传输配置 |
shared | 插件间共享的 Map,适合传递临时处理结果 |
插件应该优先通过上下文和公开 API 工作,避免直接修改内部私有状态。需要改变文件内容时,建议在 onFileSelect 中返回新的文件对象;需要拦截上传或下载时,建议在 beforeTransfer 中返回 false。
设计理念
非侵入式扩展
- 零核心代码修改:所有功能通过插件实现
- 向后兼容:不影响现有功能和 API
- 可选启用:用户可以选择性使用插件
优先级机制
每个插件可以设置 priority(数字越小越先执行):
| 优先级区间 | 用途 | 示例 |
|---|---|---|
| 0 - 5 | 验证类插件 | FileValidatorPlugin |
| 10 - 20 | 处理类插件 | CompressImagePlugin、SmartRetryPlugin |
| 20 - 50 | 辅助类插件 | WatermarkPlugin |
安装
bash
# npm
npm install @file-ud.js/plugins
# pnpm
pnpm add @file-ud.js/plugins
# yarn
yarn add @file-ud.js/plugins
# bun
bun add @file-ud.js/plugins快速使用
ts
import { FileUD } from "@file-ud.js/core";
import {
FileValidatorPlugin,
CompressImagePlugin,
} from "@file-ud.js/plugins/uploader";
import { SmartRetryPlugin } from "@file-ud.js/plugins/retry";
const uploader = FileUD.createUploader("myUploader", {
action: "/api/upload",
});
// 注册多个插件
uploader.use([
new FileValidatorPlugin({ maxSize: 10 * 1024 * 1024 }),
new CompressImagePlugin({ quality: 0.8 }),
new SmartRetryPlugin({ maxRetries: 3 }),
]);推荐导入路径:
| 场景 | 导入路径 |
|---|---|
| 上传插件 | @file-ud.js/plugins/uploader |
| 下载插件 | @file-ud.js/plugins/downloader |
| 通用插件 | @file-ud.js/plugins/retry |
| 自定义插件基类 | @file-ud.js/plugins |
插件管理
注册实例插件
use() 只影响当前 uploader 或 downloader 实例。可以传入单个插件,也可以传入插件数组:
ts
uploader.use(new FileValidatorPlugin({ maxSize: 10 * 1024 * 1024 }));
uploader.use([
new FileValidatorPlugin({ maxSize: 10 * 1024 * 1024 }),
new CompressImagePlugin({ quality: 0.8 }),
new SmartRetryPlugin({ maxRetries: 3 }),
]);同名插件重复注册时会被跳过,插件会按 priority 从小到大执行。
卸载插件
unuse(name) 会从当前实例移除指定插件,并调用插件的 destroy() 钩子:
ts
uploader.unuse("compress-image-plugin");
uploader.unuse("SmartRetryPlugin");卸载只影响当前实例,不会修改全局默认插件配置。
查看插件
ts
const retryPlugin = uploader.getPlugin("SmartRetryPlugin");
const plugins = uploader.getPlugin();传入插件名称时返回单个插件;不传名称时返回当前实例的插件列表。
设置全局默认插件
如果项目里每个上传器都需要同一组插件,可以在创建上传器之前设置全局默认插件:
ts
import { Uploader, Downloader } from "@file-ud.js/core";
import { FileValidatorPlugin } from "@file-ud.js/plugins/uploader";
import { SmartRetryPlugin } from "@file-ud.js/plugins/retry";
Uploader.setDefaultPlugins([
new FileValidatorPlugin({ maxSize: 10 * 1024 * 1024 }),
new SmartRetryPlugin({ maxRetries: 3 }),
]);
Downloader.setDefaultPlugins([
new SmartRetryPlugin({ maxRetries: 3 }),
]);
const uploader = FileUD.createUploader("avatarUploader", {
action: "/api/upload",
});全局默认插件只会影响之后创建的实例;已经创建好的实例不会自动追加这些插件。需要清空默认插件时传入空数组:
ts
Uploader.setDefaultPlugins([]);
Downloader.setDefaultPlugins([]);执行顺序
插件按 priority 从小到大依次执行:
文件选择
↓
FileValidatorPlugin (priority: 0) → 验证文件合法性
↓
CompressImagePlugin (priority: 10) → 压缩图片
↓
WatermarkPlugin (priority: 20) → 添加水印
↓
上传开始
↓
SmartRetryPlugin (priority: 10) → 失败时自动重试
↓
上传完成内置插件
| 插件 | 优先级 | 说明 |
|---|---|---|
| 文件验证 | 0 | 验证文件大小、类型、空文件检测 |
| 图片压缩 | 10 | 智能压缩、尺寸调整、格式转换 |
| 水印 | 20 | 文字/图片水印,5 个预设位置 |
| 智能重试 | 10 | 三种重试策略,智能错误过滤 |
开发自定义插件
所有插件必须实现 IUDPlugin 接口,推荐继承 BasePlugin 基类:
ts
import { BasePlugin } from "@file-ud.js/plugins";
import type { UploadFile, PluginContext } from "@file-ud.js/core/types";
class MyPlugin extends BasePlugin {
name = "my-plugin";
priority = 50;
async onFileSelect(
file: UploadFile,
context: PluginContext
): Promise<UploadFile> {
console.log("文件已选择:", file.fileName);
return file;
}
}
uploader.use(new MyPlugin());完整开发指南参见各内置插件的源码实现。