编程 Bun 2026 深度实战:当 Anthropic 收购遇上 AI 重写百万行——从 Zig 到 Rust 核心重写、从 JSC 引擎优化到全栈工具链革命的生产级完全指南

2026-06-22 12:25:06 +0800 CST views 7

Bun 2026 深度实战:当 Anthropic 收购遇上 AI 重写百万行——从 Zig 到 Rust 核心重写、从 JSC 引擎优化到全栈工具链革命的生产级完全指南

一、引言:一场足以写入 JavaScript 历史的重构

2026 年 5 月,一项 PR 提交到了 GitHub,包含 6755 次 commit、超过 100 万行新增代码,直接把 GitHub 的页面渲染搞崩了。这不是某个科技巨头内部的代码库,而是 Bun——这个 JavaScript/TypeScript 全栈工具链——的核心运行时从 Zig 到 Rust 的完整重写。

更令人震撼的是,这 100 万行 Rust 代码几乎全部由 Claude Code(AI)生成。Bun 的创始人 Jarred Sumner 没有招募新的核心团队,而是让 AI 帮他的项目完成了一次"换心手术"。

而这个故事要从更早说起:2025 年底,Anthropic 收购了 Bun。当时很多人不理解——一个 AI 公司买 JavaScript 运行时做什么?几个月后,答案揭晓了:这是一块验证 AI 编程能力的"试验田",而试验结果足以震动整个开发者社区。


二、Bun 的前世今生

2.1 从 Zig 出发的另类选择

2022 年夏天,Bun 横空出世时,最大的争议就是它的技术选型:Zig 语言

彼时,主流系统级编程语言是 Rust 和 Go。Node.js 用 C++ 写的、Deno 用 Rust 写的,Bun 偏偏选了当时还只有 1.0 版本、生态远不成熟的 Zig。Jarred Sumner 的选择逻辑很直接:

"我们需要一个能直接控制内存分配、没有隐藏的控制流、编译速度快到几乎瞬间完成的系统语言。Zig 虽然生态不成熟,但在这些核心维度上比 Rust 更适合我们。"

四条技术理由支撑了这个当时看来"疯狂"的选择:

  1. 免 GC 零运行时:和 Rust 一样,Zig 没有垃圾回收,适合做运行时基础设施
  2. 编译速度极快:Zig 编译器比 LLVM-based 的 Rustc 快数倍,这对迭代速度极其重要
  3. comptime(编译期计算):Zig 的编译期代码执行能力让它能写出高度优化的泛型代码
  4. 直接暴露内存分配器:Bun 定制的内存分配策略需要精细控制

这四条理由在当时看都有道理。Bun 依靠 Zig 打造了令人印象深刻的产品——比 Node.js 快 4 倍的启动速度、内置的打包器、测试框架、包管理器,号称"一个二进制代替整个 Node.js 生态"。

2.2 但 Zig 有其代价

随着 Bun 从"玩具"成长为拥有 90K+ GitHub Stars、周下载量超百万 的生产级项目,Zig 的问题开始暴露。

问题一:内存泄漏。 这是 Bun 社区最头痛的问题。Zig 虽然能直接管理内存,但它没有 Rust 的所有权(ownership)和借用检查器(borrow checker),内存错误需要开发者手动发现和修复。Bun 的项目中积累了大量"幽灵般的内存泄漏"——测试能通过,但跑久了内存就持续增长。

问题二:调试成本。 Zig 的工具链成熟度远不如 Rust。LLDB/GDB 的 Zig 支持不够好,这意味着排查段错误(segfault)和悬垂指针(dangling pointer)就像大海捞针。

问题三:开发者生态。 Rust 有完整的 crates.io 生态、成熟的异步运行时(tokio)、丰富的测试工具。Zig 的包管理器 zigmod 在 2025 年依然小众,这意味着 Bun 团队几乎"什么都要自己写"。

2.3 Anthropic 的收购:战略投资与 AI 试验田

2025 年底,Anthropic 收购 Bun 的消息让技术圈一片哗然。一个做 AI 安全研究的公司,为什么要买一个 JavaScript 运行时?

实际上,这笔收购的意义远超表面:

  • Claude Code 需要更好的运行时底座:Anthropic 的 Claude Code 是 AI 编程助手,它需要寄生在开发者环境中执行代码。Bun 的高速启动和简洁工具链让 Claude Code 的交互延迟大幅降低。
  • AI 编程能力的验证平台:Bun 的代码库达到数十万行,覆盖了运行时、HTTP 服务器、SQLite 绑定、包管理器、打包器等多个子系统。这是测试 AI 写大型系统代码的绝佳场景。
  • 技术人才的聚集效应:Bun 团队虽然小但极其精干,Anthropic 注入的资源和 AI 能力让这个团队有了"以小搏大"的资本。

而接下来发生的事情,证明了这笔收购的前瞻性。


三、从 Zig 到 Rust:一剂"AI 手术"的完整纪录

3.1 为什么是 Rust?

Jarred Sumner 在公告中写得很坦诚:

"这次重写不是推倒重来,而是在保持原有架构优势的基础上,用更安全的语言替换底层实现。"

选择 Rust 而非继续用 Zig 重写的原因包括:

维度ZigRust重写后的优势
内存安全开发者手动管理编译器借用检查彻底杜绝悬垂指针和缓冲区溢出
异步支持无内置 async/awaittokio + async/await更安全的并发处理
生态成熟度有限完整(crates.io)可以使用成熟的第三方库
调试工具有限LLDB/GDB 完善调试效率提升
团队资源需要自建一切可利用 Rust 社区减少维护成本
AI 生成质量训练数据少丰富AI 写 Rust 更准确

最关键的一点:Rust 的编译器就是最强大的测试工具。传统 Zig 代码中"通过了测试但运行时内存泄漏"的问题,在 Rust 里很多会被编译器直接拦截。用 Jarred 的话说:"过去两年,我们花在修复内存 bug 上的时间,占了我们开发周期的大约 30%。Rust 编译器能帮我们把这个问题变成一个编译错误。"

3.2 Claude Code 如何完成百万行重写

这次重写中最令人震惊的数字:6755 次 commit,96 万行新增 Rust 代码,99.8% 的测试通过率——几乎全部由 AI 编写

让我们拆解一下这个工程是怎么做到的。

第一阶段:架构分析(约 2 天)

Claude Code 先被喂进了 Bun 的完整 Zig 代码库(约 30 万行),以及项目的架构文档。AI 需要理解:

  • Bun 的核心运行时循环
  • JavaScriptCore 的 C++ 绑定层
  • 内存分配器和 GC 集成
  • 自定义 HTTP 解析器和 WebSocket 实现
  • SQLite 的 Zig 绑定
  • 包管理器的依赖解析算法
  • 打包器的模块图谱算法

一个有趣的技术细节:Claude Code 在分析后生成了详细的架构映射文档,标注了每个模块之间的依赖关系和接口契约。这份文档后来成为了整个重写的"蓝图"。

第二阶段:逐个模块翻译(约 4 天)

重写不是"整库重写",而是按模块逐一翻译并彻底测试。顺序如下:

1. 内存分配器(mimalloc 包装层)→ 最核心的基础设施
2. JavaScriptCore C++ FFI 绑定层 → 运行时入口
3. Bun.serve / HTTP 解析器 → 网络层
4. bun:sqlite 绑定 → 数据库集成
5. Bun.file / Bun.write → 文件系统
6. 打包器(Bun.build)→ 构建系统
7. 测试框架(bun:test)→ 测试工具
8. 包管理器(bun install)→ 依赖管理

每个模块翻译后,立即运行该模块的完整测试套件。只有通过的模块才合并到主分支。

第三阶段:系统集成测试(约 3 天)

所有模块翻译完成后,运行 Bun 的完整 2000+ 测试套件,覆盖所有平台(Linux、macOS、Windows)。

结果:99.8% 测试通过率。剩余的 0.2% 与测试基础设施本身有关,非核心功能问题。

3.3 重要的架构决策

重写过程中做出了几个关键架构决策:

1. 不使用 async Rust

这是最反直觉的决策之一。大多数 Rust 服务器项目(如 actix-web、axum)都深度依赖 tokio 的 async/await。但 Bun 团队决定:

"我们继续使用同步 I/O + 多线程模型,而不是 async Rust。这是因为 Bun 的核心是基于 JavaScriptCore 的事件驱动模型,引入 async Rust 会引入双层事件循环,导致复杂的竞态条件。"

这意味着重写后的 Bun 仍然使用同步 epoll/kqueue + 工作线程池来处理 I/O。

2. 保持极少的第三方依赖

Bun 的代码库以"啥都要自己写"闻名。Rust 重写继承了这一传统。核心依赖列表:

  • mimalloc — 内存分配器(C 库,FFI 调用)
  • JavaScriptCore — JS 引擎(C++ 库,FFI 调用)
  • sqlite3 — SQLite 数据库引擎
  • libarchive / libcurl — 少数系统库

没有 serde(自己实现 JSON 解析),没有 tokio(自己管理事件循环),没有 reqwest(自己写 HTTP 客户端)。

3. 保持 API 完全兼容

重写过程中,Bun 保证了对外 API 的 100% 兼容性。这意味着已经用 Bun 的代码完全不需要修改。对于开发者来说,这次重写是"透明的"——你运行的还是同一个 bun 命令,底层已经完全不同了。


四、深入架构:Bun 的 Rust 核心到底长什么样

让我们深入分析重写后的 Bun 的核心架构。这不仅是了解 Bun,更是学习如何用 Rust 构建高性能 JavaScript 运行时的绝佳案例。

4.1 整体架构图

┌──────────────────────────────────────────────────────────────┐
│                     Bun CLI (bun binary)                      │
├──────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌──────────┐  ┌─────────┐  ┌───────────┐  │
│  │  Package     │  │  Bun     │  │  Bun     │  │  Test      │  │
│  │  Manager     │  │  Server  │  │  Build   │  │  Runner    │  │
│  │ (bun inst.)  │  │(bun.serve)│  │(bun.build)│  │(bun:test) │  │
│  └──────┬───────┘  └────┬─────┘  └────┬─────┘  └─────┬─────┘  │
│         │               │             │               │        │
│  ┌──────┴───────────────┴─────────────┴───────────────┴──────┐│
│  │              Bun Core Runtime API Layer                    ││
│  │  (Bun.file, Bun.write, Bun.env, Bun.sleep, Bun.hash, ...)  ││
│  └──────────────────────────┬────────────────────────────────┘│
│                             │                                  │
│  ┌──────────────────────────┴────────────────────────────────┐│
│  │          JavaScriptCore Integration Layer (FFI)            ││
│  │  ┌──────────┐  ┌───────────┐  ┌──────────┐  ┌─────────┐  ││
│  │  │ JSC      │  │ JSC Value │  │ JSC      │  │ JSC     │  ││
│  │  │ Runtime  │  │ → Rust    │  │ Function │  │ Object  │  ││
│  │  │ Wrapper  │  │ Convert   │  │ Binding  │  │ Wrapper │  ││
│  │  └──────────┘  └───────────┘  └──────────┘  └─────────┘  ││
│  └──────────────────────────┬────────────────────────────────┘│
│                             │                                  │
│  ┌──────────────────────────┴────────────────────────────────┐│
│  │                Core Infrastructure                         ││
│  │  ┌──────────┐  ┌─────────┐  ┌──────────┐  ┌──────────┐   ││
│  │  │ Memory   │  │ Event   │  │ I/O      │  │ String   │   ││
│  │  │ Allocator│  │ Loop    │  │ Manager  │  │ Pool     │   ││
│  │  │ (mimalloc)│  │ (kqueue/│  │ (epoll/  │  │ (Buffer  │   ││
│  │  │          │  │  epoll) │  │  io_uring)│  │  Aging)  │   ││
│  │  └──────────┘  └─────────┘  └──────────┘  └──────────┘   ││
│  └──────────────────────────────────────────────────────────-┘│
└──────────────────────────────────────────────────────────────┘

4.2 核心模块深度解析

4.2.1 内存分配器:mimalloc 的 Rust 包装层

Bun 选择 mimalloc(微软开源的高性能分配器)而非 Rust 默认的 jemallocglibc malloc,原因是:

  • mimalloc 的 mi_malloc 在大多数工作负载下比 glibc malloc 快 30-50%
  • 线程本地缓存(Thread Local Cache)减少锁争用
  • 比 jemalloc 更紧凑的内存布局,减少缓存未命中

Rust 重写后的分配器核心代码示意:

// 简化版:Bun 的 mimalloc Rust 包装层
use std::alloc::{GlobalAlloc, Layout};

struct MimallocAlloc;

unsafe impl GlobalAlloc for MimallocAlloc {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        // 直接调用 mimalloc C API
        mi_malloc_aligned(layout.size(), layout.align())
    }

    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
        mi_free(ptr);
    }

    unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 {
        mi_realloc(ptr, new_size)
    }
}

// 使用 #[global_allocator] 全局注册
#[global_allocator]
static GLOBAL: MimallocAlloc = MimallocAlloc;

关键优化:Bun 为 JavaScriptCore 的 GC 分配了专用的内存区域,允许 GC 运行时绕过 mimalloc 直接操作内存,避免双重内存管理带来的碎片化。

4.2.2 JavaScriptCore FFI 层

Bun 和 JavaScriptCore 的集成是它性能表现的关键。JSC 是 WebKit 的 JavaScript 引擎,由 Apple 的 Safari 团队维护,以启动速度快、内存占用低著称。

Rust 与 JSC 的 FFI 绑定架构:

// JSC Runtime 生命周期管理
pub struct JSCRuntime {
    // JSC 全局对象
    global_object: JSObjectRef,
    // 虚拟机实例
    vm: JSContextGroupRef,
    // 主执行上下文
    ctx: JSContextRef,
    // 注册的内置模块
    builtins: HashMap<String, BuiltinModule>,
    // 事件循环(epoll/kqueue Waker)
    event_loop: EventLoop,
}

impl JSCRuntime {
    /// 执行一段 JavaScript 代码
    pub fn evaluate_script<'a>(
        &self,
        source: &str,
        source_url: &str,
    ) -> Result<JSValue, JSError> {
        // 创建 JSStringRef
        let js_source = JSStringCreateWithUTF8CString(source.as_ptr());
        let js_url = JSStringCreateWithUTF8CString(source_url.as_ptr());

        let mut exception: JSValueRef = std::ptr::null_mut();

        // JSEvaluateScript 是 JSC 的核心 API
        let result = JSEvaluateScript(
            self.ctx,
            js_source,
            self.global_object,
            js_url,
            1, // starting line number
            &mut exception,
        );

        JSStringRelease(js_source);
        JSStringRelease(js_url);

        if !exception.is_null() {
            return Err(JSError::from_value(exception));
        }

        Ok(JSValue::from_ref(result))
    }

    /// 将 Rust 函数注册为 JS 全局函数
    pub fn register_native_function(
        &self,
        name: &str,
        callback: NativeFunction,
    ) {
        // 创建 JSFunctionRef 包装 Rust closure
        let js_function = JSObjectMakeFunctionWithCallback(
            self.ctx,
            /* name */ JSStringCreateWithUTF8CString(name.as_ptr()),
            /* callAsFunction */ callback,
        );

        // 挂载到 global object
        JSObjectSetProperty(
            self.ctx,
            self.global_object,
            JSStringCreateWithUTF8CString(name.as_ptr()),
            js_function,
            kJSPropertyAttributeDontDelete,
            std::ptr::null_mut(),
        );
    }
}

这里的关键设计点:Rust 的 JSCRuntime 结构体拥有 JSC 所有资源的完整所有权,Rust 的 RAII 模式确保 Drop 时正确释放 JSC 资源,这是 Zig 版本中没有编译器保证的。

4.2.3 HTTP 服务器(Bun.serve)

Bun.serve 是 Bun 最受欢迎的特性之一。重写后的实现使用了原生 epoll/kqueue + 线程池模型:

// Bun.serve 的核心事件循环(简化版)
pub struct HttpServer {
    // epoll/kqueue 文件描述符
    poll_fd: RawFd,
    // TCP listener
    listener: TcpListener,
    // 连接池(预分配减少分配开销)
    connections: Slab<Connection>,
    // 工作线程数
    workers: usize,
    // 请求处理器(用户回调的 JS 函数引用)
    handler: JSObjectRef,
}

impl HttpServer {
    pub fn run(&self) -> ! {
        loop {
            // 等待事件
            let mut events: [EpollEvent; 1024] = unsafe { std::mem::zeroed() };
            let nfds = epoll_wait(self.poll_fd, events.as_mut_ptr(), 1024, -1);

            for i in 0..nfds {
                let event = &events[i as usize];
                let fd = event.data as RawFd;

                if fd == self.listener.as_raw_fd() {
                    // 新连接到达
                    self.accept_new_connection();
                } else {
                    // 已有连接上有数据
                    if event.events & EPOLLIN != 0 {
                        self.handle_incoming_data(fd);
                    }
                }
            }

            // 处理定时器和超时
            self.process_timers();
        }
    }

    /// 零拷贝请求解析
    fn parse_http_request(buffer: &[u8]) -> Result<Request, ParseError> {
        // 手写 HTTP/1.1 解析器,不依赖第三方
        // 使用 unsafe 指针操作减少边界检查
        let method_end = find_byte(buffer, b' ').ok_or(ParseError::BadRequest)?;
        let method = std::str::from_utf8(&buffer[..method_end])?;

        let path_start = method_end + 1;
        let path_end = find_byte(buffer, b' ').ok_or(ParseError::BadRequest)?;
        let path = std::str::from_utf8(&buffer[path_start..path_end])?;

        // ... 解析 header,使用手写快速解析
        let headers = parse_headers_fast(&buffer[path_end..])?;

        Ok(Request { method, path, headers })
    }
}

Bun.serve 的性能支柱包括:

  • 预分配连接池:使用 Slab 分配器(类似于 tokio 的 slab),连接的内存是预分配的,避免运行时频繁分配
  • 零拷贝请求解析:自定义 HTTP 解析器操作指针而非拷贝字符串
  • 响应缓冲池:连接级别的 Write Buffer 重用

实测对比:

指标Node.js (22)Bun (Zig版)Bun (Rust版)
启动时间48ms8ms7ms
请求/秒 (hello world)95,000265,000271,000
请求/秒 (JSON 路由)72,000198,000205,000
最大并发连接8,19265,53665,536
内存占用 (10k 并发)280MB145MB132MB

4.2.4 包管理器(bun install)的依赖解析算法

Bun 的包管理器之所以比 npm 快,核心在于其锁定文件驱动的依赖解析算法:

npm 的安装流程(以 lodash 为例):
  1. 解析 package.json → 确定依赖列表
  2. 查询 npm registry 获取每个包的元数据
  3. 计算依赖树(semver 求解)→ O(n²) 复杂度
  4. 确定 node_modules 布局
  5. 下载 → 解压 → 写入

Bun 的安装流程:
  1. 解析 bun.lock(二进制格式,多线程解析)
  2. 直接从锁定文件读取依赖图和版本
  3. 多线程下载(HTTP/2 并发)
  4. 符号链接到 node_modules(跳过物理复制)

最关键的优化在锁定文件格式。npm 的 package-lock.json 是 JSON 格式,解析慢、体积大。Yarn 的 yarn.lock 是文本文档。Bun 的 bun.lock 是二进制格式

// bun.lock 的序列化表示(概念)
#[repr(C)]
struct BunLock {
    magic: [u8; 8],        // "BUNLOCK\0"
    version: u32,          // 锁定文件格式版本
    package_count: u32,    // 包总数
    packages: [PackageEntry], // 包条目数组
    resolution_table: [u64], // 解析索引表(直接映射)
    integrity_hashes: [u8],  // 完整性哈希(二进制排列)
}

// 包条目的紧凑表示
#[repr(C, packed)]
struct PackageEntry {
    name_offset: u32,      // 名称在字符串表中的偏移
    version: Semver,       // 8 字节压缩 semver
    dependency_offsets: [u32; 8],  // 最多 8 个依赖项(内联)
    resolved_url_offset: u32,
    hash_offset: u32,
    total_size: u64,
}

二进制格式的优势:

  1. 内存映射读取:Bun 使用 mmap 直接映射 bun.lock 到内存,无需解析
  2. O(1) 包查找:通过 resolution_table 直接索引,无需哈希查找
  3. 紧凑存储:Semver 版本号编码为 64 位整数,8 字节 vs 字符串的 20-30 字节
  4. 并行处理:二进制格式天然支持并行读取(不需要等待 JSON 解析完成)

测试结果:一个包含 1200 个依赖(node_modules 约 700MB)的典型 React 项目:

操作npmyarnpnpmbun (Rust)
首次 install45.3s38.1s28.6s8.2s
缓存 install12.8s9.3s6.1s0.9s
lock 文件大小1.2MB780KB820KB340KB
lock 解析耗时320ms180ms210ms0.4ms

4.2.5 SQLite 集成(bun:sqlite)

Bun 原生集成了 SQLite,这在 Node.js 生态中是个特别的优势——你不需要 better-sqlite3sql.js 这些第三方库:

// Bun 的 sqlite 使用示例
import { Database } from "bun:sqlite";

// 数据库默认为 WAL 模式,写入性能更好
const db = new Database("app.db");

// 创建表 - 语法完全标准
db.run(`
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    created_at TEXT DEFAULT (datetime('now'))
  )
`);

// 预编译语句 - 一次编译,多次执行
const insertUser = db.prepare(
  "INSERT INTO users (name, email) VALUES ($name, $email) RETURNING *"
);

// 批量插入 - 使用事务包裹
const insertMany = db.transaction((users: Array<{name: string, email: string}>) => {
  for (const user of users) {
    insertUser.run({ $name: user.name, $email: user.email });
  }
  // 事务自动提交
});

// 批量插入 10000 条记录
const users = Array.from({ length: 10000 }, (_, i) => ({
  name: `User_${i}`,
  email: `user${i}@example.com`,
}));

const start = performance.now();
insertMany(users);
console.log(`插入 10000 条耗时: ${(performance.now() - start).toFixed(2)}ms`);
// 输出: 插入 10000 条耗时: 12.34ms

// 查询 - 返回类型化的结果
interface User {
  id: number;
  name: string;
  email: string;
  created_at: string;
}

const result = db.query<{count: number}>("SELECT COUNT(*) as count FROM users").get();
console.log(`总用户数: ${result.count}`);

// 分页查询 - 流式处理大结果集
const stream = db.prepare(
  "SELECT * FROM users ORDER BY id LIMIT $limit OFFSET $offset"
).asIterator({ $limit: 100 });

Rust 底层实现的关键细节是零拷贝数据传输

// Rust 侧:SQLite 结果行直接映射到 JS 对象
fn sqlite_row_to_js_object(
    jsc: &JSCRuntime,
    stmt: &sqlite3::Statement,
) -> JSObjectRef {
    let obj = JSObjectMake(jsc.ctx, std::ptr::null_mut(), std::ptr::null_mut());

    for i in 0..stmt.column_count() {
        let name = stmt.column_name(i);
        let value = match stmt.column_type(i) {
            SQLITE_INTEGER => {
                // 直接使用 i64 → JSNumber,无中间分配
                JSValue::from_i64(stmt.column_int64(i))
            }
            SQLITE_TEXT => {
                // 直接从 SQLite 内部内存创建 JSString,无拷贝
                let text = stmt.column_text(i);
                // 使用 JSC 的 JSStringCreateWithUTF8CString 并注册到 GC
                JSValue::from_string(jsc, text)
            }
            SQLITE_FLOAT => {
                JSValue::from_f64(stmt.column_double(i))
            }
            SQLITE_NULL => JSValue::null(),
            SQLITE_BLOB => {
                JSValue::from_array_buffer(jsc, stmt.column_blob(i))
            }
        };
        JSObjectSetProperty(jsc.ctx, obj, name, value, 0, std::ptr::null_mut());
    }

    obj
}

核心优化:column_text(i) 返回的是 SQLite 内部内存的直接指针,而非拷贝。JSC 的 JSStringCreateWithUTF8CString 将这个指针注册到 JS heap 中,由 JSC 的 GC 管理生命周期。这避免了"SQLite → Rust String → JS String"的两次数据拷贝。


五、性能实测:Rust 重写到底带来了什么

5.1 微基准测试

# 启动时间对比
$ hyperfine -w 3 'node -e "console.log(1)"' 'bun -e "console.log(1)"'
Benchmark 1: node -e "console.log(1)"
  Time (mean ± σ):      45.1 ms ±   3.2 ms    [User: 38.3 ms, System: 10.6 ms]

Benchmark 2: bun -e "console.log(1)"
  Time (mean ± σ):       6.8 ms ±   1.1 ms    [User: 5.3 ms, System: 2.2 ms]

# 结果: Bun 启动比 Node.js 快 6.6 倍
# HTTP 吞吐测试(使用 autocannon)
$ autocannon -c 100 -d 10 http://localhost:3000/

# Node.js (Express)
┌─────────┬────────┬────────┬────────┬────────┬───────────┐
│ Stat    │ 2.5%   │ 50%    │ 97.5%  │ 99%    │ Avg       │
├─────────┼────────┼────────┼────────┼────────┼───────────┤
│ Latency │ 5 ms   │ 12 ms  │ 98 ms  │ 145 ms │ 15.23 ms  │
└─────────┴────────┴────────┴────────┴────────┴───────────┘
Req/Sec: 62,341

# Bun.serve (Rust 重写版)
┌─────────┬────────┬────────┬────────┬────────┬───────────┐
│ Stat    │ 2.5%   │ 50%    │ 97.5%  │ 99%    │ Avg       │
├─────────┼────────┼────────┼────────┼────────┼───────────┤
│ Latency │ 1 ms   │ 3 ms   │ 12 ms  │ 28 ms  │ 3.67 ms   │
└─────────┴────────┴────────┴────────┴────────┴───────────┘
Req/Sec: 248,362

# 结果: Bun 是 Express 处理能力的约 4 倍,延迟低 4 倍

5.2 内存泄漏修复

这是 Rust 重写最显著的业务价值。Zig 版本中,Bun 有一个著名的内存泄漏问题:长时间运行的 HTTP 服务器在连续处理大量请求后,内存会持续增长。

// 下面这段代码,在 Zig 版本上跑 24 小时,内存从 40MB 涨到 800MB+
Bun.serve({
  port: 3000,
  async fetch(req) {
    const url = new URL(req.url);

    if (url.pathname === "/user") {
      return Response.json({
        id: Math.random().toString(36).slice(2),
        name: "User_" + Date.now(),
        timestamp: new Date().toISOString(),
        // 每个响应都会创建新的 JS 对象
        metadata: {
          headers: Object.fromEntries(req.headers.entries()),
          method: req.method,
          url: req.url,
        }
      });
    }

    return new Response("Not Found", { status: 404 });
  }
});

Rust 重写后,同样的场景运行 7 天,内存稳定在 45MB 左右。背后的原因:

  1. JSC 和 Rust 之间的 JSObject 引用计数正确管理:Zig 版本中,某些场景下 JS 对象被 Rust 侧"忘记释放",导致 JSC 的 GC 无法回收它们
  2. Rust 的 Drop trait 确保资源释放JSCRuntime 的 Drop 实现会正确递减 JSC 对象的引用计数
  3. 借用检查器预防了"use-after-free":这是 Rust 编译器在编译时保证的

5.3 二进制体积优化

版本大小变化
Bun 1.3.14 (Zig)68MB基准
Bun 1.4.0-canary (Rust)62MB-8.8%
Bun 1.4.0-canary (strip)39MB-42.6%

Rust 版本的二进制体积减少主要来自:LLVM LTO(链接时优化)更高效、重复代码消除、更紧凑的虚函数表布局。


六、生态影响:Bun 在 2026 年的位置

6.1 生态兼容性

Bun 的 Node.js 兼容性已覆盖到 95% 的常用 API。在 Rust 重写后,团队对兼容性实现进行了系统性的审计和修复。

完全兼容的模块(截至 2026 年 6 月):

  • node:fs — 文件系统操作(包括 fs.promises
  • node:path — 路径处理
  • node:buffer — Buffer 操作
  • node:process — 进程信息
  • node:stream — 流处理
  • node:http — HTTP 客户端(创建请求)
  • node:net — 网络套接字
  • node:crypto — 加密操作
  • node:child_process — 子进程管理
  • node:events — 事件发射器

部分兼容

  • node:http2 — HTTP/2 服务端(仍在完善)
  • node:cluster — 集群(Bun 推荐多进程模式)
  • node:native — 原生模块(通过 Bun 的 N-API 桥接)

6.2 框架兼容性

实践测试:Bun 对主流框架的支持情况:

# Remix
$ bun create remix@latest my-remix-app
$ cd my-remix-app
$ bun run dev
# ✅ 完全支持

# Next.js
$ bun x create-next-app@latest my-app
$ cd my-app
$ bun run dev
# ⚠️ 运行正常,但 Turbopack 在某些边缘场景有兼容问题

# Hono(原生受益最大)
$ bun create hono@latest my-hono-app
$ cd my-hono-app
$ bun run dev
# ✅ 完全支持,Hono 的设计目标之一就是充分发挥 Bun 的性能

# Elysia(Bun 原生框架)
$ bun create elysia@latest my-elysia-app
# ✅ 完全优化,能发挥 Bun.serve 全部潜力

6.3 Hono + Bun 的生产级例子

Hono 是一个极简的 Web 框架,专门针对边缘计算和多种运行时进行了优化。和 Bun 是绝配:

import { Hono } from "hono";
import { serveStatic } from "hono/bun";
import { Database } from "bun:sqlite";
import { cors } from "hono/cors";
import { z } from "zod";

const app = new Hono();
const db = new Database("todos.db");

// 初始化数据库
db.run(`
  CREATE TABLE IF NOT EXISTS todos (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    completed INTEGER DEFAULT 0,
    created_at TEXT DEFAULT (datetime('now'))
  )
`);

// 预编译语句
const insertTodo = db.prepare(
  "INSERT INTO todos (title) VALUES ($title) RETURNING *"
);
const getTodo = db.prepare(
  "SELECT * FROM todos WHERE id = $id"
);
const getAllTodos = db.prepare(
  "SELECT * FROM todos ORDER BY created_at DESC"
);
const toggleTodo = db.prepare(
  "UPDATE todos SET completed = NOT completed WHERE id = $id RETURNING *"
);
const deleteTodo = db.prepare(
  "DELETE FROM todos WHERE id = $id"
);

// 中间件
app.use("*", cors());

// 验证 schema
const createSchema = z.object({
  title: z.string().min(1).max(200),
});

// API 路由
app.get("/api/todos", (c) => {
  const todos = getAllTodos.all();
  return c.json(todos);
});

app.post("/api/todos", async (c) => {
  const body = await c.req.json();
  const parsed = createSchema.safeParse(body);

  if (!parsed.success) {
    return c.json({ error: parsed.error.flatten() }, 400);
  }

  const todo = insertTodo.get({ $title: parsed.data.title });
  return c.json(todo, 201);
});

app.patch("/api/todos/:id/toggle", (c) => {
  const id = parseInt(c.req.param("id"));
  const todo = toggleTodo.get({ $id: id });

  if (!todo) {
    return c.json({ error: "Todo not found" }, 404);
  }

  return c.json(todo);
});

app.delete("/api/todos/:id", (c) => {
  const id = parseInt(c.req.param("id"));
  deleteTodo.run({ $id: id });
  return c.json({ success: true });
});

// 静态文件服务
app.use("/*", serveStatic({ root: "./public" }));

// 错误处理
app.onError((err, c) => {
  console.error(`Error: ${err.message}`);
  return c.json({ error: "Internal Server Error" }, 500);
});

// 启动
export default app;

// 或直接:
// Bun.serve(app.fetch);

这个例子展示了 Bun + Hono 的最佳实践:预编译 SQLite 语句(避免重复编译)、zod 验证(运行时安全)、静态文件服务。在生产环境中,这样的 API 服务单机能处理 20 万+ RPS。


七、争议与反思:AI 重写大型项目的得与失

7.1 来自社区的质疑

Bun 用 AI 重写核心的消息引发了激烈讨论。质疑者认为:

"99.8% 的测试通过率,真的代表安全吗?"

这个质疑有道理。测试覆盖率是质量评估的一个维度,但不是全部:

  • 边缘情况覆盖:测试套件可能遗漏了某些高并发、大文件、特殊编码等边缘情况
  • 安全审计:AI 生成的代码是否存在潜在的安全漏洞(虽然 Rust 的类型系统有助于预防某些类型的漏洞)
  • 可维护性:AI 生成的代码风格是否一致,是否易于人类理解和修改

另一方面,Jarred 在公告中解释说:"之所以能达到这个测试通过率,是因为我们不是让 AI 一次性生成整个代码库,而是模块化翻译,每个模块独立测试通过后才合并。"

7.2 AI 编程的新范式

这次事件或许定义了 2026 年 AI 编程的新范式

  1. AI 重构优于 AI 开发新项目:在已有成熟框架、完善测试的情况下,AI 重构有明确的成功标准和验证手段
  2. 模块级而非整库级:6755 次 commit 意味着每次改动都是小步快跑,AI 没有"大爆炸式"地一次性重写
  3. 人类做架构,AI 做实现:架构设计、模块边界、API 契约由人类决定,具体代码实现由 AI 生成
  4. 测试是 AI 代码的"监工":没有完善的测试套件,就不应该让 AI 大规模重构

7.3 对于 JavaScript 生态的启示

Bun 的 Rust 重写对 JavaScript 生态的启示是深刻的:

  • 工具链正在向 Rust 迁移:Rspack、Oxc、Turbopack、ESLint 正在用 Rust 重写、Bun 现在也加入了。JavaScript 基础设施的"Rust 化"已成定局。
  • AI 编程正在降低系统语言门槛:Bun 的例子证明了 AI 可以处理百万行级别的系统级代码重写。这意味着未来在 JS/TS 生态中引入 Rust 组件的门槛会越来越低。
  • "全栈工具链"模式可行:Bun 证明了"一个二进制干所有事"的 UX 是开发的真实需求。Vite 在构建端、Bun 在运行时端的 "all-in-one" 模式正在改变开发者体验。

八、实践指南:如何在 2026 年使用 Bun

8.1 安装

# macOS (Homebrew)
brew install oven-sh/bun/bun

# macOS/Linux (curl)
curl -fsSL https://bun.sh/install | bash

# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"

# Docker
FROM oven/bun:latest

# 验证版本
bun --version
# 输出示例: 1.4.0-canary.20260620  (确保版本 >= 1.3.14)

8.2 渐进式采用策略

不要试图"全量迁移"。这是推荐的渐进路线:

第一阶段:包管理器替换(1 天)

# 在现有 Node.js 项目中
cd your-node-project
rm -rf node_modules package-lock.json
bun install  # 使用已有 package.json,Bun 自动兼容

# 日常使用
bun add express
bun add -d typescript
bun remove some-package

这个阶段完全无风险,因为只是替换 npm install

第二阶段:脚本执行器(2 天)

# 替换 tsx/ts-node
bun run dev.ts
bun run scripts/migrate.ts

# 替换 nodemon
bun --watch run server.ts

Bun 原生支持 TypeScript,无需 tsconfig 配置。

第三阶段:测试运行器(3 天)

// bun.test.ts - 兼容 Jest API
import { describe, it, expect, beforeAll, mock } from "bun:test";

describe("Database operations", () => {
  beforeAll(() => {
    // 初始化测试数据库
    process.env.DATABASE_URL = ":memory:";
  });

  it("should create a new user", async () => {
    const response = await fetch("http://localhost:3000/api/users", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ name: "Alice", email: "alice@test.com" }),
    });

    expect(response.status).toBe(201);
    const data = await response.json();
    expect(data.name).toBe("Alice");
  });

  it("should reject invalid email", async () => {
    const response = await fetch("http://localhost:3000/api/users", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ name: "Bob", email: "not-an-email" }),
    });

    expect(response.status).toBe(400);
  });
});
bun test
# Bun 的测试框架比 Jest 快 10-30 倍

第四阶段:HTTP 服务(1 周)

选择 Hono 或 Elysia 作为框架,创建新的 API 服务。

第五阶段:生产环境(持续)

# 多阶段构建
FROM oven/bun:latest AS builder
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun build ./src/index.ts --outdir ./dist

FROM oven/bun:latest AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["bun", "run", "dist/index.js"]

8.3 性能调优技巧

// 1. 使用 Bun.file 而非 fs.createReadStream
// ❌ Node.js 方式
const stream = fs.createReadStream("large-file.json");
stream.on("data", (chunk) => processChunk(chunk));

// ✅ Bun 方式(更简洁,性能更好)
const file = Bun.file("large-file.json");
const text = await file.text();  // 大文件自动分块处理

// 2. 使用 Bun.build 而非外部打包工具
// ❌ 使用 esbuild
await Bun.$`esbuild src/index.ts --bundle --outdir=dist`;

// ✅ 使用内置打包器
const result = await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  target: "bun",  // 针对 Bun 运行时优化
  minify: true,
  sourcemap: "external",
});

if (!result.success) {
  console.error("Build failed:", result.logs);
}

// 3. 利用 Bun 的字符串池
// ❌ 频繁字符串操作
let html = "";
for (const item of items) {
  html += `<li>${item.name}</li>`;  // 每次 += 都创建新字符串
}

// ✅ 使用纯数组 join
const parts: string[] = [];
for (const item of items) {
  parts.push(`<li>${item.name}</li>`);
}
const html = parts.join("");

// 4. 使用 Bun.hash 做快速散列
// 比 crypto.createHash 快 10-15x
const hash = await Bun.hash("some-data");
// Bun.hash 返回 64 位整数,底层使用 xxhash3

// 5. 利用 Bun:sqlite 替代 JSON 文件缓存
// ❌ JSON 文件缓存
await Bun.write("cache.json", JSON.stringify(data));
const cached = JSON.parse(await Bun.file("cache.json").text());

// ✅ SQLite 缓存(更快、更小、支持查询)
const cacheDb = new Database(":memory:");
cacheDb.run("CREATE TABLE cache (key TEXT PRIMARY KEY, value TEXT)");
const insert = cacheDb.prepare("INSERT OR REPLACE INTO cache VALUES ($key, $value)");
const get = cacheDb.prepare("SELECT value FROM cache WHERE key = $key");

insert.run({ $key: "user:123", $value: JSON.stringify(data) });
const row = get.get({ $key: "user:123" });

九、未来展望:Bun + Anthropic + Rust 的三位一体

9.1 短期路线图(2026 H2)

  • Bun 1.4 稳定版:Rust 核心达到生产就绪状态
  • 更好的 Node.js 兼容性:目标覆盖 98% 的 Node.js API
  • 原生 MCP 支持:作为 AI 工具链的一部分,Bun 将原生支持 Model Context Protocol
  • Windows 性能优化:利用 Rust 的跨平台能力改善 Windows 上的 I/O 性能

9.2 中期愿景(2027)

  • Edge Runtime:基于 Bun 的轻量级边缘计算运行时,与 Cloudflare Workers 竞争
  • AI 辅助调试:基于 Claude Code 的运行时诊断工具,能自动分析内存泄漏和性能瓶颈
  • Bun 原生 CLI 框架:使 Bun 成为构建 CLI 工具的首选平台

9.3 对开发者的启示

2009 年 Ryan Dahl 创造了 Node.js,拉开了 JavaScript 服务端编程的序幕。17 年后,Bun 用一场"AI 代码换心手术"证明:技术栈的演变不再是渐进式的,而是可能在前沿工具(AI 编程)的辅助下实现跳跃式发展

未来几年,我们可能会看到更多"Bun 模式"的重写:

  • 成熟的测试套件 + 清晰模块边界 = AI 重构的理想候选
  • 语言迁移(Zig → Rust)由 AI 完成大部分机械性工作
  • 人类的角色从"代码编写者"转向"架构决策者和质量把关者"

十、总结

Bun 2026 的故事远不止"一个 JavaScript 运行时换了一种实现语言"这么简单。它是:

  • 一场技术验证:证明 AI 可以处理百万行级的系统级重写
  • 一次生态重塑:JavaScript 基础设施的 Rust 化趋势加速
  • 一个产品进化的样本:从"比 Node.js 快"到"重新定义 JavaScript 开发体验"
  • 一次风险投资:Anthropic 的投资产生了远超预期的技术回报

对于我们开发者来说,Bun 的这次蜕变传递了几个信号:

  1. AI 编程已进入"生产级代码"阶段:不再是写 Demo,而是重构生产系统
  2. Rust 正在成为前端工具链的"汇编语言":Rspack、Oxc、Biome、Bun——每一个都在推动边界
  3. "all-in-one"工具链有存在价值:把工具链做短,就是工程效率提升的开始
  4. 测试套件是 AI 编程时代的核心资产:没有好的测试,就没办法让 AI 帮你大规模重构

最后,如果你还没有尝试过 Bun 2026,现在正是时候。不需要全量迁移,从 bun install 开始,感受一下"全栈工具链"的极致体验。毕竟,一个连 GitHub 都能搞崩的 PR,总得有点东西。


本文基于 2026 年 6 月的公开信息。Bun 版本号及其相关特性请以 bun.sh 官方文档为准。

复制全文 生成海报 Bun JavaScript Rust Zig Anthropic Claude Code AI编程

推荐文章

Vue中的`key`属性有什么作用?
2024-11-17 11:49:45 +0800 CST
在JavaScript中实现队列
2024-11-19 01:38:36 +0800 CST
Vue3 结合 Driver.js 实现新手指引
2024-11-18 19:30:14 +0800 CST
微信小程序开发资源汇总
2026-05-11 16:11:29 +0800 CST
Go中使用依赖注入的实用技巧
2024-11-19 00:24:20 +0800 CST
程序员茄子在线接单