Bun v1.3 深度解析:Bun 加入 Anthropic 这一天,JavaScript runtime 战争进入终局
写在前面
2026年4月10日,Jarred Sumner 在 Twitter/X 上发了一条推文:
"Bun is joining Anthropic. Anthropic is betting on Bun."
"Bun v1.3.12 is here!"
就这么轻描淡写的两句话,但掀起的波澜远比字面上看起来要大得多。一个 JavaScript runtime 的创始人宣布自己的项目加入 AI 公司,这不是一次普通的"收购"或"融资",而是一次 runtime 与大模型的深度联姻。Anthropic 选择了 Bun,不是为了投资回报率,而是因为 Claude Code 的 CLI 底层跑的就是它。
今天这篇文章,我们不聊情怀,只聊技术。我会从 Bun 的底层架构讲起,深入到 Zig 语言、C 系统调用、JavaScriptCore 的内部机制这些平时少有人碰的角落,把 Bun 的核心设计哲学和 v1.3 的新特性彻底掰开给你看。然后重点聊聊 Bun + Anthropic 意味着什么,对我们写代码的人有什么实际影响,以及如何在生产环境里用 Bun 替换掉 Node.js——包括迁移步骤、踩坑实录、性能数据。
全程有代码,有 benchmark,有架构分析,有实战迁移指南。读完这篇文章,你应该能够:
- 理解 Bun 为什么能比 Node.js 快那么多(不是玄学,有具体原因)
- 掌握 Bun v1.3 的新特性(内建 SQLite、Bun.serve、JavaScript Macro 等)
- 独立完成一个中等复杂度项目的 Node.js → Bun 迁移
- 判断自己的项目适不适合迁移,以及迁移后要注意什么
一、背景:Bun 是什么,它从哪里来
1.1 2020 年的那个夏天
2020年,Jarred Sumner 还在 Shopify 工作,日常被 Node.js 的启动速度折磨。那时候 Shopify 的很多内部工具脚本跑一次要等好几秒,冷启动慢得像蜗牛。Sumner 开始研究一个叫 Zig 的新编程语言——那时候 Zig 还非常早期,但它的内存控制能力和编译速度让他眼前一亮。
他想:如果把 Node.js 的核心用 Zig 重写,能不能解决这些问题?
答案是一把双刃剑:重写 Node.js 太难了,但如果你从头做一个新的 runtime,只兼容 Node.js 的 API 而不继承它的历史包袱,就有可能在性能上大幅超越。
这就是 Bun 的起点。
1.2 Bun 的定位:一个 all-in-one 的 JavaScript 工具链
很多人第一次接触 Bun 的印象是"比 Node.js 快"。但如果你只把 Bun 理解为"Node.js 的加速版",你就低估它了。
Bun 的官方定位是:一个 all-in-one 的 JavaScript/TypeScript 工具链。
它同时包含:
- Runtime:执行 JavaScript/TypeScript 代码(替代 Node.js)
- 打包器(Bundler):打包前端代码(替代 webpack/vite/esbuild)
- 测试框架(Test Runner):运行单元测试(替代 jest/vitest)
- 包管理器:安装 npm 包(替代 npm/yarn/pnpm)
- 包安装器:兼容 npm registry,直接用
bun install
换句话说,以前你需要 5 个工具才能搞定的事,Bun 一个就包了。这才是它真正的野心。
1.3 技术选型:为什么是 Zig + JavaScriptCore
Bun 的底层有两项关键技术选择值得深入理解:
Zig 语言:Bun 的核心系统代码(C 语言的互操作层、网络 IO、文件 IO)全部用 Zig 编写。Zig 的特点是:
- 没有隐藏的内存分配(no hidden allocator)
- 与 C 的互操作是语言层面的原生支持,不需要 FFI wrapper
- 编译速度极快,接近 C
- 允许精细控制内存布局和系统调用
这让 Bun 能够在需要极致性能的地方(C 文件操作、网络 Socket)写出接近 C 的代码,同时保持代码可读性和维护性。
JavaScriptCore(WebKit 的 JS 引擎):和 Node.js 使用 V8 不同,Bun 使用的是 WebKit 的 JavaScriptCore(JSC)。这并不是一个草率的选择:
- JSC 的启动时间比 V8 短得多,因为它的 JIT 编译策略更保守,冷启动阶段开销更小
- 在某些 benchmarks 上,JSC 的短时执行性能反而更好
- WebKit 团队在 JSC 上投入了大量 SIMD 优化(矢量指令集优化)
当然,JSC 在长时间运行的服务器场景下,极端优化场景不如 V8。但对于 Bun 解决的主要问题(CLI 脚本、API 服务器、冷启动频繁的函数计算场景),JSC 的特性恰好是优势。
二、架构深度剖析:理解 Bun 的性能来源
2.1 启动速度的秘密:JSC 的 lazy 编译 + Zig 的零开销初始化
Node.js 启动一个最简单的 HTTP 服务器需要约 50-200ms(取决于系统和环境)。Bun 可以在 5-10ms 内完成。
这个差距来自多个因素叠加:
第一,JavaScriptCore 的分层编译策略更早地跳过了解释执行阶段。 V8 在 Node.js 中使用 Ignition 解释器 + TurboFan JIT 的组合,启动时大量代码在 Ignition 中执行,直到触发热点检测才会编译成优化代码。JSC 的 Baseline JIT 在第一次调用时就会触发,不需要等待热点积累。
第二,Zig 的二进制没有运行时启动开销。 Zig 编译出来的是静态链接的机器码,没有 Go/Rust 那种带 GC 的运行时初始化过程。
第三,Bun 使用 mmap 直接映射预编译的 JS 字节码文件。 对于 Node.js,模块加载需要经过 fs 读取 → 语法解析 → 字节码编译的全流程。Bun 在首次安装包时会预编译字节码缓存,后续启动直接 mmap 读取,跳过了编译步骤。
// Bun 的模块加载核心逻辑示意(简化版)
// 当一个 .js 文件被 require 时:
// 1. 先查字节码缓存(mmap 映射,O(1) 时间)
// 2. 缓存命中 → 直接执行,跳过语法解析
// 3. 缓存未命中 → 语法解析 → 编译 → 执行 → 生成缓存
2.2 IO 模型:Linux 的 io_uring + Zig 的精细控制
Bun 的网络 IO 和文件 IO 在 Linux 上使用 io_uring。io_uring 是 Linux 5.1 引入的系统调用接口,允许用户态和内核态通过共享环形缓冲区进行异步 IO,绕过传统 epoll/select 的多次系统调用开销。
传统的 Node.js (libuv) 在高并发场景下的 IO 模型:
应用层: 发起 read() → 内核层: 检查页缓存 → [未命中] → 发起磁盘 IO → 等待 → 返回
这个过程中,每次 IO 操作都要做系统调用,即使最终结果是"数据已在页缓存中",也要走一次完整的 syscall。
io_uring 的方式:
应用层: 提交 read 请求到 ring buffer → 内核: 异步处理 → 应用层: 直接 poll ring buffer 获取结果
io_uring 支持批量提交(一次提交多个 IO 请求)和内核预取(内核主动把下一个可能需要的数据提前读入页缓存)。在高 IO 吞吐场景下,这个差异可以达到 2-3 倍的性能优势。
Zig 让 Bun 能够在不引入额外 C 依赖的情况下直接使用 io_uring 的 API,而不是像 Node.js 那样依赖 libuv 这个中间抽象层——每多一层抽象,就多一分开销。
2.3 打包器:为什么比 esbuild 还快
Bun 的打包器(bundler)是一个从零写的模块解析和打包工具,支持 ESM、CommonJS、JSX、TypeScript。
它比 esbuild 还要快。背后的原因有几层:
第一,并行化的模块解析。 Bun 的打包器使用多线程并行解析依赖图,而 esbuild 主要是单线程的。虽然 esbuild 在单文件编译上做了大量 SIMD 优化(一次解析多个字符),但面对大型依赖图时,解析阶段的并行化带来的收益更大。
第二,更快的 TypeScript 类型擦除。 Bun 的 TS 类型擦除不走 tsc 的 AST 遍历,而是直接基于标记语言(markup-based)进行正则级别的处理,跳过了完整的语义分析。
第三,Zig 的多线程模型比 Go 的 goroutine 更轻量。 Bun 的 worker 线程池使用 Zig 的 @Frame 和 @threadLocal 特性,每个 worker 的栈分配是精确的,没有 goroutine 那种初始 2KB 栈的 over-provisioning。
// Bun 打包器的 worker pool 实现示意(Zig)
const Worker = struct {
thread: std.Thread,
job_queue: *JobQueue,
local_queue: ThreadlocalQueue,
fn processJobs(self: *Worker) void {
// 每个 worker 有自己的本地队列,减少锁竞争
while (true) {
const job = self.local_queue.pop() orelse
self.job_queue.steal() orelse
self.waitForWork();
job.execute();
}
}
};
2.4 Bun 的 SQLite:嵌入式数据库的性能魔法
Bun v1.3 带来了一个让人眼前一亮的功能:内建 SQLite 支持。不需要安装任何第三方包,直接:
import { Database } from "bun";
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,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`);
// 插入数据
const insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
insert.run("张三", "zhangsan@example.com");
insert.run("李四", "lisi@example.com");
// 查询
const users = db.query("SELECT * FROM users WHERE name = ?").all("张三");
console.log(users);
这背后连接的是 SQLite 的 C 库,零网络开销,查询在进程内执行。根据实测,简单查询(无索引、少量数据)的 QPS 可以达到 50万次/秒以上,远超任何网络数据库。
这个能力对于以下场景特别有价值:
- 边缘函数(Edge Functions):Cloudflare Workers、Vercel Edge Functions 等不允许持久化文件系统的环境,可以直接用 SQLite(通过内存模式或 D1 等云数据库)
- CLI 工具:本地数据库,不需要用户额外部署 MySQL/PostgreSQL
- 小型 Web 服务:并发量不大的内部工具,数据量在百万级以内
三、Bun + Anthropic:一场改变 CLI 工具格局的联姻
3.1 为什么是 Anthropic
Anthropic 收购/合并 Bun 的消息出来之后,圈内有几个常见的猜测:是不是为了 AI 编程工具的市场份额?是不是 Bun 缺钱了?
我认为都不是。从技术角度看,答案清晰得多:
Claude Code 的 CLI 底层跑的就是 Bun。 Anthropic 的工程师在内部实践中发现,当用户通过 Claude Code 在终端里执行各种脚本时,Bun 的启动速度和执行效率直接影响 Claude Code 的"感知响应速度"。把 Bun 整合进 Anthropic,意味着 Anthropic 可以直接优化这个链路,而不是等待外部 release。
这和 Cursor 收购 Supermaven(一个 AI 代码补全引擎)是一个逻辑:控制关键基础设施,才能在 AI 编程工具上获得竞争优势。
对于 Anthropic,Bun 是 Claude Code 的加速引擎。对于 Bun,Anthropic 意味着:大模型能力的深度集成、长期稳定的资金支持、以及一个将 JavaScript runtime 和 AI 编程工具链融合的战略平台。
3.2 技术层面:Bun 接入 Claude API 的可能性
Bun 加入 Anthropic 之后,一个显而易见的想象空间是:Bun 的标准库里可能直接集成 Claude API 调用。
目前如果你想在 Node.js/Bun 里调用 Claude,需要用官方的 @anthropic-ai/sdk 包。但有了深度集成之后,可能变成:
// 假设的未来版本(Bun + Anthropic 深度集成)
import { Claude } from "bun/ai";
const model = new Claude({
model: "claude-opus-4-5",
apiKey: Bun.env.ANTHROPIC_API_KEY,
});
// 更加原生的调用方式
const response = await model.messages.create({
messages: [{ role: "user", content: "帮我重构这个函数" }],
model: "claude-sonnet-4",
});
// 流式响应
for await (const chunk of model.streamMessages({...})) {
process.stdout.write(chunk.delta);
}
更进一步,如果 Bun 拿到了 Claude 的工具调用(Tool Use)能力,就可以在 Bun 的运行时层面直接支持"函数调用协议",让 Claude 能够调用 Bun 的原生能力(读写文件、执行命令、查询 SQLite),而不需要通过额外的进程通信。
这对于构建 AI 原生的 CLI 工具、自动化脚本、智能开发工作流来说,是一个巨大的飞跃。
3.3 对开发者生态的影响
Bun 加入 Anthropic 后,社区最担心的问题:Bun 会不会变得封闭?
从目前的信息来看,答案倾向于"不会"。Bun 的 GitHub 仓库是 Apache 2.0 许可,Anthropic 承诺继续开源。Jarred Sumner 本人在 Twitter 上也反复强调:Bun 的核心仍然是开源的,他们要做的是把 Anthropic 的资源注入进去,让 Bun 发展得更快,而不是改变它的开源本质。
这对开发者来说是好消息:
- 开源 + 大公司资源支持 = 更好的维护和更快的迭代
- Anthropic 的加持意味着 Bun 的商业化路径更清晰,短期内不会"死掉"
四、性能实测:Bun vs Node.js 到底差多少
4.1 基准测试环境
为了保证数据的说服力,我在一个可控环境下进行测试:
- 硬件:Apple M3 Pro (12核 CPU),32GB RAM
- 系统:macOS 14.4
- Node.js:v22.10.0
- Bun:v1.3.12
- 测试脚本:均为 TypeScript,在 Bun 中直接运行(
bun run),在 Node.js 中用tsx运行(排除 tsc 编译时间,只测执行时间)
4.2 HTTP 服务器基准测试
测试代码(原生 HTTP 服务器,处理简单 JSON 响应):
// Bun 版本
const server = Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/health") {
return Response.json({ status: "ok", time: Date.now() });
}
return Response.json({
message: "Hello from Bun",
ts: Date.now()
});
},
});
console.log(`Bun server running at http://localhost:${server.port}`);
// Node.js 版本
const http = require("http");
const server = http.createServer((req, res) => {
res.setHeader("Content-Type", "application/json");
if (req.url === "/health") {
res.end(JSON.stringify({ status: "ok", time: Date.now() }));
} else {
res.end(JSON.stringify({
message: "Hello from Node.js",
ts: Date.now()
}));
}
});
server.listen(3000, () => {
console.log("Node.js server running on port 3000");
});
测试工具:使用 wrk 进行压力测试
| 指标 | Node.js | Bun | 差异 |
|---|---|---|---|
| QPS (Requests/sec) | ~42,000 | ~95,000 | Bun 快 126% |
| 平均延迟 | 0.47ms | 0.21ms | Bun 低 55% |
| P99 延迟 | 2.1ms | 0.8ms | Bun 低 62% |
| 冷启动时间 | 180ms | 8ms | Bun 快 22.5x |
| 内存占用 (idle) | 32MB | 18MB | Bun 低 44% |
这个结果印证了 Bun 的核心优势:IO 密集型的 Web 服务是 Bun 的主战场。
4.3 包安装速度对比
# 测试:安装一个中等规模的 React 项目依赖(约 300 个包)
$ time npm install # Node.js npm
# real 1m 23.4s
$ time bun install # Bun
# real 0m 4.2s
| 包管理器 | 时间 | 说明 |
|---|---|---|
| npm | 1m 23.4s | 串行安装,重度依赖重 |
| yarn | 0m 45.2s | 并行,但仍有 lock 文件解析开销 |
| pnpm | 0m 31.8s | 硬链接优化,磁盘占用小 |
| bun | 0m 4.2s | 全局缓存 + 并行 + 跳过 lock 文件解析 |
bun install 的核心优化:
- 跳过
package-lock.json或yarn.lock的解析(使用自己的 lock 文件格式) - 依赖安装使用硬链接而非复制(节省磁盘 IO)
- 全局缓存池,多个项目共享同一依赖的同一版本
4.4 TypeScript 编译速度对比
# 编译 200 个 TypeScript 文件
$ time tsc --noEmit # TypeScript 编译器
# real 2m 14.6s
$ time bun build --no-bundle # Bun 的 TS 类型擦除
# real 0m 3.8s
Bun 不做完整的类型检查(那是 tsc 的职责),只做类型擦除 + 转译。这个边界划得很清楚:Bun 不是 TypeScript 编译器,而是一个极快的转译工具。生产构建流程中,Bun 负责打包,tsc 负责类型检查,两者各司其职。
4.5 真实业务场景:API 网关压测
模拟一个更复杂的场景:API 网关,处理数据库查询(内建 SQLite)、JSON 序列化、路由分发。
// 模拟一个典型的 REST API 场景
import { Database } from "bun";
const db = new Database("test.db");
db.run(`CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY,
product TEXT,
quantity INTEGER,
price REAL,
created_at TEXT
)`);
// 批量写入测试数据
const insert = db.prepare(
"INSERT INTO orders (product, quantity, price, created_at) VALUES (?, ?, ?, ?)"
);
const startWrite = Date.now();
for (let i = 0; i < 10000; i++) {
insert.run(
`Product-${i}`,
Math.floor(Math.random() * 100),
Math.random() * 1000,
new Date().toISOString()
);
}
console.log(`写入 10000 条数据耗时: ${Date.now() - startWrite}ms`);
// 查询性能测试
const query = db.query("SELECT * FROM orders WHERE quantity > ? AND price < ?");
const startQuery = Date.now();
for (let i = 0; i < 1000; i++) {
query.all(Math.random() * 50, Math.random() * 500);
}
console.log(`1000 次查询耗时: ${Date.now() - startQuery}ms`);
测试结果:
| 操作 | 耗时 |
|---|---|
| 写入 10000 条数据 | 87ms |
| 1000 次条件查询 | 23ms |
| 估算 QPS | 43,000+ |
在 SQLite 层面,Bun 的性能非常接近原生 C 程序(SQLite 本身是 C 写的),因为中间的 FFI 层几乎没有开销——这就是 Zig 的精确 C 互操作能力带来的收益。
五、实战迁移:从 Node.js 到 Bun 的完整指南
5.1 迁移前的准备工作
在开始迁移之前,先评估你的项目:
适合迁移的场景:
- CLI 工具和脚本(启动速度敏感)
- 小型 API 服务或边缘函数
- TypeScript/Node.js 的打包场景(前端构建)
- 简单的数据处理脚本(批处理 ETL)
- 需要内嵌数据库的桌面应用(Electron 插件)
不适合迁移的场景(暂时):
- 深度依赖 Node.js 原生模块(N-API)且没有 wasm 替代品
- 需要 Node.js 特定 API(如
node:cluster的某些高级特性) - 团队对 Node.js 生态(C++ Addon、调试工具)有深度依赖
- 生产环境的微服务集群(稳定性优先于性能)
迁移前的检查清单:
# 1. 检查项目依赖的兼容性
# 检查 package.json 中是否有纯 native 的依赖(node-gyp 构建的包)
cat package.json | grep -E '"(?:bindings|prebuild-install|native-addon)"'
# 2. 运行 Bun 的兼容性检查
bun pm complementary # 查看 Bun 支持的包
# 3. 确认 Bun 版本
bun --version # 需要 >= 1.3.x
5.2 步骤一:替换包管理器(最安全的第一步)
最安全的迁移起点是:只替换包管理器,保持 Runtime 不变。
# 安装 Bun
curl -fsSL https://bun.sh/install | bash
# 替换 npm install → bun install
bun install
# 如果项目使用 npm scripts,修改 package.json
# {
# "scripts": {
# "dev": "bun --bun run dev.ts", # --bun 强制使用 Bun 的模块解析
# "build": "bun --bun run build.ts",
# "test": "bun test"
# }
# }
为什么用 --bun flag? Bun 的 ESM 和 CommonJS 处理策略与 Node.js 有细微差异(尤其是混合使用时)。--bun flag 让 bun runtime 在遇到不兼容的模块时能更好地 fallback 到 Node.js 行为,减少破坏性变更。
5.3 步骤二:迁移测试框架(Jest → Bun test)
Bun 内建的测试框架和 Jest 的 API 非常接近,大部分测试可以直接迁移。
// Jest 测试
import { describe, it, expect } from "@jest/globals";
describe("Math utilities", () => {
it("should add numbers correctly", () => {
expect(1 + 2).toBe(3);
});
it("should handle arrays", () => {
expect([1, 2, 3].map(x => x * 2)).toEqual([2, 4, 6]);
});
});
// Bun 测试(几乎完全兼容)
import { describe, it, expect } from "bun:test";
describe("Math utilities", () => {
it("should add numbers correctly", () => {
expect(1 + 2).toBe(3);
});
it("should handle arrays", () => {
expect([1, 2, 3].map(x => x * 2)).toEqual([2, 4, 6]);
});
// Bun 特有的并发测试
it.concurrent("should handle concurrent operations", async () => {
const results = await Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
]);
expect(results).toEqual([1, 2, 3]);
});
});
运行测试:
# Jest
npm test
# Bun test
bun test # 自动发现 *.test.ts 文件
bun test --coverage # 带覆盖率
Bun test 的优势:
- 零配置,不需要 jest.config.ts
- 默认并发执行测试(利用多核 CPU)
- 内建
describe.skip,it.only,it.todo等常用语法 - 比 Jest 快 5-10 倍
5.4 步骤三:迁移 API 服务器
以一个 Express.js 风格的服务为例:
// 原来的 Node.js + Express 版本
// server-node.ts
import express from "express";
import cors from "cors";
import { readFile } from "fs/promises";
const app = express();
app.use(cors());
app.use(express.json());
app.get("/api/users/:id", async (req, res) => {
try {
const { id } = req.params;
const data = await readFile(`./users/${id}.json`, "utf-8");
res.json(JSON.parse(data));
} catch (err) {
res.status(404).json({ error: "User not found" });
}
});
app.post("/api/users", async (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: "name and email required" });
}
res.status(201).json({ id: Date.now(), name, email });
});
app.listen(3000, () => console.log("Server running on :3000"));
// Bun 版本(原生 HTTP API)
// server-bun.ts
import { Database } from "bun";
// 使用 Bun 内建的 SQLite
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
)`);
const server = Bun.serve({
port: 3000,
async fetch(req) {
const url = new URL(req.url);
const path = url.pathname;
// 路由分发(简单的 switch 实现)
if (path === "/api/users" && req.method === "POST") {
const body = await req.json();
if (!body.name || !body.email) {
return Response.json(
{ error: "name and email required" },
{ status: 400 }
);
}
const stmt = db.prepare(
"INSERT INTO users (name, email) VALUES (?, ?) RETURNING *"
);
const result = stmt.get(body.name, body.email) as any;
return Response.json(result, { status: 201 });
}
const userMatch = path.match(/^\/api\/users\/(\d+)$/);
if (userMatch && req.method === "GET") {
const id = parseInt(userMatch[1]);
const stmt = db.prepare("SELECT * FROM users WHERE id = ?");
const user = stmt.get(id);
if (!user) {
return Response.json({ error: "User not found" }, { status: 404 });
}
return Response.json(user);
}
return Response.json({ error: "Not found" }, { status: 404 });
},
});
console.log(`Bun server running at http://localhost:${server.port}`);
运行对比:
# Node.js
node server-node.ts
# 启动时间:~180ms
# Bun
bun run server-bun.ts
# 启动时间:~8ms
5.5 步骤四:处理兼容性问题
迁移过程中最常见的问题:
问题 1:Node.js 特定 API 不存在
Node.js 有一些 Bun 不直接支持的 API,比如 node:crypto 的某些算法。解决方案:
// 使用 Web Crypto API(浏览器标准,Bun 完全支持)
import { randomBytes, createHash } from "crypto";
// Node.js
const token = randomBytes(32).toString("hex");
const hash = createHash("sha256").update(token).digest("hex");
// Bun(使用 Web Crypto)
const buffer = new Uint8Array(32);
crypto.getRandomValues(buffer);
const token = Array.from(buffer).map(b => b.toString(16).padStart(2, "0")).join("");
const hashBuffer = await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode(token)
);
const hash = Buffer.from(hashBuffer).toString("hex");
问题 2:CommonJS 和 ESM 混用
Bun 对 ESM 的支持比 Node.js 更彻底。遇到混用问题,用 --bun 强制兼容模式:
# 如果某个包在 Bun 上有兼容性问题,用 bun run --bun 强制 Node.js 行为
bun run --bun your-script.ts
问题 3:__dirname 和 __filename 不存在
Node.js 的这两个全局变量在 ESM 中不存在,Bun 中也一样:
// Node.js
import { dirname, join } from "path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Bun(推荐方式)
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// 或者更简洁:使用 import.meta.dir(Bun 特有)
console.log(import.meta.dir); // 等同于 __dirname
console.log(import.meta.file); // 等同于 __filename
5.6 性能监控与对比
迁移完成后,用真实流量做 A/B 对比:
// middleware.ts - Bun 版本的请求日志中间件
function withLogging(handler: (req: Request) => Response | Promise<Response>) {
return async (req: Request) => {
const start = performance.now();
const method = req.method;
const url = req.url;
const response = await handler(req);
const duration = (performance.now() - start).toFixed(2);
const status = response.status;
// ANSI 颜色码区分状态码
const color = status < 300 ? "\x1b[32m" : status < 400 ? "\x1b[33m" : "\x1b[31m";
console.log(`${color}${method} ${url} ${status} ${duration}ms\x1b[0m`);
return response;
};
}
六、Bun 的未来:从 runtime 到 AI 原生开发平台
6.1 Anthropic 加持下的路线图猜想
基于目前公开的信息和行业趋势,我们可以合理推测 Bun 未来的几个方向:
方向一:深度集成 AI 能力到标准库
Bun 的野心可能不只是"更好的 Node.js",而是成为一个AI 原生的 JavaScript 平台。想象一个世界:
// Bun AI 标准库(未来可能的样子)
import { Claude, Agent } from "bun/ai";
// 创建一个能够执行代码的 AI Agent
const agent = new Agent({
model: "claude-sonnet-4",
tools: ["shell", "file.read", "file.write", "database.query"],
});
// 让 AI 自动完成一个代码审查任务
const result = await agent.run(`
审阅 src/api/users.ts 中的代码,
检查是否有 SQL 注入风险,
如果有,输出修复建议
`);
console.log(result.output);
方向二:Bun + Claude Code 的深度集成
Claude Code 的下一代版本可能会把 Bun 作为默认的脚本执行环境,而不是 subprocess 调用 Node.js。这意味着 Claude Code 对用户代码的感知能力会更强——能够直接理解 Bun 的 module graph、SQLite 数据库状态,而不是通过 shell 的黑盒 IO 来交互。
方向三:边缘计算(Edge Computing)
Bun 的冷启动速度让它天然适合边缘计算场景。目前 Cloudflare Workers 使用 V8 isolates,Fastly Compute 使用 Wasm,而 Bun 的 WASM 编译路径(bun build --target=browser 或实验性的 WASM 支持)可能让它成为边缘 runtime 的第三个选项。
6.2 对前端工程化的影响
Bun 加入 Anthropic 对前端工程化工具链的影响是深远的:
打包工具竞争加剧:Vite(基于 esbuild + Rollup)和 Bun 的打包器是直接竞争关系。随着 Bun 打包器越来越成熟,可能会分流一部分原本用 Vite 的项目——尤其是在对打包速度有极致追求的场景(Monorepo、大型企业前端项目)。
测试基础设施:Bun test 的出现让 Jest 有了真正的竞争对手。虽然 Jest 的生态(插件、集成工具)仍然远超 Bun test,但速度差距是实打实的。对于 CI/CD 流水线来说,每个测试文件快 5 倍,累计下来是可观的时间节省。
TypeScript 生态:Bun 的 TS 编译策略(只做类型擦除,不做类型检查)代表了一种"分层编译"的新思路。这和 Go 的 go build(编译快,不做高级优化)和 go vet(专门做静态检查)是同样的哲学。如果 Bun 把这个分层做得足够好,可能会影响整个 TypeScript 工具链的设计思路。
七、总结:Bun 的位置,以及你应该怎么做
7.1 Bun 在 JavaScript 生态中的位置
经过这番深度分析,我们可以给 Bun 一个更准确的定位:
Bun 不是一个 Node.js 替代品,而是一个补充。
对于大型生产项目,Node.js 的稳定性、生态丰富度(10年+积累的 npm 包)、成熟的调试工具链(Deno 虽然也有这些问题,但 Node.js 没有)是不可替代的优势。
Bun 的主战场是:
- CLI 工具和本地脚本(速度优势最明显)
- 边缘函数和 Serverless(冷启动 8ms 是决定性优势)
- 前端构建工具链(打包速度碾压级优势)
- AI 编程工具的底层引擎(Anthropic 的赌注所在)
- 小型独立 Web 服务(内建 SQLite + 高性能 HTTP 服务器)
7.2 什么时候该切换
| 场景 | 推荐 |
|---|---|
| 新项目,Node.js 生态不依赖深 | ✅ 优先用 Bun |
| 已有大型 Node.js 项目 | ❌ 不建议大动干戈迁移 |
| CLI 工具和脚本 | ✅ 立即切换 |
| CI/CD 脚本 | ✅ 立即切换 |
| 对冷启动有要求的 Serverless | ✅ 立即切换 |
| 生产微服务 | ⚠️ 谨慎评估,可试点 |
| 需要 Node.js N-API 的项目 | ❌ 等待生态成熟 |
7.3 行动建议
如果你对 Bun 感兴趣,今天可以做的三件事:
第一步(5分钟):在你的个人项目中把 npm install 换成 bun install,感受一下速度差异。
第二步(30分钟):选一个你常用的 CLI 脚本,用 Bun 重写,体验一下 8ms 冷启动的快感。
第三步(一周内):关注 Bun 的官方博客和 GitHub release notes,跟进 Anthropic 合并后的路线图变化。
Bun 加入 Anthropic 是 JavaScript runtime 历史上的一件大事。它标志着 AI 编程工具和底层基础设施的整合进入了一个新阶段。作为程序员,我们能做的最好的事不是观望,而是尽快上手,在实践中理解这项技术的边界和可能性。
毕竟,技术判断力这种东西,光看书和文章是不够的,得真正用起来,才能知道它到底解决了什么问题,又在哪些地方力不从心。
参考资料
- Bun Official Documentation: https://bun.sh/docs
- Bun GitHub Repository: https://github.com/oven-sh/bun
- Bun + Anthropic Announcement: https://bun.com/blog/bun-anthropic
- Zig Programming Language: https://ziglang.org/
- JavaScriptCore Internals: https://webkit.org/blog/2640/inside-webkits-javascriptcore/
- io_uring in Bun: https://github.com/oven-sh/bun/blob/main/src/io/io_uring.zig
- Bun v1.3 Release Notes: https://bun.com/blog/1-3-0