从 Zig 到 Rust:Bun 运行时百万行代码重写背后的工程决策与 AI 协作实践

📅 发布时间:2026/8/4 15:30:21
从 Zig 到 Rust:Bun 运行时百万行代码重写背后的工程决策与 AI 协作实践 引言2026年7月8日JavaScript 运行时 Bun 的创始人 Jarred Sumner 在官方博客发布了一篇震动前端社区的文章Bun 将从 Zig 全面重写为 Rust。这不是一次普通的语言迁移——在预发布版 Claude Fable 5 的辅助下64 个 Claude 实例并行运行 11 天编写了超过 100 万行 Rust 代码API 费用约 16.5 万美元约合 111.9 万元人民币完成了传统工程团队需要一年才能完成的工作量。这次重写的核心驱动力不是性能而是内存安全。Bun 作为 JavaScript 运行时需要在垃圾回收机制与手动内存管理之间频繁交互。Zig 缺乏构造/析构函数和所有权系统导致 use-after-free、double-free 和内存泄漏等问题反复出现。Rust 的所有权系统和借用检查器能在编译期捕获这类错误将运行时崩溃转化为编译错误——这是比风格指南和运行时检查更前置、更可靠的反馈循环。对于前端开发者而言Bun 的 CLI 月下载量已超过 2200 万次在 GitHub 上获得超过 9.1 万星标Claude Code、OpenCode 等工具将其作为运行时Vercel、Railway、DigitalOcean 提供一等公民支持。这次重写不仅关乎 Bun 自身的稳定性更标志着 AI 辅助大规模代码迁移从概念验证走向工程实践对整个 JavaScript 工具链的演进方向具有标志性意义。Bun 的技术架构与 Zig 时代的技术债Bun 的 scope 从一开始就极为庞大JavaScript/TypeScript/CSS 转译器、压缩器和打包器npm 兼容的包管理器类 Jest 的测试运行器Node.js 和 TypeScript 兼容的模块解析HTTP/1.1 和 WebSocket 客户端以及fs、net、tls等 Node.js API 实现。Jarred Sumner 在 2021 年 4 月 16 日写下第一行 Zig 代码最初版本是将 esbuild 的 JavaScript/TypeScript 转译器从 Go 逐行移植到 Zig。Zig 的低层控制能力和对性能的极致追求使一个人在一年内构建出如此庞大的项目成为可能。Sumner 在博客中坦言Zig 让 Bun 成为可能。如果不是 Zig我永远无法在一年内构建出这么多东西。截至重写前Bun 的 Zig 代码量已达 535,496 行不含注释另有约 20% 的代码用 C 编写。Bun 还嵌入了多个 C/C 库构成其运行时基座JavaScriptCoreSafari 的 JavaScript 引擎、uWebSockets 与 usocketsHTTP/WebSocket 服务器和事件循环、lshpack 与 lsquicHPACK 和 HTTP/3 库、BoringSSLGoogle 的 OpenSSL 分支以及 SQLite。技术债的核心在于JavaScript 是垃圾回收语言现代 JavaScript 引擎如 JavaScriptCore 和 V8对异常处理和垃圾回收器有严格的规则。Zig 如同 C 一样不管理内存没有构造/析构函数大部分清理工作需要在每个调用点用defer显式写出。对于 Bun 这样需要正确处理垃圾回收值和手动管理值生命周期的项目每一处内存分配都需要仔细审查这些字节在哪里释放如何确保只释放一次是否正确检查了 JavaScript 异常这个垃圾回收指针对保守栈扫描器是否可见内存安全问题的系统性拆解Bun v1.3.14 版本修复的 bug 清单揭示了问题的系统性本质。以下是一部分典型缺陷node:zlib中当异步.write()仍在线程池执行时调用.reset()导致 heap-use-after-free 崩溃node:http2中重入式 JS 回调如超时监听器内的session.request()触发哈希表 rehash使内部流指针失效UDPSocket.send()中valueOf()或toString()回调可能在载荷捕获与实际发送之间分离ArrayBuffercrypto.scrypt中输出缓冲区分配失败时回调和受保护密码/盐缓冲区永不释放tlsSocket.setSession()每次调用泄漏一个SSL_SESSION约 6.5KB因d2i_SSL_SESSION后缺少SSL_SESSION_freefs.watch()的观察者在.close()后永不被垃圾回收因引用计数下溢将每个观察者永久钉为 GC 根CSS 解析器中background-clip带有厂商前缀和多层背景时触发 double-freeMessageEvent中存在竞态条件GC 标记线程可能在并发访问时观察到撕裂的 variantBun 团队并非没有采取防御措施。他们给 Zig 编译器打了补丁以支持 Address Sanitizer每次提交都运行 ASAN 测试在 Windows 上发布 ReleaseSafe 构建使用 FuzzilliV8 和 JavaScriptCore 使用的 JavaScript 引擎模糊测试器7×24 小时模糊测试运行时 API并编写了大量端到端内存泄漏测试。这些措施比许多项目做的更多但问题的本质是fuzzing 发生在代码合并之后CI 发生在代码推送之后运行时安全检查发生在代码运行时。Sumner 直言我们的 bug 修复清单让人感觉很糟我厌倦了睡前还在担心 Bun 崩溃。对于内存生命周期管理最有效的防线是在编译期就阻止错误的发生。语言选型的工程逻辑为什么是 Rust三种语言的资源清理机制存在本质差异语言清理机制保障方式Zigdefer/errdefer显式调用依赖开发者C~Destructor、移动语义隐式调用依赖风格指南RustDroptrait编译期强制所有权系统保证Bun 团队曾考虑在 Zig 中实现 Rust 风格的智能指针来解决生命周期问题fn foo(a_ptr: SharedPtr(TCPSocket)) !void { const a: *TCPSocket a_ptr.get(); defer a_ptr.deref(); const b try do_something_with_a(a); defer b.deref(); // ... }但这比原生 Zig 代码更加笨拙fn foo(a: *TCPSocket) !void { const b try do_something_with_a(a); // ... }自制智能指针提供了比 Rust 更差的工效却不提供 Rust 的编译期保障。风格指南如 TigerBeetle 的 TigerStyle 或 Google 的 C 风格指南依赖代码审查和 linter 进行尽力而为的执行无法在编译期阻止错误。Rust 的核心优势在于Bun bug 清单中大量的 use-after-free、double-free 和错误路径中忘记释放的 bug在 safe Rust 中是编译错误。RAII 式的自动清理通过Droptrait 实现编译错误是比风格指南更好的反馈循环。Sumner 最终的判断是编译错误是比风格指南更好的反馈循环。AI 协作重写的工程方法论这次重写最引人注目的不是语言切换本身而是 AI 辅助百万行代码迁移的工程方法论。策略选择一次性重写而非增量迁移。Jarred Sumner 基于将 esbuild 转译器从 Go 移植到 Zig 的经验认为一次性重写优于增量重写。增量重写会产生期望最终被删除的临时代码短期内维护痛苦。Bun 的测试套件用 TypeScript 编写不依赖运行时的编程语言这为重写提供了语言无关的验证基础——百万断言的测试套件成为判断重写正确性的客观标尺。50 个动态工作流。重写使用了约 50 个在 Claude Code 中持续运行的动态工作流每个工作流是一个编写-审查-修复的循环// 伪代码动态工作流的核心循环 let task; while ((task todoList.pop())) { const result task(); const feedback await Promise.all([review(result), review(result)]); await apply(feedback, result); }工作流涵盖生成 Zig 到 Rust 的移植指南PORTING.md 和 LIFETIMES.tsv、机械式移植每个.zig文件到.rs文件、修复每个 crate 的编译错误、使子命令如bun test、bun build正常工作、让全部测试通过以及多轮大型重构和清理。对抗式审查Adversarial Review。这是保障 AI 生成代码质量的关键机制。审查使用分离的上下文窗口编写代码的 Claude 倾向于让代码被接受审查代码的 Claude 则被要求假设代码是错误的穷尽地寻找 bug 和不工作的原因。每个实现者配备 2 个或更多对抗式审查者——实现者不审查审查者不实现。对抗式审查在合并前捕获了多个真实 bug。例如在js_bun_spawn_bindings.rs中// 原始代码——编译通过但存在致命缺陷 for stdio in [spawned_stdout, spawned_stderr] { match stdio { StdioResult::Buffer(mut pipe) { pipe.close(Subprocess::on_pipe_close) } StdioResult::Fd(fd) fd.close(), StdioResult::Unavailable {} } }审查者发现uv_close是异步的libuv 保留原始指针直到下一个事件循环 tick然后调用on_pipe_close释放内存。但pipe是一个Box在 match 分支结束时 drop——libuv 持有已释放的内存close 回调随后再次释放。这是 use-after-free 加 double-free。修复方案// 修复leak Box 让 libuv 通过回调释放 Box::leak(pipe).close(Subprocess::on_pipe_close)另一个例子node_fs.rs中将 f64 秒数拆分为 timespec 时使用trunc()对于 1970 年之前的负数时间戳trunc()向零取整会产生负的 nsec无效 timespec改用floor()解决。重写结果与生态影响Bun v1.4.0 以 Canary 版本发布重写带来了以下量化结果指标数据修复 bug 数128 个性能提升约 2%-5%二进制体积减少 20%Rust 代码量超过 100 万行原始 Zig 代码535,496 行不含注释API 费用约 16.5 万美元耗时11 天并行 Claude 实例64 个动态工作流50 个从行业趋势看Rust 已成为 JavaScript 工具链的主导语言。Deno 从第一天起就用 Rust 构建五年来受益于 crates.io、tokio、hyper 和 swc 等成熟生态Cloudflare Workers 的运行时基于 RustTurbopack 同样使用 Rust。Bun 的加入进一步巩固了这一格局。Bun 是公开存在的最大 Zig 生产代码库也是 Zig 获得主流可见性最重要的项目。这次重写对 Zig 社区是重大信号——Hacker News 上 710 分、441 条评论的讨论中观点在早该如此和Zig 怎么办之间分裂。但正如多位评论者指出的这并非对 Zig 的否定而是表明对于以运行时为核心产品的商业公司语言选择既是性能决策也是招聘决策。Zig 在 2026 年仍处于 pre-1.0 状态标准库在次要版本间变动能立即上手的工程师池相对于 Rust 几乎可以忽略。当你在招聘上与 DenoRust、Cloudflare WorkersRust竞争时留存率和上手成本的数学计算会变得很难看。局限性与风险AI 生成代码的质量保障仍是开放问题。尽管对抗式审查和百万断言的测试套件提供了相当程度的信心但 AI 生成代码的长期可维护性、隐蔽缺陷和边缘情况覆盖仍需时间验证。Sumner 坦承他最初也不预期这次重写能成功几天后高百分比的测试套件开始通过我看到新的 Rust 代码与原始 Zig 代码库的匹配程度。我的看法从值得一试变成了我要合并这个。过渡期风险。虽然 Bun 团队承诺保持 API 兼容性现有项目无需修改代码但社区成员指出 Zig 版本缺少 LTS 支持和 CVE 修复过渡期间出现了重大 bug。部分开发者因对过渡方式的不满已回退到 Node.js。重写本身的风险。Joel Spolsky 2000 年关于不要重写代码的经典论述仍然适用。Bun 押注重写能在第二年带来团队速度的提升——新贡献者数周而非数季度上手依赖从 crates.io 获取而非手写。如果判断错误结果是两年内功能发布变慢却仍未追上 Node.js。利益相关。Anthropic 于 2025 年 12 月收购 Bun重写使用的是 Anthropic 自家的 Claude Fable 5 预发布模型。Sumner 在文章开头明确披露了这一关系。一家公司同时拥有运行时、AI 模型和重写工具的事实引发了关于生态集中度的讨论但 16.5 万美元的 API 费用对于被收购后的 Bun 团队而言并非实质负担。结论Bun 从 Zig 到 Rust 的重写是 2026 年前端工程领域最具标志性的事件之一。它同时回答了两个问题对于 JavaScript 运行时这类需要混合垃圾回收与手动内存管理的系统软件Rust 的所有权系统提供了编译期保障显著优于 Zig 的显式 defer 和自制智能指针对于百万行级别的代码迁移AI 辅助重写在结构化工作流、对抗式审查和语言无关测试套件的支撑下已从理论可能走向工程实践。这次重写也提出了新的问题当 AI 能在 11 天内完成传统团队一年的工作时软件工程的瓶颈从代码编写转移到了代码审查和测试设计。Bun 的实践表明对抗式审查和百万断言的测试套件是负责任地合并大量 AI 生成代码的必要条件。审查代码的 Claude 被要求假设代码是错的——这种对抗性思维或许正是 AI 协作开发时代最需要的工程素养。对于前端开发者短期影响为零——API 不变性能不降。长期来看一个更安全、更稳定的 Bun 运行时对整个 JavaScript 生态是积极的。而对 Zig 社区这是一次痛苦但可能必要的成长信号pre-1.0 语言在商业项目中的风险是真实的语言成熟的优先级高于任何单一项目的成功。开源仓库GitHub - wangzifan396-wzf/TW: AI 可视化实验室集 · 600 个交互式项目 · 4960 模块 · 零外部依赖 · 纯 HTML/CSS/JS SVG · 覆盖 AI/ML、CS 系统、计算理论、交叉学科全谱系 · GitHub本文由 AI 辅助生成经人工审核校对。数据来源Bun 官方博客bun.com/blog/bun-in-rust、IT之家报道2026年7月11日、top10.dev 编辑分析2026年7月9日、Hacker News 讨论。所有事实均附来源未编造数据。文中所引代码示例来自 Bun 官方博客原文。