插件 Hook 过滤器
Hook 过滤器允许 Rolldown 在调用你的插件之前,先在 Rust 端评估过滤条件,从而跳过不必要的 Rust 到 JS 调用。这提升了性能,并支持更好的并行化。更多详情请参见 为什么需要插件 Hook 过滤器。
基本用法
不要在你的 hook 内部检查条件:
export default function myPlugin() {
return {
name: 'example',
transform(code, id) {
if (!id.endsWith('.data')) {
// 提前返回
return
}
// 执行实际转换
return transformedCode
},
}
}改用带有 filter 属性的对象 hook 格式:
export default function myPlugin() {
return {
name: 'example',
transform: {
filter: {
id: /\.data$/
},
handler(code) {
// 执行实际转换
return transformedCode
},
}
}
}Rolldown 会在 Rust 端评估过滤器,并且只有在过滤器匹配时才调用你的 handler。
TIP
@rolldown/pluginutils 导出了一些用于 hook 过滤器的工具,例如 exactRegex 和 prefixRegex。
过滤器属性
除了 id 之外,你还可以基于 moduleType 和模块源码进行过滤。filter 属性的工作方式与 @rollup/pluginutils 中的 createFilter 类似。
- 如果向
include传入多个值,只要其中 任意一个 匹配,过滤器就算匹配。 - 如果过滤器同时具有
include和exclude,则exclude优先。 - 如果指定了多个过滤器属性,只有当所有指定属性都匹配时,过滤器才算匹配。换句话说,即使有一个属性未匹配,也会被排除,而不管其他属性如何。例如,下面的过滤器只有在模块文件名以
.js结尾、源码包含foo且不包含bar时才会匹配:js{ id: { include: /\.js$/, exclude: /\.ts$/ }, code: { include: 'foo', exclude: 'bar' } }
以下属性受每个 hook 支持:
resolveIdhook:idloadhook:idtransformhook:id、moduleType、code
另请参见 HookFilter。
NOTE
当你传入 string 时,id 会被视为 glob 模式;当你传入 RegExp 时,id 会被视为正则表达式。 在 resolve hook 中,id 必须是 RegExp,不允许使用 string。 这是因为 resolveId 中的 id 值是导入语句中写入的精确文本,通常不是绝对路径,而 glob 模式是用来匹配绝对路径的。
可组合过滤器
对于更复杂的过滤逻辑,Rolldown 通过 @rolldown/pluginutils 包提供了可组合的过滤表达式。这些表达式允许你使用 and、or 和 not 等逻辑运算符来构建过滤器。
WARNING
可组合过滤器尚未在 Vite 或 unplugin 中支持。它们只能用于 Rolldown 插件。
示例
import { and, id, include, moduleType } from '@rolldown/pluginutils';
export default function myPlugin() {
return {
name: 'my-plugin',
transform: {
filter: [include(and(id(/\.ts$/), moduleType('ts')))],
handler(code, id) {
// 仅在 moduleType 为 'ts' 的 .ts 文件上调用
return transformedCode;
},
},
};
}可用的过滤器函数
and(...exprs)/or(...exprs)/not(expr)— 过滤表达式的逻辑组合。id(pattern, params?)— 按 id 过滤。string模式按完全相等匹配(不是 glob);RegExp会针对 id 进行测试。importerId(pattern, params?)— 按导入者 id 过滤。string模式按完全相等匹配;RegExp会针对导入者 id 进行测试。仅可用于resolveIdhook。moduleType(type)— 按模块类型过滤(例如 'js'、'tsx' 或 'json')。code(pattern)— 按代码内容过滤。query(key, pattern)— 按查询参数过滤。include(expr)/exclude(expr)— 顶层 include/exclude 包装器。queries(obj)— 组合多个查询过滤器。
完整 API 参考请参见 @rolldown/pluginutils README。
互操作性
Rollup 4.38.0+、Vite 6.3.0+ 以及所有版本的 Rolldown 都支持插件 hook 过滤器。
支持旧版本
如果你正在编写一个需要同时支持旧版本 Rollup(< 4.38.0)或 Vite(< 6.3.0)的插件,你可以提供一个在两种环境下都能工作的回退实现。
策略是:在可用时使用带过滤器的对象 hook 格式,而在旧版本中回退到一个在内部检查条件的普通函数:
const idFilter = /\.data$/;
export default function myPlugin() {
return {
name: 'my-plugin',
transform: {
// Rolldown 和新版 Rollup/Vite 会使用该过滤器
filter: { id: idFilter },
// 当过滤器匹配时调用 handler
handler(code, id) {
// 为了兼容旧版本,在 handler 中再次检查
// 只有在你支持旧版本时才需要这样做
if (!idFilter.test(id)) {
return null;
}
// 执行实际转换
return transformedCode;
},
},
};
}这种方式可以确保你的插件:
- 在 Rolldown 和新版 Rollup/Vite 中使用过滤器以获得最佳性能
- 在旧版本中仍能正常工作(它们会对所有文件调用 handler,但内部检查可确保行为正确)
TIP
在支持旧版本时,请保持过滤器模式和内部检查同步,以避免混淆。
moduleType 过滤器
模块类型概念在 Rollup / Vite 7 及以下版本中不存在。因此,这些工具不支持 moduleType 过滤器,并且会忽略它。
