Vite+ 1.0 与 Oxlint:切换前我会先验证这些提速数据
译注:本文编译自 dev.to 文章《Vite+ 1.0 and Oxlint: The Speedup Claims I'll Test Before Switching》,作者以第一人称记录了对 VoidZero 最新进展公告的解读,以及在实际项目中切换工具链前会执行的验证步骤。原文链接见文末。
作者坦言,自己已经拖延了四个月的 lint 清理工作。原因不是难,而是每次在中等规模的 TypeScript 项目上跑带类型信息的 ESLint,都要等很久。因此,当 Evan You 在 Cloudflare 博客发布 VoidZero 四个月进展报告,并提到"在大型代码库中比 ESLint 快最多 18 倍"时,作者的第一反应是怀疑,第二反应是打开终端。
结论先行:这些数字是厂商数据,方向可信,而 Vite+ 1.0 是首次把整套基于 Rust 的 JavaScript 工具链打包在一起。作者尚未在自己的仓库上实测,因此这篇文章是对公告的解读,加上他允许这些工具接近客户项目之前会执行的具体检查。
四个月里实际交付了什么
公告列出了五项内容,它们属于不同类型的声明:
- Oxc React Compiler 编译 React 应用比 Babel 版本快 10 倍;
- Vitest 5 比 Vitest 4 快最多 50%;
- tsgolint(Oxlint 背后的类型感知引擎)已稳定,比搭配 typescript-eslint 的 ESLint 快 12 到 18 倍;
- Oxfmt 比 Prettier 快 7 倍,其 JSON、CSS、SCSS、Less、GraphQL 和 YAML 格式化器已用 Rust 重写;
- Vite+ 达到 1.0。
注意这些限定词。"最多 50%"是最好情况,"最多 18 倍"是大型代码库上的最好情况,React Compiler 的"10 倍"是编译步骤的数字,而编译时间很少是构建中最慢的部分。每一项在某个项目上都是真实的提速,但没有一项能说明在"我的项目"上会发生什么。这不是在批评 VoidZero,所有厂商都这么写。它提醒我们:由工具作者给出的基准回答的是"这能快吗",而不是"对我而言会快吗"。
作者还认可了这套技术栈的论证:Oxc 是编译器,Rolldown 是打包器,Vite 位于其上,Oxlint 和 Vitest 复用相同的部件。当某一层变快,上层就免费变快。共享解析器和共享 AST 意味着一次修复能让多个工具受益,因此作者倾向于相信这个逻辑。
最关心的部分:类型感知 lint
带类型信息的 lint 是最慢的,也是最能抓真实 bug 的:浮动的 Promise、误用的异步回调、不安全的 any 流入函数。这些都需要把 TypeScript program 放在内存里,而这正是 ESLint 加 typescript-eslint 耗时的地方。
据公告,tsgolint 支持 61 条 typescript-eslint 类型感知规则中的 59 条,且 Oxlint 可以在 lint 和类型检查之间共享同一个 TypeScript program,而不是构建两次。第二部分是作者会首先关注的,因为大多数 CI 流水线把 tsc --noEmit 和 ESLint 作为两个独立步骤运行,两者都要为解析整个项目付出代价。
公告展示的配置改动很小:
import { defineConfig } from "oxlint";
export default defineConfig({
options: {
typeAware: true,
typeCheck: true,
},
});对比作者当前的配置:一个 eslint.config.js,带指向 tsconfig 的 parser 选项、一个查了两次文档才搞懂的 project service 设置,以及一段解释为什么慢规则慢的注释。即便提速最终只有 6 倍而非 18 倍,更少的活动部件也是胜利。
不过,缺失的两条规则很重要。如果团队依赖 tsgolint 未覆盖的那两条 typescript-eslint 规则之一,就得同时运行两个 linter 一段时间。公告没有说明是哪两条,这是作者会首先去文档里确认的事。
Oxfmt 与 Prettier 之问
格式化器是个信仰话题,所以务实一点。Oxfmt 声称输出与 Prettier 兼容,迁移只需两条命令:
pnpm add -D oxfmt
pnpm oxfmt --migrate prettier
pnpm oxfmt任何 Prettier 替代品的风险都在 diff。如果输出哪怕有 0.5% 的行不同,就会产生一个巨大的格式化 commit,破坏 git blame。作者曾用 Laravel Pint 经历过一次"一个 commit 毁掉 git blame"。因此计划很无聊:在分支上跑 Oxfmt,统计改动行数,如果保留就把格式化 commit 加入 .git-blame-ignore-revs。
对作者而言,格式化器的速度是最不吸引人的收益。小项目上格式化本来就只有几秒。他会为了单一工具链而切换,而不是为了省那几秒。
Vite+ 1.0 与决策疲劳
Vite+ 打包了 Vite 8、Vitest 5、Rolldown、Oxlint、Oxfmt 和任务缓存,并替你选好了默认值。Evan You 的主张是:AI agent 和人类都在"我该用哪个 linter"上浪费时间,更少的选择意味着更快的交付。作者一半同意。
同意的一半:新项目不该在首次 commit 前就需要六个配置文件。不同意的一半:默认值很好,直到你需要偏离的那天,然后你读的是一个统一工具的文档,而不是五个知名工具的文档。作者有客户项目因框架原因锁定特定 ESLint 插件,一个"默认值很棒"的工具链帮不上忙。他会把 Vite+ 用于新项目,旧项目则按兵不动,直到有理由为止。
作者还对一种叙事持怀疑态度。公告称 2026 年的使命是让开发者的 agent 更快,因为一旦推理变快,慢的 linter 或类型检查器就成了瓶颈。这话本身没错。但如果 agent 循环花 40 秒等构建,解决办法往往是少跑一些,而不是把同样的事跑得更快。把 lint 范围限定到改动文件,胜过每次迭代都跑快 10 倍的全量 lint。更快的工具和更聪明的调用可以叠加,两者都做。
打包式开发与 React Compiler
还有两项值得一提。第一是 Bundled Dev(原 Full Bundle Mode),在开发环境使用 Vite 的生产打包器。它目前藏在实验性 flag 后面,公告称 Cloudflare 自家 dashboard 的所有内部开发者已在用它。这是个有用的数据点,因为大型 dashboard 应用正是非打包开发服务器在数千个模块请求下吃力的场景。
import { defineConfig } from "vite";
export default defineConfig({
experimental: {
bundledDev: true,
},
});第二是 Oxc React Compiler,通过 @vitejs/plugin-react 的 compiler: true 加上 oxc-transform-react 包启用。作者曾写过 React 19.3 view transitions 如何让他删掉手写的计时代码,而编译器属于同一类改动:组件里更少的手工活。他的顾虑是,编译器在正确性上的风险不同于 linter。慢的 linter 浪费时间,错误的编译输出则会发布 bug。在任何涉及金钱的项目上信任它之前,他会先跑完整测试并做视觉检查。
切换前我会跑什么
以下清单按在真实项目上的执行顺序排列,大约花一小时,是检验厂商声明的诚实方式。
第一,给当前基线计时。把现有的 lint、类型检查和测试命令各跑三次,记下中位数。没有基线,"快 18 倍"就是无法验证的数字。
for i in 1 2 3; do /usr/bin/time -f "%e s" pnpm eslint . ; done
for i in 1 2 3; do /usr/bin/time -f "%e s" pnpm tsc --noEmit ; done
for i in 1 2 3; do /usr/bin/time -f "%e s" pnpm vitest run ; done第二,在分支上用新工具做同样的事,区分冷缓存和热缓存。冷缓存数字是 CI 看到的,热缓存数字是本地看到的。第三,对比输出:同一 commit 上两个 linter 的 lint 结果,以及同一批文件上的格式化输出。一个更快但漏掉某类 bug 的工具不是胜利。第四,对照你的配置,检查 tsgolint 未覆盖的那两条类型感知规则。
如果想本周就试,挑最慢的仓库,今天跑上面的基线循环,把三个中位数记在以后找得到的地方,然后在分支上装 Oxlint 对比。作者也会在自己的项目上这么做,并更希望读者告诉他公告数字在自己那里不成立,而不是轻信他或厂商的说法。