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 更适合我们。"
四条技术理由支撑了这个当时看来"疯狂"的选择:
- 免 GC 零运行时:和 Rust 一样,Zig 没有垃圾回收,适合做运行时基础设施
- 编译速度极快:Zig 编译器比 LLVM-based 的 Rustc 快数倍,这对迭代速度极其重要
- comptime(编译期计算):Zig 的编译期代码执行能力让它能写出高度优化的泛型代码
- 直接暴露内存分配器: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 重写的原因包括:
| 维度 | Zig | Rust | 重写后的优势 |
|---|---|---|---|
| 内存安全 | 开发者手动管理 | 编译器借用检查 | 彻底杜绝悬垂指针和缓冲区溢出 |
| 异步支持 | 无内置 async/await | tokio + 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 默认的 jemalloc 或 glibc 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版) |
|---|---|---|---|
| 启动时间 | 48ms | 8ms | 7ms |
| 请求/秒 (hello world) | 95,000 | 265,000 | 271,000 |
| 请求/秒 (JSON 路由) | 72,000 | 198,000 | 205,000 |
| 最大并发连接 | 8,192 | 65,536 | 65,536 |
| 内存占用 (10k 并发) | 280MB | 145MB | 132MB |
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,
}
二进制格式的优势:
- 内存映射读取:Bun 使用
mmap直接映射 bun.lock 到内存,无需解析 - O(1) 包查找:通过 resolution_table 直接索引,无需哈希查找
- 紧凑存储:Semver 版本号编码为 64 位整数,8 字节 vs 字符串的 20-30 字节
- 并行处理:二进制格式天然支持并行读取(不需要等待 JSON 解析完成)
测试结果:一个包含 1200 个依赖(node_modules 约 700MB)的典型 React 项目:
| 操作 | npm | yarn | pnpm | bun (Rust) |
|---|---|---|---|---|
| 首次 install | 45.3s | 38.1s | 28.6s | 8.2s |
| 缓存 install | 12.8s | 9.3s | 6.1s | 0.9s |
| lock 文件大小 | 1.2MB | 780KB | 820KB | 340KB |
| lock 解析耗时 | 320ms | 180ms | 210ms | 0.4ms |
4.2.5 SQLite 集成(bun:sqlite)
Bun 原生集成了 SQLite,这在 Node.js 生态中是个特别的优势——你不需要 better-sqlite3 或 sql.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 左右。背后的原因:
- JSC 和 Rust 之间的 JSObject 引用计数正确管理:Zig 版本中,某些场景下 JS 对象被 Rust 侧"忘记释放",导致 JSC 的 GC 无法回收它们
- Rust 的 Drop trait 确保资源释放:
JSCRuntime的 Drop 实现会正确递减 JSC 对象的引用计数 - 借用检查器预防了"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 编程的新范式:
- AI 重构优于 AI 开发新项目:在已有成熟框架、完善测试的情况下,AI 重构有明确的成功标准和验证手段
- 模块级而非整库级:6755 次 commit 意味着每次改动都是小步快跑,AI 没有"大爆炸式"地一次性重写
- 人类做架构,AI 做实现:架构设计、模块边界、API 契约由人类决定,具体代码实现由 AI 生成
- 测试是 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 的这次蜕变传递了几个信号:
- AI 编程已进入"生产级代码"阶段:不再是写 Demo,而是重构生产系统
- Rust 正在成为前端工具链的"汇编语言":Rspack、Oxc、Biome、Bun——每一个都在推动边界
- "all-in-one"工具链有存在价值:把工具链做短,就是工程效率提升的开始
- 测试套件是 AI 编程时代的核心资产:没有好的测试,就没办法让 AI 帮你大规模重构
最后,如果你还没有尝试过 Bun 2026,现在正是时候。不需要全量迁移,从 bun install 开始,感受一下"全栈工具链"的极致体验。毕竟,一个连 GitHub 都能搞崩的 PR,总得有点东西。
本文基于 2026 年 6 月的公开信息。Bun 版本号及其相关特性请以 bun.sh 官方文档为准。