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

过去一年半,我帮团队迁移了三个项目到 Rust 工具链。有的是部分迁移,有的是全面铺开。这件事做完之后,我对 Rust 工具的态度从兴奋变成了复杂------有些部分确实快得让人上瘾,有些部分则让我怀念过去那个「什么都能装什么都能用」的 JS 生态。

先说现状。现在每隔几周就有一个新的 Rust 原生工具冒出来:Oxc 号称比 ESLint 快 100 倍,Rspack 宣称构建速度是 webpack 的 10 倍,Biome 说可以同时取代 ESLint 和 Prettier,Rolldown 则要做 Vite 的下一代打包内核。

这些数字确实震撼。社区里也有声音在说:不用 Rust 工具就说明你的项目落后了。

但把这些工具真的塞进一个跑了两年的商业项目里,事情就不那么纯粹了。


Rust 工具到底快在哪

先看看它们的底层运行逻辑差异。

一个传统 JS 工具(比如 ESLint)的处理流程:

复制代码
源码 → JavaScript 解析器(Espree) → AST → 遍历 + 规则检查 → 输出结果

每一步都在 JavaScript 的事件循环里跑。几万个文件全走一遍,耗时自然上去。

Rust 工具(比如 Oxc)的流程:

复制代码
源码 → Rust 解析器 → AST → 多线程并行遍历 + 规则检查 → 输出结果

编译到机器码 + 多线程并行,在纯计算场景下确实有数量级优势。这没什么好争议的。

但问题在于真实的前端项目不是纯计算场景。

typescript 复制代码
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import AutoImport from 'unplugin-auto-import/vite';

export default defineConfig({
  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。

arduino 复制代码
// ESLint:三个环节各解析一次
// Oxc:一次解析,多处复用

这才是真正意义上的加速,而不是「换个快的语言写同样的事」。

但这也引出了一个现实问题:Rust 工具和现有的 JS 插件体系天然不兼容。

想在 Oxc 里用 eslint-plugin-vue?不行。想在 Rspack 里用 webpack 的 loader?也不是全部兼容。在大型项目迁移中,这种割裂感很要命。


迁移过程中踩过的坑

看一个工具不能只看它跑 demo 有多快。

插件断崖

我负责的一个项目用了 23 个 ESLint 插件、286 条规则。包括 eslint-plugin-importeslint-plugin-vueeslint-plugin-unicorn,还有自己写的几条自定义规则。

换成 Oxc 之后,不到 40% 的规则能找到等价实现。

剩下的 60% 就尴尬了。要么放弃规则接受质量下降,要么两条工具链并行跑(那还迁移个什么劲),要么用 Rust 重写自定义规则。维护 Rust 版本的自定义 lint 规则不是不能做,但团队里不是每个人都愿意为了 lint 去学另一门语言。

最后我选了折中方案:新模块用 Oxc,旧模块保留 ESLint,CI 里分阶段推进。

结果就是你永远不知道当前文件用的是哪套规则,开发体验反而更差了。

TypeScript 版本滞后

Biome 和 Oxc 用的是自己实现的 TypeScript 解析器。这意味着它们对最新 TypeScript 语法的支持永远滞后于官方编译器。

TypeScript 6.0 如果引入新语法,tsc 可以直接编译,但 Biome 可能要等几周甚至几个月。对于在快速迭代的团队,这种滞后会直接卡住 Rust 工具的采用决策。

typescript 复制代码
// TS 6.0 新语法假设
const config = {
  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 工具还慢。

yaml 复制代码
- name: Install Oxc
  run: npm install @oxlint/core
  # 没有预编译二进制的话,这里会触发 Rust 编译
  # 耗时约 6 分钟

在那一刻你会重新想「更快」到底是什么意思。

Rust 工具不能做什么

Rust 工具不会让你的业务代码变快。React 组件渲染速度、API 响应时间、数据库查询效率------这些和打包工具用 Rust 还是 JS 写的没有关系。

它优化的是开发者的等待时间:热更新从 2000ms 降到 200ms,lint 从 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

相关推荐
Hyyy2 小时前
Function Calling / Tool Use的原理和实现模式
前端·llm·ai编程
爱勇宝2 小时前
从 Ctrl+CV 到 Enter:程序员正在失去什么
前端·后端·程序员
徐小夕2 小时前
我们开源了一款“框架无关”的思维导图编辑器,3分钟集成到任意系统
前端·javascript·github
PBitW2 小时前
GPT训练我的第三天,明白了应该咋说满分回答!😕😕😕
前端·javascript·面试
码事漫谈2 小时前
EdgeOne Makers + WorkBuddy:零基础也能快速搭建可上线的 AI 智能体(附图文教程)
后端
像我这样帅的人丶你还3 小时前
Java 后端详解(四):分页与搜索
java·javascript·后端
她的男孩3 小时前
数据权限为什么不能只靠注解?Forge 的 Mapper 层 SQL 改写源码拆解
java·后端·架构
摸着石头过河的石头3 小时前
前端多仓库管理:从混乱到有序的进化之路
前端
星栈3 小时前
写 Dioxus Demo 不难,难的是把它写成项目
前端·rust·前端框架