编译 | 苏宓出品 | CSDNIDCSDNnews从 Zig 到 Rust知名的开源项目 Bun 完成了一次彻底的技术转向。近日JavaScript 运行时 Bun 创始人 Jarred Sumner 发布长文首次公开复盘 Bun 重写背后的全过程。这位曾长期力挺 Zig 的开发者用一篇文章详细解释了为何最终决定放弃这一语言并分享了自己一个人如何借助 Anthropic 的 Claude Fable 5 与 Claude Code仅用 11 天便完成了 53 万余行 Zig 代码向超过 100 万行 Rust 代码的迁移也借此希望能够给更多开发者一些参考。一个曾把 Zig 推向世界的人如今主动重写它如果说过去几年谁让更多开发者认识 ZigJarred Sumner 一定排得上号。Bun 最初就是一个将 esbuild 的 JavaScript 和 TypeScript 转译器从 Go 逐行移植到 Zig 的项目。2021 年 4 月 16 日Jarred Sumner 写下了自己的第一行 Zig 代码。他后来回忆称当时在 Hacker News 上看到一份单页版的 Zig Language ReferenceZig 对底层的掌控能力以及对性能的极致追求给他留下了深刻印象因此决定将 Bun 押注在 Zig 之上。从定位上看Bun 一开始的目标就远不只是一个简单的 JavaScript 运行时。Jarred Sumner 称Bun 构建之初野心就非常大其试图在一个统一工具链中覆盖 JavaScript 和 TypeScript 开发流程中的多个核心环节包括 JavaScript、TypeScript 和 CSS 的转译、压缩与打包兼容 npm 的包管理器类似 Jest 的测试运行器兼容 Node.js 与 TypeScript 的模块解析机制HTTP/1.1 和 WebSocket 客户端以及包括 fs、net、tls 在内的大量 Node.js API 实现。这个庞大的目标几乎全部由 Sumner 一人完成。按照他的回忆Bun 最初版本耗时约一年开发完成当时他还没有 LLM 工具辅助主要在奥克兰一间狭小的公寓里使用 Zig 完成了整个项目。Sumner 认为对于这样一个野心庞大的个人项目最终陷入 GitHub 个人主页中“废弃项目的墓地”才是更常见的结局。而 Zig 的出现让 Bun 成为了可能。“如果没有 Zig我不可能在一年时间里完成这么多工作。”随着时间推移如今的 Bun 已经从一个个人开发项目成长为被广泛采用的 JavaScript 工具链。其命令行工具每月下载量超过 2200 万次包括 Claude Code、OpenCode 在内的热门开发工具都选择将 Bun 作为运行时。同时Vercel、Railway、DigitalOcean 等云平台也已经提供了对 Bun 的官方支持。不过Bun 追求“大而全”的设计理念也带来了长期稳定性的挑战。随着功能不断扩展项目复杂度持续上升如何维护一个覆盖运行时、工具链和 Node.js 兼容层的庞大系统成为 Bun 后续发展中必须面对的问题。为什么放弃 Zig在最新发布的博客中Jarred Sumner 并没有否定 Zig。相反他表示如果时间回到 2022 年自己依然会选择 Zig 作为 Bun 的底层语言。在 Bun 早期发展阶段Zig 确实展现出了明显优势。它拥有优秀的 C 语言互操作能力、简洁直接的语言设计以及接近 C/C 的底层控制能力这些特性帮助 Bun 快速搭建起一个高性能 JavaScript 运行时。但随着 Bun 规模不断扩大问题也逐渐暴露出来。Sumner 回忆称随着代码量增长团队不得不投入越来越多精力处理内存泄漏、生命周期管理以及各种底层稳定性问题。大量 Bug 修复任务不断累积甚至影响到了开发者的日常状态。他坦言“层出不穷的 Bug 修复清单让我身心俱疲每晚睡前都会担心 Bun 是否会出现运行崩溃。”更关键的是这些问题并不是单纯依靠更加严格的编码规范就能够完全避免。即便团队进行了大量代码审查底层内存安全问题依然可能出现。因此Sumner 开始重新评估 Bun 的技术路线是否应该选择一门能够从语言层面减少这类问题的语言。C/C 能否成为替代方案事实上C 曾经是一个看似合理的选择。目前 Bun 约有 20% 的代码采用 C 编写同时项目内部也大量依赖 C/C 生态中的成熟组件包括用于支撑 Safari 的 JavaScript 引擎 JavaScriptCore、提供 HTTP/WebSocket 能力的 uWebSockets 与 usockets、实现 HPACK 和 HTTP/3 的 lshpack 与 lsquic、Google 基于 OpenSSL 开发的 BoringSSL以及 SQLite 等。因此如果选择 C 重构 Bun并非完全从零开始。Sumner 认为C 甚至能够带来一些便利。例如开发者可以直接使用构造函数和析构函数管理资源同时减少大量 extern C 的封装代码。但问题在于C 依然无法从根本上解决内存安全挑战。即便团队采用更加严格的代码审查流程制定编码规范并开启 AddressSanitizerASAN等检测工具内存越界、资源释放错误以及内存泄漏等问题仍然可能发生。最终C 并没有成为 Bun 的答案。而这也成为 Sumner 转向 Rust 的重要原因之一相比依赖工程规范和人工审查Rust 希望通过编译器和所有权模型在代码运行之前就阻止大量潜在错误。为什么选择 Rust此前困扰 Bun 的大量问题主要集中在内存安全领域包括 use-after-free释放后使用、double-free重复释放以及异常分支中遗漏资源释放等情况。而在 Rust 的安全子集中这类问题通常会在编译阶段直接被阻止。Rust 通过所有权、借用检查器以及 Drop 机制实现类似 RAII 的自动资源管理让许多潜在错误在代码运行前就暴露出来。相比依靠团队制定编码规范、进行人工 Code Review 来降低风险Rust 编译器提供了一种更加严格且强制的约束方式。但对于 Bun 这样的成熟项目而言迁移到另一门语言并不是一个简单决定。据 Sumner 介绍剔除注释后Bun 现有 Zig 代码规模约为 53.5 万行。如果依靠一个小型工程团队手动完成语言迁移预计需要整整一年时间。而在这一年里Bug 修复、安全补丁以及新功能开发都将受到影响。因此他们团队认为想要以最低风险完成迁移最合理的方案并不是重新设计代码而是进行一次“机械式移植”——尽可能保持原有逻辑不变最大程度复用现有测试体系通过测试结果验证迁移后的代码是否可靠。幸运的是Bun 自身拥有一套基于 TypeScript 构建的完整测试体系并不依赖底层运行时采用何种编程语言这也为迁移提供了重要基础。然而完全暂停开发一年并不是现实选择。Sumner 表示最初团队考虑过另一条路线继续使用 Zig通过更加严格的编码规范约束内存安全问题同时在代码库中加入借鉴 Rust 思想设计的自研智能指针。但这一方案并没有让他满意。在 Sumner 看来自研智能指针无论是开发体验还是安全保障都无法达到 Rust 的水平。相比重新造一套内存管理机制直接采用一门已经经过多年验证的系统级语言似乎更加合理。就在这个过程中他产生了一个大胆设想“为什么不花一周时间测试一下 Anthropic 最新的大模型看看它能否把 Bun 完整重写成 Rust”最初Sumner 对这一想法并没有抱太大期待。但实验开始后情况很快发生变化。几天之后大量测试用例已经能够正常通过而 AI 生成的 Rust 代码与原有 Zig 实现之间也展现出了较高的一致性。这让 Sumner 的想法发生了转变。最开始他只是希望验证“AI 是否能够完成这项任务”但随着迁移结果逐渐稳定最终决定直接合并这套由 AI 辅助完成的 Rust 重构代码。借助 Claude用 Rust 重写 Bun迁移伊始Sumner 认为这类大型重构存在大量容易踩坑的做法。例如直接向模型输入一句“将 Bun 改写成 Rust并确保不会出现任何问题”然后期待 AI 一次性完成整个项目这并不是可靠方案。在他的设想中AI 辅助重构需要遵循类似人工迁移的工程方法核心需要解决两个问题是渐进式重构还是一次性全量迁移以及如何保证迁移后的 Bun 与原版本保持一致。对于迁移方式Sumner 最终选择了一次性全量移植。他回忆称最初开发 Bun 时自己曾经手动将 esbuild 的 JavaScript/TypeScript 转译器从 Go 迁移到 Zig而且整个过程没有使用任何大语言模型。根据此前经验一次性完成完整迁移往往比渐进式重构效果更好。原因在于渐进式重构通常会产生大量临时代码。这些代码虽然能够帮助项目逐步过渡但随着时间推移团队还需要不断清理历史包袱最终导致代码结构更加复杂长期维护体验下降。因此在 Bun 从 Zig 迁移到 Rust 的过程中团队决定采用更加直接的方式尽可能保持原有逻辑不变将 Zig 代码转换为 Rust 实现。另一个关键问题是如何保证 Rust 版本 Bun 与原版本在架构、性能和功能上保持一致同时又能够利用 Rust 的核心安全特性例如借用检查器。最终Sumner 确定了一个相对保守的方案先按照“Zig 直译 Rust”的方式完成迁移再逐步优化代码。也就是说第一阶段的目标不是写出最优雅的 Rust而是确保 Rust 版本能够完整替代原有 Zig 版本。等 Bun v1.4 发布后再逐步减少 unsafe 代码块将部分实现改写成更加符合 Rust 语言习惯的形式。在 Sumner 看来迁移过程真正需要解决的核心问题只有这两个其余更多属于工程执行细节。11 天完成全量迁移Claude Code 组成 50 套动态工作流为了执行这项大规模迁移Sumner 并没有让 Claude 单独完成任务而是在 Claude Code 中搭建了一套循环式代码生成与审核流程。他认为软件工程师日常开发本质上就是一个循环提出任务 → 编写代码 → 接受反馈 → 修改代码 → 再次验证。此次 Bun Rust 重构也是按照类似方式运行。在 Claude Code 中Sumner 创建了约 50 套动态工作流持续运行 11 天完成整个代码库迁移。这些工作流覆盖多个阶段首先Claude 需要生成迁移指南建立 Zig 语法、类型系统与 Rust 之间的映射规则。随后根据 PORTING.md 和 LIFETIMES.tsv 等文档将全部 .zig 文件机械转换为 .rs 文件。之后系统持续处理 Rust 编译错误让各个 crate 逐步恢复正常运行并确保 bun test、bun build 等核心命令能够工作。最后通过完整测试套件验证迁移结果并进行多轮代码重构和清理。整个过程中Sumner 并不是完全放手让 AI 自动运行而是持续监控工作流状态。当出现异常时他会人工查看日志定位问题再调整 Claude 的执行流程让模型重新处理错误。当然对于一次新增数十万行甚至百万级规模代码的 Pull Request很多人最大的疑问是如何确保 AI 生成的代码值得信任Sumner 给出的答案是测试体系 对抗式代码评审。Bun 原本就拥有一套与底层实现语言无关的测试体系其中包含百万级断言可以持续验证 Rust 版本是否保持原有行为。但仅靠测试仍然不足。因此他引入了一套类似人工软件开发流程中的“代码作者”和“代码审查者”分离机制。在传统开发中代码作者和代码审查者通常是两个人。原因在于代码编写者往往希望自己的实现能够尽快合并容易忽略自身代码中的问题而独立审查者则会站在怀疑角度寻找潜在漏洞。Sumner 认为Claude 同样存在类似倾向。因此在 Bun Rust 重构过程中他采用了“生成 Claude 对抗评审 Claude”的模式一个 Claude 负责生成代码至少两个 Claude 负责独立审查。审查模型不会看到生成过程只能读取代码 Diff并默认代码存在缺陷任务就是寻找可能导致 Bug、逻辑失效或者性能退化的问题。最终生成端和评审端形成相互制约。这一机制并非理论设计而是在实际迁移过程中发现了真实问题。其中一个典型案例来自异步关闭句柄问题。Claude 生成的 Rust 代码能够正常编译逻辑表面上也没有明显错误但评审模型发现代码可能导致 use-after-free 和 double-free。问题源于 libuv 的异步关闭机制。当调用 uv_close 时libuv 并不会立即释放句柄而是等待后续事件循环触发回调完成清理。但 Rust 中 Box 包裹的对象会在作用域结束时自动析构释放。这意味着libuv 可能继续访问已经被释放的内存从而引发崩溃。最终团队通过调整代码让对象生命周期延长避免异步回调访问失效内存。Sumner 表示这类问题正是传统代码审查容易遗漏而 Rust 编译器和对抗式 AI 审查能够帮助发现的问题。在整个迁移过程中对抗评审提前发现了多类真实 Bug包括异步资源释放问题、负数时间戳处理问题等。这些代码在编译阶段没有任何错误功能测试初期也未必能够暴露问题但经过独立 Claude 审查后被提前拦截。对于 Sumner 而言这次 Bun Rust 重构最大的变化并不只是“AI 写了大量代码”而是软件工程流程本身发生了变化AI 不再只是代码生成工具而成为参与迁移、测试和审查的大规模工程协作者。全流程复盘不容忽视的是此次迁移并非是几句提示词的事Sumner 在这次迁移过程中做了大量的工作详细来看前置筹备制定统一移植规范在正式生成代码前Sumner 投入 3 小时与 Claude 深度对齐 Zig 到 Rust 的语法、类型映射规则由模型输出标准化移植文档PORTING.md这份文档后续也发布至 Hacker News https://news.ycombinator.com/item?id48016880公开分享。项目最大难点在于原有 Zig 代码混合手动内存管理与 GC 内存原生无 Rust 生命周期标注体系。为此Sumner 搭建专属动态工作流让 AI 逐文件遍历全部结构体字段梳理完整控制流推导适配 Rust 的生命周期参数。每组生命周期方案都会交由两组独立对抗评审模型校验修正冲突标注后统一归档为LIFETIMES.tsv作为后续所有代码转换的统一标准Sumner 本人也人工复核两份核心文档消除规则漏洞。小规模试点移植验证 AI 转换与对抗评审机制可行性为避免大规模转换出现批量逻辑偏差Sumner 先选取3个.zig文件开展试点。单文件分配 1 个 AI 模型负责生成对应.rs代码2 组独立对抗评审模型对照移植规范校验代码逻辑一致性最后由修复模型统一落地评审修改意见。试点阶段验证了核心质控手段——对抗式代码评审的有效性评审 AI 仅能读取代码 diff无法查看代码生成模型的推导上下文且被强制预设代码存在缺陷穷尽挖掘潜在内存崩溃、逻辑退化问题提前拦截编译正常但存在隐性缺陷的代码。批量全量代码迁移解决多实例命令冲突并行生成百万行代码项目总计需要转换 1448 个 Zig 源码文件初期执行出现多 Claude 实例并发执行 git 操作冲突stash、reset 等指令互相覆盖修改内容若为每个 AI 分配独立工作区Bun 庞大的代码仓库又会耗尽磁盘存储空间。Sumner 随即更新工作流约束规则禁止执行任何临时修改类 git 命令、禁用 cargo 等高耗时阻塞指令仅允许单次提交指定文件。后续拆分 4 套独立并行工作分片每套分配 16 个 Claude 同步运行总计 64 个 AI 并行作业。峰值状态下 AI 每分钟可产出 1300 行代码每一行代码都经过两名独立对抗评审校验完成一轮修复后才允许提交。11 天运行累计生成 6502 次有效提交峰值单小时提交量 695 次。批量修复编译报错拆分 Crate 并行处理化解循环依赖阻碍百万行代码生成完毕后Sumner 搭建工作流以单个 crate 为单位批量处理编译报错通过cargo check汇总全部错误并按文件分组分配 64 个 AI 分摊修复任务依旧沿用“1生成2评审1落地修复”的固定循环。原有 Zig 代码为单一编译单元Sumner 计划拆分近百个 Rust crate 加速编译但拆分方案前期存在缺陷大量循环依赖引发约 16000 条编译错误。其团队也开始新增专项工作流梳理循环依赖代码归属、完成模块重构彻底扫清编译障碍。整个过程中出现了 AI 为绕过报错填充占位 stub、添加大段冗余注释掩盖不合理兼容逻辑的问题Sumner 为对抗评审新增拦截规则若需要长篇注释解释临时兼容方案判定代码存在根本性缺陷必须重构而非临时占位最终这一问题在调整提示词后彻底解决。分层测试流水线从冒烟测试到本地全量用例全覆盖编译无报错后项目分阶段推进测试验证1. 基础烟雾测试优先实现bun --version正常编译运行解决链接错误、程序启动 panic2. 子命令适配工作流逐个修复bun test、bun build等CLI子命令运行崩溃捕获堆栈交由AI迭代修复3. 全量本地测试分片执行按代码目录拆分 4 个工作区随机分配百条测试用例并行执行捕获失败用例自动走AI修复评审流程。Bun 测试套件包含海量内存泄漏检测、长耗时集成测试、极限压力测试部分用例运行时长超一分钟还会耗尽 TCP 连接、读写 GB 级文件、创建上万子进程。Bun 团队借助systemd-runcgroups做 CPU、内存、PID 命名空间隔离但服务器仍多次因磁盘占满宕机拉长了整个测试周期。CI 全平台适配收尾完成分支合并首轮 CI 流水线执行时共有 972 个测试文件运行失败。经过两天的运行失败的测试文件数量缩减至 23 个再经过一天半调试Linux 平台所有测试分片全部绿灯。项目覆盖 macOS x64/arm64、Linux x64/arm64、Windows x64/arm64 六大平台Windows 适配难度最高比 Linux 晚近一天完成全量用例通过。收尾阶段持续运行自动化工作流循环修复各平台剩余 CI 失败用例配套专项工作流处理 Windows 专属兼容、代码去重、削减 unsafe 代码块、整体代码清理。在全部平台 100% 测试通过且人工核验所有用例无跳过、正常执行后Sumner 正式将百万行 Rust 重构代码合并至主分支。本次合并仅完成代码落地并未对外发布正式版本留足迭代优化周期。Rust 版的 Bun从数据层面来看整个重构周期为 5 月 3 日至 5 月 14 日共计 11 天。峰值 4 套工作流、64 个 Claude 并行运行。移植阶段累计 4416 次提交一分钟峰值 58 次提交新增改写代码合计 1430577 行最终合并入库变更量 1009272 行全程无任何测试用例删除或跳过。资源消耗层面合并前累计消耗未缓存输入token 59 亿、输出 token 6.9 亿缓存读取输入 token 720 亿按官方 API 定价折算成本约 16.5 万美元。最终完成 Rust 重构后的 Bun v1.4.0 针对性修复了上一版本 128 类内存与运行故障依托 Rust 原生 Drop 自动析构机制彻底解决长期存在的内存泄漏问题官方实测批量打包场景内存占用大幅回落。同时得益于跨语言 LTO 链接优化、栈空间复用机制全平台运行性能提升 2% 至 5%二进制安装包体积整体缩减约 20%栈内存消耗也显著降低各类极限递归解析场景不再轻易触发程序崩溃。新版本兼顾生产落地实用性与长期迭代维护性Prisma、Claude Code 等主流工具已率先上线试用Linux 环境下 Claude Code 启动速度提升 10%。从开发侧来看移植后的 Rust 代码与原有 Zig 逻辑高度对齐原有开发人员上手门槛低搭配 borrow checker、Miri、7×24 小时解析器模糊测试等工具后续团队可系统性规避内存安全类缺陷为持续迭代筑牢稳定性基础。最后Sumner 感慨道若交由熟悉完整代码库的工程师团队人工完成本次 Rust 重构预计耗时一整年。而仅我一人配合 Fable 模型、全程监控 Claude Code仅用 11 天就完成全平台测试套件 100% 通过。如今单人借助 AI 工具能完成远超过去一年的开发工作量。来源https://bun.com/blog/bun-in-rust