编程 当 Bun 遇见 Claude:Bun v1.3 加入 Anthropic,JavaScript runtime 战争进入终局

2026-04-11 12:15:34 +0800 CST views 11

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.jsBun差异
QPS (Requests/sec)~42,000~95,000Bun 快 126%
平均延迟0.47ms0.21msBun 低 55%
P99 延迟2.1ms0.8msBun 低 62%
冷启动时间180ms8msBun 快 22.5x
内存占用 (idle)32MB18MBBun 低 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
包管理器时间说明
npm1m 23.4s串行安装,重度依赖重
yarn0m 45.2s并行,但仍有 lock 文件解析开销
pnpm0m 31.8s硬链接优化,磁盘占用小
bun0m 4.2s全局缓存 + 并行 + 跳过 lock 文件解析

bun install 的核心优化:

  • 跳过 package-lock.jsonyarn.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
估算 QPS43,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 编程工具和底层基础设施的整合进入了一个新阶段。作为程序员,我们能做的最好的事不是观望,而是尽快上手,在实践中理解这项技术的边界和可能性。

毕竟,技术判断力这种东西,光看书和文章是不够的,得真正用起来,才能知道它到底解决了什么问题,又在哪些地方力不从心。


参考资料

推荐文章

Vue 3 中的 Watch 实现及最佳实践
2024-11-18 22:18:40 +0800 CST
PHP解决XSS攻击
2024-11-19 02:17:37 +0800 CST
Go 开发中的热加载指南
2024-11-18 23:01:27 +0800 CST
ElasticSearch简介与安装指南
2024-11-19 02:17:38 +0800 CST
Node.js中接入微信支付
2024-11-19 06:28:31 +0800 CST
使用 node-ssh 实现自动化部署
2024-11-18 20:06:21 +0800 CST
Vue3中怎样处理组件引用?
2024-11-18 23:17:15 +0800 CST
Go的父子类的简单使用
2024-11-18 14:56:32 +0800 CST
在 Nginx 中保存并记录 POST 数据
2024-11-19 06:54:06 +0800 CST
PHP 命令行模式后台执行指南
2025-05-14 10:05:31 +0800 CST
pycm:一个强大的混淆矩阵库
2024-11-18 16:17:54 +0800 CST
为什么大厂也无法避免写出Bug?
2024-11-19 10:03:23 +0800 CST
一键配置本地yum源
2024-11-18 14:45:15 +0800 CST
一些实用的前端开发工具网站
2024-11-18 14:30:55 +0800 CST
WebSQL数据库:HTML5的非标准伴侣
2024-11-18 22:44:20 +0800 CST
JS 箭头函数
2024-11-17 19:09:58 +0800 CST
程序员茄子在线接单