
Vite 插件如何用 hook filter 减少不必要的 transform【免费下载链接】viteNext generation frontend tooling. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vi/vite如果你正在开发 Vite 插件会遇到一个典型问题transform这类 hook 在开发服务器和构建时会对每一个模块请求触发而你的转换逻辑往往只关心特定扩展名或特定内容的文件。Rolldown 的 hook filter 特性让你声明“什么情况下才调用这个 hook”Vite 从 6.3.0 起支持这一特性Rollup 从 4.38.0 起支持插件作者可以用它避免不必要的 hook 调用减少 transform 开销。为什么 hook filter 能减少不必要的 transformVite 的 性能指南 指出resolveId、load和transform这三个 hook 会拖慢某些文件的加载文档给出的优化建议之一就是在做完整转换之前先判断code是否包含特定关键词、id是否匹配特定扩展名。文件 transform 得越久浏览器加载页面时的请求瀑布效应越明显。Plugin API 文档 对 hook filter 的定位与此一致Rolldown 引入该特性是为了降低 Rust 与 JavaScript 两个运行时之间的通信开销插件指定模式pattern来决定何时调用 hook从而避免不必要的 hook 调用、提升性能。也就是说没有 filter 时 hook handler 会被调用后再在 JS 侧判断有了 filter不匹配的模块在进入 handler 前就被挡掉了。给 transform hook 加 filter 的基本写法把原来写成普通函数的transform改为{ filter, handler }对象形式filter.id接受一个正则只有模块 id 匹配时 handler 才会被调用export default function myPlugin() { const jsFileRegex /\.js$/ return { name: my-plugin, // Example: only call transform for .js files transform: { filter: { id: jsFileRegex, }, handler(code, id) { // Additional check for backward compatibility if (!jsFileRegex.test(id)) return null return { code: transformCode(code), map: null, } }, }, } }这是 Plugin API 文档 中 “Hook Filters” 一节给出的示例。注意两点filter声明的是调用条件handler 里仍然保留if (!jsFileRegex.test(id)) return null这道检查。文档明确要求这样做目的是让插件向后兼容不支持 hook filter 的旧版本Rollup 4.38.0 以下、Vite 6.3.0 以下——旧版本不认filter会无条件调用 handler此时 handler 内的判断就成了唯一防线。返回null表示不做转换让文件原样继续走后续管线。同样的对象形式可以套在其他支持 filter 的 hook 上。迁移指南 中降低 Babel 装饰器成本的写法展示了按code内容过滤只有源码中包含的文件才执行这次 transformfunction decoratorPreset(options: Recordstring, unknown) { return { preset: () ({ plugins: [[babel/plugin-proposal-decorators, options]], }), rolldown: { // Only run this transform if the file contains a decorator. filter: { code: , }, }, } }用现成工具函数构造 filter手写正则容易踩坑例如想精确匹配虚拟模块 id。rolldown/pluginutils导出了exactRegex、prefixRegex等专门用于 hook filter 的工具函数rolldown/filter也转导出了它们。Plugin API 文档中的自定义文件类型转换示例const fileRegex /\.(my-file-ext)$/ export default function myPlugin() { return { name: transform-file, transform: { filter: { id: fileRegex, }, handler(src, id) { return { code: compileFileToJS(src), map: null, // provide source map if available } }, }, } }虚拟模块示例则展示resolveId和load也接受 filter用exactRegex精确匹配import { exactRegex } from rolldown/pluginutils export default function myPlugin() { const virtualModuleId virtual:my-module const resolvedVirtualModuleId \0 virtualModuleId return { name: my-plugin, resolveId: { filter: { id: exactRegex(virtualModuleId) }, handler() { return resolvedVirtualModuleId }, }, load: { filter: { id: exactRegex(resolvedVirtualModuleId) }, handler() { return export const msg from virtual module }, }, } }Windows 路径要先归一化filter 的id是拿解析后的模块 id 做匹配的这里有一个跨平台坑Vite 解析 id 时会把路径归一化为 POSIX 分隔符Windows 上保留盘符而 Rollup 默认保留 win32 分隔符\。Plugin API 文档 的 “Path Normalization” 一节建议比较路径前先归一化vite模块导出了normalizePath工具import { normalizePath } from vite normalizePath(foo\\bar) // foo/bar normalizePath(foo/bar) // foo/bar如果你的 filter 正则里出现路径片段例如匹配某个子目录下的文件先经过normalizePath再参与比较才能同时在 Windows 和其他平台正确匹配。验证 filter 是否生效文档给出的检查手段是 transform 计时日志vite --debug plugin-transform运行后观察各文件的 transform 耗时。文档提醒由于异步操作计时往往不准确这些数字只能当作粗略估计但仍然能暴露出更耗时的操作--debug是 CLI 的-d, --debug [feat]选项用于显示 debug 日志。另一个可选分支是安装vite-plugin-inspect安装方式见该插件自身的说明访问localhost:5173/__inspect/查看项目的模块和转换栈适合调试插件中间状态。限制与边界版本要求hook filter 需要 Rollup 4.38.0 或 Vite 6.3.0。低于这些版本时filter声明会被忽略所以 handler 内的兜底判断如if (!jsFileRegex.test(id)) return null不能省。计时仅供参考vite --debug plugin-transform输出的耗时受异步操作影响只能用于相对比较不能当作精确基准。filter 只决定调用时机不改变 hook 语义它不会减少匹配模块自身的转换工作只是让不匹配的模块跳过 hook handler。参考文档Plugin API — Hook Filters、Performance — Audit Configured Vite Plugins、Migration。【免费下载链接】viteNext generation frontend tooling. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vi/vite创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考