8.1 兼容性总览
Bun 2.0 对 Node.js API 的兼容程度(Bun 官方自测 + 社区验证):
| 模块/功能 | 兼容度 | 备注 |
|---|---|---|
| node:fs, fs/promises | ~99% | 极少数 edge case 行为略异 |
| node:path, node:url | 100% | |
| node:http, https | ~98% | 推荐新代码用 Bun.serve |
| node:net, tls | ~95% | |
| node:stream | ~95% | 复杂 duplex 场景需测 |
| node:events | 100% | |
| node:crypto | ~97% | |
| node:child_process | ~95% | 推荐 Bun.spawn |
| node:worker_threads | ✅ | |
| node:cluster | ✅ (1.2+) | |
| node:vm | 部分 | |
| CommonJS(require) | 100% | 可与 ESM 混用 |
| node-gyp 原生模块(.node) | 大部分可用 | 需重编译某些 |
| Express / Fastify / Koa | ✅ 直接跑 | |
| Next.js | 部分 | 建议先看官方状态 |
| Prisma | ✅ | 需 trustedDependencies |
查官方最新兼容表:bun.sh/docs/runtime/nodejs-apis
8.2 process / globalThis
process.argv // ✅
process.env // ✅
process.cwd() // ✅
process.platform / arch // ✅
process.versions.bun // Bun 特有,Node 下为 undefined
process.versions.node // Bun 伪装成兼容 Node 版本(为第三方库)
globalThis.Bun // 全局 Bun 对象
8.3 CommonJS 与 ESM 互操作
Bun 里 CJS 和 ESM 可以互相 import:
// CJS 文件
const fs = require("node:fs");
module.exports = { greet: () => "hi" };
// ESM 文件
import mod from "./cjs-file.cjs"; // ✅ 能 import
import { readFileSync } from "./cjs-file.cjs"; // ✅ 能解构
这比 Node 自己的兼容更宽松——Node 从 CJS 到 ESM 的互操作限制更多。
8.4 typescript 配置
用 bun init 生成的 tsconfig 已含 Bun 类型。手动配时关键项:
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "bundler",
"types": ["bun-types"], // 或 npm i -D @types/bun
"lib": ["esnext", "dom"],
"allowJs": true,
"strict": true,
"noEmit": true // Bun 不需要 tsc 编译
}
}
8.5 替换清单:迁移一个 Node 项目
第一阶段:不改代码,直接跑
$ bun install
$ bun run start
多数情况直接就能跑。不能跑通常是:
- 某个 postinstall 被 Bun 默认拒绝——在 package.json 加
trustedDependencies - 某个 CJS 原生模块未编译——运行
bun install --force或查清楚包名加到 trustedDependencies - 用了某个尚不兼容的 Node API——查 bun.sh/docs 对照
第二阶段:渐进式用 Bun 原生 API
| Node | Bun 原生(更快) |
|---|---|
| fs.readFile | Bun.file(...).text() |
| fs.writeFile | Bun.write(path, data) |
| http.createServer | Bun.serve({ fetch }) |
| child_process.spawn | Bun.spawn |
| bcrypt | Bun.password |
| better-sqlite3 | bun:sqlite |
| ws | Bun.serve + websocket |
| dotenv | 自动加载 |
| jest | bun test |
每次换一个,独立 commit——方便 rollback。
8.6 常见坑
坑 1:postinstall 被默认跳过
现象:装了某包但用不了,检查 node_modules 里对应目录是空的。解决:bun pm untrusted 查看被阻止的脚本,然后 bun pm trust <package>。
坑 2:node-gyp 编译失败
现象:node-gyp rebuild 错误。一般是 Bun 没能自动触发编译,或 .node 原生模块与 Bun 的 Node-API 版本不匹配。解决:
- 确保装了 Python 3 和 C++ 工具链
bun install --force- 用 pure-JS 替代版(如
better-sqlite3改bun:sqlite)
坑 3:__dirname / __filename 在 ESM 下不存在
Node ESM 里要用:
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
Bun 里也同理。或直接用 import.meta.dir/import.meta.file(Bun 扩展)。
坑 4:某些包只支持 V8
如 v8-profiler、某些 monkey-patch V8 内部的工具——Bun 的 JSCore 跑不了。这类包通常非核心业务(性能分析、IDE 工具)。
8.7 调试
断点调试
$ bun --inspect src/server.ts
# 打开返回的 chrome://inspect URL 连接 Chrome DevTools
$ bun --inspect-wait src/server.ts
# 等待调试器连接才执行(便于打第一条断点)
VS Code 用 Bun 扩展即可原生支持 Launch / Attach。
日志
console.log、console.table、console.dir 与 Node 基本一致,但 Bun 的 Bun.inspect(x) 更强大,支持循环引用、带颜色。
8.8 性能剖析
$ bun --hot --inspect=0.0.0.0:9229 server.ts
# 然后在 chrome://inspect 里 CPU profile
# 采样型 profiler(v1.2+)
$ bun run --profiler src/server.ts
8.9 与 pm2 / forever 等进程管理器
Bun 可以被 pm2 管理(当 Node 使):
pm2 start "bun run start" --name api --interpreter none
或使用 Bun 1.2+ 的 node:cluster 模式做多进程。
8.10 小结
- Bun 兼容 Node API ~95%+,Express/Fastify/Prisma 都能直接跑。
- 迁移两阶段:先"换解释器"不改代码,再渐进式换 Bun 原生 API 提速。
- 主要坑:postinstall trust、node-gyp 编译、ESM __dirname、V8 特定包。
- 调试:
bun --inspect+ Chrome DevTools / VS Code。