前端工具链的「Rust 化」:一场没有赢家的军备竞赛?

📅 2026/6/30 3:23:21
前端工具链的「Rust 化」:一场没有赢家的军备竞赛?
过去一年半我帮团队迁移了三个项目到 Rust 工具链。有的是部分迁移有的是全面铺开。这件事做完之后我对 Rust 工具的态度从兴奋变成了复杂——有些部分确实快得让人上瘾有些部分则让我怀念过去那个「什么都能装什么都能用」的 JS 生态。先说现状。现在每隔几周就有一个新的 Rust 原生工具冒出来Oxc 号称比 ESLint 快 100 倍Rspack 宣称构建速度是 webpack 的 10 倍Biome 说可以同时取代 ESLint 和 PrettierRolldown 则要做 Vite 的下一代打包内核。这些数字确实震撼。社区里也有声音在说不用 Rust 工具就说明你的项目落后了。但把这些工具真的塞进一个跑了两年的商业项目里事情就不那么纯粹了。Rust 工具到底快在哪先看看它们的底层运行逻辑差异。一个传统 JS 工具比如 ESLint的处理流程源码 → JavaScript 解析器Espree → AST → 遍历 规则检查 → 输出结果每一步都在 JavaScript 的事件循环里跑。几万个文件全走一遍耗时自然上去。Rust 工具比如 Oxc的流程源码 → Rust 解析器 → AST → 多线程并行遍历 规则检查 → 输出结果编译到机器码 多线程并行在纯计算场景下确实有数量级优势。这没什么好争议的。但问题在于真实的前端项目不是纯计算场景。import{defineConfig}fromvite;importvuefromvitejs/plugin-vue;importAutoImportfromunplugin-auto-import/vite;exportdefaultdefineConfig({plugins:[vue(),AutoImport({imports:[vue,vue-router]}),],});Rust 可以极快地解析这段代码但它理解不了unplugin-auto-import/vite指向哪个文件也不知道defineConfig的类型结构。这些信息存留在 Node.js 生态的模块解析链路里Rust 碰不到。所以在实际 lint 流程中Rust 工具仍然需要通过 FFI跨语言调用去问 Node.js「这个模块解析到什么位置了」「这个 TypeScript 类型的最终定义在哪」跨语言调用是有成本的。当项目依赖复杂时这个成本会吃掉 Rust 在解析阶段省下的时间。Oxc 的「100 倍」是怎么算的很多人看到「比 ESLint 快 100 倍」之后第一反应是直接全面替换。但这个 100 倍比较的是纯 lint 阶段的耗时。ESLint 慢不是因为 lint 本身慢而是它叠加了多次 AST 解析。ESLint 内部用 Espree 解析一次加上typescript-eslint/parser又用 TypeScript 编译器解析一次如果同时跑 Prettier 又是单独一次——同一个文件被反复解析了三遍。Oxc 的做法不同它用 Rust 一次性解析并缓存 AST然后让 lint、格式化、甚至代码生成共享同一份 AST。// ESLint三个环节各解析一次 // Oxc一次解析多处复用这才是真正意义上的加速而不是「换个快的语言写同样的事」。但这也引出了一个现实问题Rust 工具和现有的 JS 插件体系天然不兼容。想在 Oxc 里用eslint-plugin-vue不行。想在 Rspack 里用 webpack 的loader也不是全部兼容。在大型项目迁移中这种割裂感很要命。迁移过程中踩过的坑看一个工具不能只看它跑 demo 有多快。插件断崖我负责的一个项目用了 23 个 ESLint 插件、286 条规则。包括eslint-plugin-import、eslint-plugin-vue、eslint-plugin-unicorn还有自己写的几条自定义规则。换成 Oxc 之后不到 40% 的规则能找到等价实现。剩下的 60% 就尴尬了。要么放弃规则接受质量下降要么两条工具链并行跑那还迁移个什么劲要么用 Rust 重写自定义规则。维护 Rust 版本的自定义 lint 规则不是不能做但团队里不是每个人都愿意为了 lint 去学另一门语言。最后我选了折中方案新模块用 Oxc旧模块保留 ESLintCI 里分阶段推进。结果就是你永远不知道当前文件用的是哪套规则开发体验反而更差了。TypeScript 版本滞后Biome 和 Oxc 用的是自己实现的 TypeScript 解析器。这意味着它们对最新 TypeScript 语法的支持永远滞后于官方编译器。TypeScript 6.0 如果引入新语法tsc可以直接编译但 Biome 可能要等几周甚至几个月。对于在快速迭代的团队这种滞后会直接卡住 Rust 工具的采用决策。// TS 6.0 新语法假设constconfig{port:3000,host:localhost,}satisfies ServerConfig;// Biome/Oxc 解析器不认识这个语法// tsc正常运行不是 Rust 工具团队不努力而是追 TypeScript 的语法变化本身就是一场马拉松。CI 多架构问题本地跑得快不代表 CI 也快。我们团队的 CI runner 有三个架构x86 Linux、ARM macOS、Windows 虚拟机。Rust 工具需要为每个目标平台编译原生二进制。主流工具一般会提供预编译包但当你用的版本恰好没有你架构的预编译包时CI 会从源码编译 Rust 工具。这个过程 5-10 分钟算下来比直接用 JS 工具还慢。-name:Install Oxcrun:npm install oxlint/core# 没有预编译二进制的话这里会触发 Rust 编译# 耗时约 6 分钟在那一刻你会重新想「更快」到底是什么意思。Rust 工具不能做什么Rust 工具不会让你的业务代码变快。React 组件渲染速度、API 响应时间、数据库查询效率——这些和打包工具用 Rust 还是 JS 写的没有关系。它优化的是开发者的等待时间热更新从 2000ms 降到 200mslint 从 30 秒降到 0.5 秒打包从 2 分钟降到 10 秒。但等待时间的边际效益递减得很快。从 30 秒降到 0.5 秒确实爽再从 0.5 秒降到 50 毫秒大部分人已经感觉不到了。我跟几个团队聊过他们的反馈和「快不快」关系不大。有人介意的是 lint 报一堆他没写过的文件里的错有人不能接受构建结果和本地不一致还有人说热更新太快反而打断思路因为页面频繁重渲染。而那些真正让人头疼的问题——配置复杂、插件不兼容、迁移成本高、构建不一致——Rust 工具一个都没解决有些甚至还因为引入了新复杂性变得更糟了。那到底要不要迁移基于这一年半的实践我的判断是这样的。新建项目没有历史包袱一开始就上 Rust 工具没什么毛病。代码库特别大10 万 文件、lint 和构建已经拖慢交付的也值得认真考虑。团队愿意接受部分插件缺失、主要用 React/Vue 这类主流框架的话迁移成本相对可控。反过来老项目挂了一堆自定义 ESLint 规则、webpack loader 或插件的建议再等等。团队对现有工具链没什么强烈痛点的也没必要折腾。项目重度依赖最新 TypeScript 语法的、CI/CD 环境复杂需要支持多架构的、项目快交付了不想引入不确定性的——这些情况强行迁移大概率得不偿失。技术选型不是为了赶时髦是为了让你的团队在特定约束下获得最好的开发体验。Rust 工具到底在解决谁的问题回头看一下Oxc、Biome、Rspack 的作者都来自超大规模代码库的维护团队——Meta、字节跳动、Vercel。在这些公司lint 全量代码跑 30 分钟构建一次 10 分钟热更新卡到怀疑人生。在这个量级下Rust 工具的价值不可替代。但你的项目到这个量级了吗几百个文件构建不到 10 秒ESLint 全量检查 3 秒就跑完了——强行迁移到 Rust 工具链你感受到的可能不是「变快了」而是「那个自定义规则怎么没了」。结语五年后大多数前端项目大概率会跑在 Rust 或类似的原生工具上这一点我基本同意。效率驱动下的演化方向是清晰的。但演化需要时间也需要承认中间状态的合理性。现阶段最好的策略可能不是「全面迁移」而是「渐进采用」新模块用新工具旧模块继续跑旧工具迁移周期以月为单位而不是周。如果你的项目现在用 webpack ESLint Prettier 跑得好好的团队效率也在线你不需要因为 Rust 工具的出现而感到焦虑。最终交付给用户的是你的产品不是你的构建工具链。你觉得呢原创技术博客 · 开源项目分享 · AI全栈创作社区 idao.fun