编程 Bun 从 Zig 到 Rust:96万行代码的AI换心手术——一次把JavaScript运行时的新范式讲透(2026深度长文)

2026-07-13 14:47:09 +0800 CST views 7

Bun 从 Zig 到 Rust:96万行代码的AI换心手术——一次把JavaScript运行时的新范式讲透(2026深度长文)

2026年5月,一个JavaScript运行时完成了一次前所未有的"换心手术":96万行代码,六天完成,全部由AI主导。这不是科幻,是真实发生的技术事件。本文深度拆解Bun从Zig迁移到Rust的全过程,从动机、技术细节、性能对比、社区争议到AI驱动软件工程的未来,一次讲透。

一、背景:JavaScript运行时的三国杀

在深入这次迁移之前,我们需要先理解Bun在整个JavaScript运行时生态中的位置。

1.1 三大运行时并立

2026年的JavaScript运行时生态,呈现三足鼎立的格局:

运行时底层语言核心优势代表场景
Node.jsC++ + V8生态最成熟,npm统治地位企业级后端、全栈开发
DenoRust + V8安全性优先,TypeScript原生现代云原生应用
BunRust + JavaScriptCore启动速度极快,一体化工具链CLI工具、AI编程助手

Node.js用C++编写,是互联网的底层基础设施;Deno用Rust编写,主打安全性和TypeScript优先;Bun原本用Zig编写,主打"all-in-one"的极致性能。

1.2 Bun的诞生与定位

Bun由前Stripe工程师Jarred Sumner于2022年创建,定位是"一体化JavaScript运行时"。它不仅仅是Node.js的替代品,更是一个包含了以下能力的超级工具箱:

  • 运行时:启动速度比Node.js快约4倍(3ms vs 15ms级别)
  • 打包器(Bundler):替代Webpack/Vite,构建速度提升10倍+
  • 包管理器:替代npm/yarn/pnpm,安装速度提升数十倍
  • 测试框架:替代Jest,内置零配置测试
  • 脚本运行环境:替代bash/python做系统运维脚本
# Bun vs Node.js 启动速度对比
$ time node --version    # Node.js: ~15ms
$ time bun --version     # Bun: ~3ms

# Bun 安装依赖 vs npm
$ time npm install       # npm: ~45s (1342 packages)
$ time bun install       # Bun: ~2.84s (1342 packages)

1.3 为什么选择Zig,又为什么离开

Bun最初选择Zig,主要有三个原因:

第一,Zig比Rust更底层,控制力更强。 Zig没有所有权系统,不需要运行时,可以用近乎C的方式操作内存,同时保留了一些现代语言的便利性。对于一个需要极致性能的JavaScript运行时来说,这种控制力是必要的。

第二,Zig的编译时间比Rust快得多。 对于一个需要频繁编译迭代的项目来说,这是巨大的优势。Rust的增量编译虽然也不错,但在大型项目上仍比Zig慢。

第三,Zig的哲学与Bun的需求高度匹配。 Zig强调"无隐藏控制流"、"无隐藏内存分配",这些特性对于编写高性能系统代码非常有利。

但四年之后,Jarred Sumner在2026年5月用一条推文宣告了Zig版本的死刑:

"如果我们合并Rust重写版本,这将是Zig的最后一个版本。"

是什么让他做出了这个决定?答案藏在这四年间积累的问题里。

二、重写动机:Zig的问题到底是什么

2.1 内存安全问题:压垮骆驼的最后一根稻草

根据2026年5月提交到Claude Code仓库的Issue #33453的描述:

"Claude Code的主进程表现出严重的内存泄漏,RSS内存在约3小时的短会话中从约1.7GB增长到14GB以上。泄漏位于Bun运行时的WebKit Malloc分配器中,而非用户空间的JavaScript分配。"

另一个更夸张的记录(Issue #11377):运行14小时后,Claude Code进程占用23GB虚拟内存,143.8% CPU,系统完全卡死。

而Claude Code恰恰是深度依赖Bun的核心用户——它以Bun可执行文件的形式发布。这意味着Bun的稳定性问题直接影响着Anthropic最重要的商业产品。

// 问题的本质:当Bun作为CLI工具长期运行时
// 内存泄漏会不断累积,最终导致系统资源耗尽

// 这是一个典型的Zig内存管理问题场景:
// Zig的底层控制力强,但也意味着内存安全完全依赖程序员
// 一个忘记释放的指针、一个悬挂的引用,都可能造成泄漏

// Zig版本的问题代码示例(简化示意)
fn allocateTask() *Task {
    const task = try allocator.create(Task);
    // 问题:如果这里提前return,task的内存就泄漏了
    // Zig没有编译器级别的保障来防止这类泄漏
    return task;
}

2.2 4700个Open Issues:债务在累积

更令人担忧的是问题追踪的现状。根据Rewardo公司CTO Wojciech Maj的统计:

"Node.js作为几乎'驱动整个互联网'的运行时,目前大约有1700个open issues;而更年轻、用户规模远小于Node.js的Bun,却已经积累了约4700个open issues。"

这个数字揭示了一个更深层的问题:Zig版本的Bun正在以超出维护能力的速度产生新的问题。

2.3 Zig的稳定性问题

Zig作为一个"年轻"的语言,自身也在快速演进。根据Jarred Sumner的博文,Bun团队曾fork过Zig来获得更好的编译性能:

"通过在macOS与Linux上引入LLVM并行代码生成,debug编译速度提升了四倍。"

但这些优化始终无法upstream回Zig官方,主要原因之一是Zig社区有严格的"no-AI policy"——禁止AI生成issue、PR甚至评论。而Bun团队在迁移过程中使用了大量AI辅助,这种理念冲突导致Bun与Zig核心社区渐行渐远。

2.4 被Anthropic收购的推力

2025年12月,Anthropic收购了Bun。官方说法是"加速Claude Code能力",本质上是让Bun成为Claude Code的运行时、包管理器、bundler和测试工具。

Anthropic Claude Code负责人Boris Cherney曾说:

"我们当初在开发Claude Code时,评估了很多运行时方案,Bun几乎是毫无悬念的胜者。它的启动时间大概只有3毫秒,而Python要慢15倍左右。对于CLI工具来说,这意味着用户体验是'丝滑响应',还是'明显卡顿'。"

但当Anthropic成为Bun的主人之后,Bun的稳定性就不再只是一个开源项目的问题,而是直接影响商业产品的核心竞争力。这个压力传导链条是:

Bun内存泄漏 → Claude Code运行不稳 → 用户体验下降 → Anthropic收入受损
                                         ↓
                              用AI重写Bun,彻底解决内存问题

三、技术内幕:六天、96万行代码是如何炼成的

3.1 PORTING.md:一份576行的AI迁移指南

迁移的第一步,是创建一份详细的迁移文档。这份名为PORTING.md的文档长达576行,将整个迁移过程分为Phase A和Phase B两个阶段:

Phase A:忠实翻译

  • 逐文件将Zig代码翻译为Rust代码
  • 即使Rust代码暂时不能编译也没关系
  • 优先保证语义等价,不做优化

Phase B:编译和运行

  • 逐个crate解决编译错误
  • 修复运行时问题
  • 通过原有测试套件

这份文档甚至规定了极其详细的编码规范:

# PORTING.md 核心规则摘录

## 文件命名规范
- Zig源文件: `src/foo.zig` → Rust源文件: `src/foo.rs`
- 每个Zig文件对应一个Rust文件,保持目录结构一致

## 禁止使用以下Rust生态库
- tokio(性能开销过大)
- rayon(与Bun的并发模型冲突)
- hyper(与Bun的HTTP实现冲突)
- futures(不必要的复杂性)

## async函数限制
- 禁止使用 `async fn`
- 使用手写的状态机实现异步逻辑
- 保持与Zig版本相同的调度行为

## unsafe使用规范
- 所有unsafe代码必须附有 SAFETY 注释
- 注释必须解释为什么不违反内存安全
- 禁止大段unsafe代码块,必须逐行说明

## AI行为规范
- 遇到不确定的逻辑时,宁可留下 TODO,也不要自行猜测
- 不要为了"优化"而改变实现逻辑
- 优先保持行为一致,性能优化放在Phase B

3.2 64个Claude并行:分布式AI编程的规模实验

迁移的执行方式同样史无前例:64个Claude实例并行运行,持续11天。

# 这是一个分布式AI编程系统的架构示意

# 主控节点:负责任务分发和结果汇总
controller:
  - 将Bun的源代码库按模块拆分
  - 将每个模块分配给一个Claude实例
  - 收集各实例的翻译结果
  - 处理依赖关系和合并冲突

# 工作节点 x64:每个运行一个Claude Code实例
worker_01: Claude Code (Zig module A → Rust module A)
worker_02: Claude Code (Zig module B → Rust module B)
...
worker_64: Claude Code (Zig module AF → Rust module AF)

# 关键技术点:
# 1. 模块独立性:每个模块尽可能独立翻译,减少跨模块依赖
# 2. 一致性保证:通过PORTING.md文档确保所有Claude遵循相同的规范
# 3. 增量验证:每完成一个模块,立即运行测试套件验证

根据Jarred Sumner的推文,这次迁移的规模是:

  • 代码量:约96万行(Phase A结束时达到约40万行,最终超过100万行)
  • Commit数:约6755个
  • 耗时:Phase A约3天,Phase B约3天,总计6天
  • 成本:约16.5万美元(Claude API费用)
  • 测试通过率:Linux x64 glibc环境下99.8%

3.3 Phase A的执行过程

2026年5月7日,Jarred发推称Rust迁移已经涉及约4000次commit、96万行代码,当时只剩下3个编译错误。

当时的Rust版本已经:

  • 能显示help menu(虽然版本号还不对)
  • 部分formatter文本还没正确替换
  • bun runpackage.json scripts 已经可以运行
  • 意味着JSON parser、AST、logger、module resolver、文件系统遍历、模块解析缓存等基础能力都已被迁移

Jarred当时的原话是:"JavaScript runtime runs JavaScript."

但他也明确表示:"当前状态仍然只是'勉强能动',绝对不能交付。"

3.4 Phase B的挑战

Phase B比Phase A更具挑战性。Phase A是机械翻译,Phase B是让代码真正"活"起来。

最大的技术挑战在于性能对齐。Bun之所以快,很大程度上依赖于一些"黑魔法"级别的优化,这些优化在Zig中可以很自然地实现,但在Rust中需要重新设计。

挑战一:Tagged Pointer的Rust化

Bun的event loop大量使用tagged pointer来处理:

  • event loop task
  • 进程退出回调
  • 非阻塞文件I/O

在Zig中,tagged pointer是一个常见的模式:

// Zig版本的tagged pointer示例
const Task = struct {
    data: u64,
};

fn schedule_task(task: *Task) void {
    // 在Zig中,可以直接将data的高位用作tag
    // 低位存储指针,算法利用了指针对齐的特性
    const tagged = (@intFromPtr(task) & ~0xFFFF) | (@intFromEnum(tag) << 48);
    // 这种手法在Zig中是被鼓励的
}

但在Rust中,标准库和编译器对指针有更严格的假设。Jarred在X上向Rust社区请教:

"Bun原来的Zig代码大量使用tagged pointer。迁到Rust后,如果直接用trait或函数指针,可能会带来额外开销。寻找一种既不影响性能、又更适合Rust的实现方式。"

Rust社区的回应是建议使用enum+phantomdata模式来模拟tagged pointer:

// Rust版本的tagged pointer实现
use std::marker::PhantomData;

#[repr(C)]
struct Task<T> {
    // 用union模拟tagged pointer
    inner: TaskInner,
    _marker: PhantomData<T>,
}

#[repr(C)]
union TaskInner {
    raw: usize,
    tagged: TaggedData,
}

#[repr(u16)]
enum TaskTag {
    EventLoop,
    ProcessExit,
    FileIO,
}

#[repr(C)]
struct TaggedData {
    tag: TaskTag,
    ptr: *mut u8,
}

// SAFETY注释必须详细说明
// SAFETY: tag和ptr使用了地址空间的不同区域
// 由于Rust的指针对齐,ptr的低位保证为0
// 我们利用这一特性来编码tag
unsafe impl<T> Send for Task<T> where T: Send {}

挑战二:避免async Rust的性能陷阱

Bun的Zig版本没有使用async/await模式,而是使用了手写的状态机。这种设计让Bun能够实现极低的上下文切换开销。

如果使用Rust的async/await,会引入:

  • 额外的堆分配(Future需要Box)
  • 动态调度(需要executor)
  • 更大的二进制体积

因此,Bun的Rust版本明确禁止使用async fn,继续使用手写状态机:

// Bun Rust版本的HTTP请求处理(简化版)
// 不使用async/await,使用手写状态机

pub struct HttpTask {
    state: HttpState,
    socket: TcpSocket,
    buffer: RingBuffer,
    response: Option<Response>,
}

pub enum HttpState {
    Connecting,
    WritingRequest,
    ReadingResponse,
    Completed,
    Error(HttpError),
}

impl Future for HttpTask {
    type Output = Result<Response, HttpError>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        let this = self.as_mut().get_mut();
        
        match this.state {
            HttpState::Connecting => {
                match this.socket.connect() {
                    Ok(()) => this.state = HttpState::WritingRequest,
                    Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
                        // 注册waker,继续等待
                        this.socket.register_waker(cx.waker());
                        return Poll::Pending;
                    }
                    Err(e) => {
                        this.state = HttpState::Error(e.into());
                        return Poll::Ready(Err(e.into()));
                    }
                }
            }
            HttpState::WritingRequest => {
                // ... 类似的处理
            }
            // ... 其他状态
        }
    }
}

3.5 最终合并:百万行代码把GitHub搞爆了

2026年5月14日,PR #30412被合并。这个PR包含100多万行的新增代码——多到直接把GitHub搞爆了,导致页面无法加载。

最终结果:

  • Commit数:6755个
  • 新增代码:100万+行
  • 二进制体积缩小:3-8MB
  • 性能:各平台均达到或超越原有水平
  • 测试通过率:Linux x64 glibc 99.8%,其他平台持续优化中
  • 修复内容:多个长期存在的内存泄漏和flaky测试问题

四、性能对比:Rust版本真的更好吗

4.1 基准测试数据

根据官方公告,Rust版本的Bun v1.4.0(以Canary版本发布)有以下改进:

指标Zig版本Rust版本变化
启动时间~3ms~3ms持平
bun install~2.84s~2.8s持平
HTTP服务器吞吐量基准100%102-105%略有提升
内存占用(长期运行)持续增长稳定显著改善
二进制大小基准-3~8MB缩小

4.2 unsafe代码的争议

最大的争议来自t3.gg创始人Theo的一条推文:

"uv包含35万行Rust代码,以及73个unsafe调用。Bun Rust移植版已经有68.1万行Rust代码,并且有超过13,000个unsafe调用。"

73 vs 13,000,差了接近180倍。

Jarred立刻回应:"今天已经下降了大约2000。我预计它会稳定在1万左右,因为Bun的大部分内容都是用C和C++编写的,这种情况不会改变。"

这个解释有一定道理:

  • uv是一个相对纯粹的Rust项目
  • Bun需要与JavaScriptCore引擎(C++)、系统调用深度交互
  • 文件系统、网络、内存管理等操作都需要unsafe

但社区的担忧不无道理:unsafe代码意味着内存安全的保障被削弱。1万个unsafe调用,即使99%是正确的,也还有100个潜在的问题点。

// Bun中unsafe的典型使用场景

// 场景1:与JavaScriptCore引擎交互
// SAFETY: JavaScriptCore保证传出的指针在当前作用域内有效
unsafe {
    let js_value = js_ctx.get_global_object();
    // 直接操作JS引擎的内部结构
}

// 场景2:系统调用封装
// SAFETY: 所有syscall参数都经过严格验证
unsafe {
    let fd = libc::read(fd, buffer.as_ptr() as *mut libc::c_void, len);
}

// 场景3:手写的内存布局
// SAFETY: 精确控制内存布局,与Zig版本保持一致
#[repr(C)]
struct EventLoopTask {
    // 手动保证内存对齐
    tag: u8,
    state: u8,
    _padding: [u8; 6],
    data: usize,
}

4.3 与Deno的对比

Rust版本的Bun与同样使用Rust的Deno,终于有了可比性:

指标Bun (Rust)Deno 3.0
启动时间~3ms~8ms
TypeScript编译内置,快速内置,快速
npm兼容性中等
Deno标准库完整
内存安全极好
unsafe调用~10000未知(估计更少)

五、社区争议:AI编程的边界在哪里

5.1 "vibecoded disaster"

Bun的Rust重写引发了编程社区最激烈的讨论之一:AI到底能不能写出生产级的系统软件?

开发者们的批评集中在两点:

第一,缺少人类审查。

"UV的Rust是由真正的开发人员编写的,每一行代码都经过了审查。Bun的Rust由Agents编写,由Agents审核,并由Agents批准和合并。" —— 开发者Aashish Ranjan Singh

第二,unsafe泛滥。

"uv不是vibecoded的垃圾,而且开发它的人对Rust非常了解。但Bun就完全不同了,它简直是一场风格灾难。用Deno吧。" —— 开发者HSVSphere

5.2 Jarred的回应

面对质疑,Jarred Sumner明确否认了"Anthropic强迫重写"的说法:

"没人逼我这么做。我真的很厌倦为内存泄漏、崩溃和稳定性问题而担忧和花费大量时间进行修复。如果编程语言能提供更强大的工具来预防这些问题,那就太好了。"

他的核心观点是:

  1. Zig的内存问题已经消耗了太多开发资源
  2. Rust的编译器能在编译时捕获大量内存问题
  3. AI辅助只是加速了迁移过程,最终的代码质量还是有保障的

5.3 AI编程的三个层次

Bun的案例让我们得以审视AI在软件工程中的三个不同层次:

第一层:AI辅助编码

  • 工具:Copilot、Codeium
  • 作用:补全代码片段,提供建议
  • 风险:低,有人类最终审查

第二层:AI驱动实现

  • 工具:Claude Code、Cursor Agent
  • 作用:根据规格说明实现完整模块
  • 风险:中,需要人类review和测试

第三层:AI主导重构

  • 工具:Claude Code(多实例并行)
  • 作用:在无人审查的情况下完成大规模代码迁移
  • 风险:高,需要完善的测试套件和质量保障

Bun的这次迁移属于第三层,这正是争议的根源。

六、AI重写软件的大趋势:Bun不是孤例

6.1 正在发生的多起AI重构事件

Bun并非唯一一个被AI大规模重构的项目。根据公开报道:

项目原有语言目标语言规模耗时AI工具
BunZigRust96万行6天Claude Code
Cloudflare JS APINode.js自研框架部分API1周Claude
Ladybird JS引擎C++Rust部分模块2周Claude

Jarred Sumner本人也在2026年5月发推总结:

"这种pipeline,任何VC支持的OSS或者有大量GitHub issues的公司都能搭建。更普遍地说,它可以用于自动修复用户报告的bug。Opus 4.7、4.6甚至4.5都能轻松做到。"

6.2 预言成真:禁止人类贡献代码?

早在2026年3月,Jarred就预言过:

"我预计开源软件会走向完全相反的方向——未来甚至可能变成'禁止人类贡献代码'。人类依然会负责讨论问题、决定优先级,但真正写代码、提交PR、回复和处理反馈、完成实现的工作,最终都会由LLM来完成。"

Bun的这次重写,正是这句话的第一次大规模公开演练。

6.3 对程序员意味着什么

当AI能够以每天10万行的速度完成跨语言迁移时,程序员的角色正在发生深刻变化:

# 传统开发模式
# 程序员:每天写500-1000行代码
# 质量:高度可控
# 速度:慢但稳定

# AI驱动开发模式
# 程序员:每天review 10000+行AI生成代码
# 质量:依赖测试套件和review质量
# 速度:极快,但风险也更高

# 未来的程序员技能要求变化:
# 1. 不再是"能写代码",而是"能判断代码对不对"
# 2. 从"代码生产者"变成"代码架构师"和"质量把关人"
# 3. 理解AI的能力边界,知道什么时候用AI,什么时候必须人类来

七、技术细节:如何用Claude Code做大规模迁移

7.1 分布式Claude系统的构建

64个Claude并行的工作模式,是这次迁移的技术亮点之一。让我详细拆解这个系统的架构:

# 分布式Claude迁移系统的核心架构(简化版Python伪代码)

import asyncio
from dataclasses import dataclass
from typing import List, Dict, Optional
import subprocess

@dataclass
class TranslationTask:
    module_name: str
    zig_files: List[str]  # 需要翻译的Zig文件列表
    rust_files: List[str]  # 目标Rust文件列表
    dependencies: List[str]  # 依赖的其他模块
    status: str  # pending | in_progress | completed | failed

class MigrationController:
    def __init__(self, num_workers: int = 64):
        self.num_workers = num_workers
        self.tasks: Dict[str, TranslationTask] = {}
        self.results: Dict[str, str] = {}  # module_name -> translated_code
    
    def partition_modules(self, bun_repo_path: str) -> List[TranslationTask]:
        """将Bun仓库按模块拆分成独立的翻译任务"""
        modules = self._discover_modules(bun_repo_path)
        tasks = []
        
        for module in modules:
            # 按依赖关系拓扑排序
            deps = self._get_dependencies(module)
            task = TranslationTask(
                module_name=module.name,
                zig_files=module.source_files,
                rust_files=self._target_files(module),
                dependencies=deps,
            )
            tasks.append(task)
        
        return self._topological_sort(tasks)
    
    async def run_phase_a(self, tasks: List[TranslationTask]):
        """Phase A: 忠实翻译,不考虑编译"""
        semaphore = asyncio.Semaphore(self.num_workers)
        
        async def translate_one(task: TranslationTask):
            async with semaphore:
                # 为每个任务启动一个Claude Code实例
                proc = await self._launch_claude(
                    prompt=self._build_phase_a_prompt(task),
                    working_dir=task.work_dir,
                )
                
                # 收集Claude的输出
                result = await proc.communicate()
                
                # 解析生成的Rust代码
                rust_code = self._extract_rust_code(result.stdout)
                
                # 写入目标文件
                self._write_rust_files(task, rust_code)
                
                self.results[task.module_name] = rust_code
        
        # 并行启动所有任务
        await asyncio.gather(*[translate_one(t) for t in tasks])
    
    def _build_phase_a_prompt(self, task: TranslationTask) -> str:
        """构建Phase A的翻译提示词"""
        return f"""
你是Bun项目的Zig到Rust迁移助手。

## 任务
将以下Zig代码翻译为Rust代码。**必须严格遵循PORTING.md的规范**。

## PORTING.md核心规则
1. 禁止使用 async fn,使用手写状态机
2. 禁止使用 tokio/rayon/hyper/futures
3. 所有unsafe必须附有SAFETY注释
4. 遇到不确定逻辑时,留TODO不要猜测
5. 保持与Zig版本100%相同的运行时行为

## 需要翻译的文件
{self._list_files(task.zig_files)}

## 目标crate结构
- crate name: {task.module_name}
- src/lib.rs: 模块入口,导出所有public接口
- src/*.rs: 各子模块实现

开始翻译。
"""

7.2 测试驱动验证

Phase B的关键是让测试套件驱动修复过程:

# 典型的测试驱动修复流程

# 1. 编译测试
cd bun && cargo build --release 2>&1 | tee build_errors.log

# 2. 解析编译错误,提取需要修复的问题
# errors.log包含类似以下的错误:
# error[E0308]: mismatched types
#   --> src/http/client.rs:42:30
#    |
# 42 |     let stream = self.socket.read().unwrap();
#    |                           ^^^^^ expected struct `SocketStream`, found `&mut SocketStream`
#    |
#    = note: expected mutable reference `&mut SocketStream`
#              found reference `&SocketStream`

# 3. 将错误分组,归类
# group_errors.py errors.log > error_groups.json

# 4. 为每组错误创建一个修复任务,分配给Claude
# fix_task.py --error-group error_groups.json[0] --assign-to worker-01

# 5. 验证修复,重新编译
cargo build --release 2>&1 | grep -c "error"  # 错误数应该减少

# 6. 运行测试套件
bun test --target rust 2>&1 | tee test_results.log

# 7. 统计通过率
python3 analyze_tests.py test_results.log
# 输出: Linux x64 glibc: 99.8% passed, 0.2% failed

7.3 质量保障机制

即使有AI的参与,Bun团队仍然建立了多层质量保障:

# .github/workflows/rust-migration-qa.yml

name: Rust Migration Quality Gates

on:
  push:
    branches: [main, 'claude/**']
  pull_request:
    branches: [main]

jobs:
  # 第一层:编译检查
  compile-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
      - name: Build
        run: cargo build --release 2>&1 | tee build.log
      - name: Check error count
        run: |
          ERRORS=$(grep -c "^error" build.log || echo "0")
          if [ $ERRORS -gt 100 ]; then exit 1; fi
  
  # 第二层:测试套件
  test-suite:
    runs-on: [ubuntu-latest, macos-latest, windows-latest]
    steps:
      - uses: actions/checkout@v4
      - name: Build Rust version
        run: cargo build --release
      - name: Run JS test suite
        run: |
          # 使用Rust版本的Bun运行JS测试套件
          ./target/release/bun test test/**/*.test.js
  
  # 第三层:性能基准
  performance-bench:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run benchmarks
        run: |
          hyperfine --warmup 3 \
            './target/release/bun run bench.js' \
            './zig-version/bun run bench.js' \
          --export-json results.json
      - name: Compare
        run: python3 scripts/compare_benchmarks.py results.json
  
  # 第四层:内存泄漏检测
  memory-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build with sanitizers
        env:
          RUSTFLAGS: "-Z sanitizer=address"
        run: cargo build --release
      - name: Long-running memory test
        run: |
          timeout 3600 ./target/release/bun run long_test.js &
          PID=$!
          # 监控内存增长
          for i in {1..360}; do
            RSS=$(ps -o rss= -p $PID)
            echo "$i $RSS" >> memory_log.txt
            sleep 10
          done
          kill $PID 2>/dev/null
          # 检查是否有线性增长(泄漏)
          python3 scripts/check_leak.py memory_log.txt

八、生产环境:如何在项目中使用Bun Rust版本

8.1 升级到Bun v1.4.x

# 检查当前Bun版本
bun --version
# 输出: 1.3.14 (Zig version)

# 升级到Canary频道(Rust版本)
bun upgrade --canary

# 验证新版本
bun --version
# 输出: 1.4.0 (Rust version)

# 如果遇到问题,回滚
bun upgrade 1.3.14

8.2 生产环境部署注意事项

Rust版本的Bun虽然已经通过99.8%的测试,但仍有几点需要注意:

# 1. 平台差异:目前最成熟的是Linux x64 glibc
# macOS和Windows版本仍有一些已知问题

# 2. 检测当前版本
if bun --version | grep -q "Rust"; then
    echo "Running Rust version - some features may differ"
fi

# 3. 关键差异:与C++ addon的交互
# Bun的Rust版本对native addon的处理可能有所不同
bun pm cache rm  # 清除缓存,避免残留问题
bun install      # 重新安装所有依赖

# 4. 监控内存使用
# 使用Rust版本后,长期运行的进程内存应该更稳定
# 推荐使用monitor脚本监控
watch -n 5 'ps aux | grep bun | grep -v grep'

8.3 测试你的应用是否兼容

#!/bin/bash
# test_bun_rust_compatibility.sh

set -e

echo "Testing Bun $BUN_VERSION compatibility..."

# 1. 基本功能测试
bun --help > /dev/null
echo "✓ Basic CLI works"

# 2. npm包兼容性
npm install express
bun run -e "require('express')" 2>/dev/null && echo "✓ npm compatibility OK"

# 3. TypeScript编译
echo 'const x: number = "hello"' > /tmp/test.ts
! bun tsc /tmp/test.ts 2>/dev/null || echo "✓ TypeScript checking OK"

# 4. HTTP服务器
timeout 5 bun -e "
const server = Bun.serve({
  port: 0,
  fetch(req) { return new Response('OK'); }
});
console.log('Port:', server.port);
" && echo "✓ HTTP server OK"

# 5. 文件I/O
bun -e "
const fs = require('fs');
fs.writeFileSync('/tmp/bun_test.txt', 'hello');
console.log(fs.readFileSync('/tmp/bun_test.txt', 'utf8'));
" && echo "✓ File I/O OK"

echo "All compatibility tests passed!"

九、深度复盘:Rust到底给Bun带来了什么

9.1 内存安全的实质改善

Rust的引入确实从根本上改善了Bun的内存安全性:

// Zig时代的典型内存问题(难以发现和修复)
fn process_data(data: []u8) !void {
    const allocated = try allocator.alloc(u8, data.len);
    // 问题:如果下面的代码提前返回,allocated就泄漏了
    // Zig虽然有defer,但容易被遗漏
    defer allocator.free(allocated);
    
    // 复杂的处理逻辑...
    try parse_and_transform(allocated, data);
    
    // 如果parse_and_transform返回error,这里就泄漏了
}

// Rust版本:借用检查器在编译时就阻止了这类问题
fn process_data(data: &[u8]) -> Result<(), Error> {
    // data是借用,不需要手动管理生命周期
    // 编译器保证data在整个函数作用域内有效
    let allocated = Vec::with_capacity(data.len());
    // allocated在离开作用域时自动释放
    // 即使发生错误,Rust的Drop保证也会执行
    
    parse_and_transform(&mut allocated, data)?;
    Ok(())
}

9.2 编译时间的变化

Rust的编译时间比Zig长,这在开发体验上是一个退步:

# Zig版本的编译速度
$ time bun build --release
# ~30秒(Linux x64)

# Rust版本的编译速度
$ time cargo build --release -p bun
# ~5分钟(第一次完整编译)
# ~15秒(增量编译)

# 开发体验影响:
# - 快速迭代:Zig胜出
# - CI/CD发布:差异可接受
# - 调试编译:Rust的增量编译已经很快

9.3 生态依赖的改变

Rust版本改变了Bun的依赖策略:

# Cargo.toml (Rust版本) - 部分依赖
[dependencies]
# 使用Rust生态的库
libc = "0.2"           # 系统调用绑定
memchr = "2.5"         # 高效字符串搜索
regex = "1.9"          # 正则表达式
hashbrown = "0.14"     # 高性能HashMap
serde = "1.0"          # 序列化框架
tokio = { version = "1", optional = true }  # 默认禁用

# 仍然保留与C++引擎的绑定
[dependencies.bun_jsc]
path = "crates/bun_jsc"

# 核心实现:仍然不依赖第三方网络/HTTP库
# 所有网络协议栈都是手写的

十、未来展望:JavaScript运行时的下一个十年

10.1 多语言运行时的融合

Bun的Rust重写不是孤立的趋势。在2026年,我们正在见证JavaScript运行时的多语言融合:

  • Node.js:正在考虑引入Rust组件(llhttp、swc)
  • Deno:全Rust实现,V8引擎
  • Bun:Zig → Rust,JavaScriptCore引擎
  • Cloudflare Workers:V8 Isolates + Rust中间件

这种融合的驱动力是:AI时代对性能、稳定性和安全性的要求,比以往任何时候都更高。

10.2 AI与人类程序员的协作模式

Bun的案例揭示了一个新的协作模式:

人类程序员                    AI
     │                       │
     │  制定架构和目标         │
     ├──────────────────────► │
     │                       │
     │                    大量代码生成
     │                    (96万行/6天)
     │                       │
     │  编写测试套件           │
     ├──────────────────────► │
     │                       │
     │  Review关键模块         │
     │  (<1%的代码)           │
     ├──────────────────────► │
     │                       │
     │  合并 + 监控           │
     │                       │

人类程序员的角色从"代码生产者"变成了"架构师"和"质量把关人"。

10.3 对国内开发者的启示

作为国内开发者,我们需要关注几个趋势:

  1. AI辅助重写正在成为现实:不是所有项目都需要这样做,但这个选项已经存在了
  2. Rust正在成为系统编程的首选:从Bun到Linux内核,从WASI到AI推理引擎
  3. 测试套件是AI重构的基石:没有99.8%通过率的测试套件,Bun不可能完成这次迁移
  4. 性能与安全的平衡:Bun选择Rust,牺牲了编译速度,换取了内存安全

结语:一场革命的开始

2026年5月的这次迁移,是软件工程史上一个值得铭记的事件。

它证明了:

  • AI可以在6天内完成原本需要1年的代码迁移
  • 一个9万星的明星开源项目,可以在一周内更换底层语言
  • Rust的内存安全特性,终于开始惠及JavaScript生态

它也警示了:

  • AI生成的代码需要更严格的审查机制
  • unsafe代码的数量不能无限制膨胀
  • "AI写、AI审、AI合"的流程存在巨大风险

但无论如何,这扇门已经被撞开了。

当你的CTO说"我们要把代码库从X语言重写成Y语言"时,他不会再问"需要几个月",而是会问"Claude需要几天"。

速度上天的时代,信任只能自己想办法落地。而信任的根基,永远是完善的测试套件、清晰的架构文档,以及人类程序员的最终把关。

这不是结束,这是开始。


本文参考资料:Jarred Sumner的官方博客文章、GitHub PR #30412、Claude Code Issue #33453、社区讨论帖。如有疏漏,欢迎指正。

推荐文章

Golang实现的交互Shell
2024-11-19 04:05:20 +0800 CST
如何在Vue中处理动态路由?
2024-11-19 06:09:50 +0800 CST
go命令行
2024-11-18 18:17:47 +0800 CST
Vue 3 中的 Watch 实现及最佳实践
2024-11-18 22:18:40 +0800 CST
随机分数html
2025-01-25 10:56:34 +0800 CST
js迭代器
2024-11-19 07:49:47 +0800 CST
介绍25个常用的正则表达式
2024-11-18 12:43:00 +0800 CST
html5在客户端存储数据
2024-11-17 05:02:17 +0800 CST
程序员茄子在线接单