为什么需要关注 Bun?
如果你是一名 JavaScript/TypeScript 开发者,可能已经对 Node.js 和 Deno 非常熟悉。但最近两年,一个名为 Bun 的运行时正在快速崛起。它由 Jarred Sumner 创建,目标是提供一个更快、更简洁、更集成的 JavaScript 工具链。
Bun 不仅是一个运行时,还内置了包管理器、打包器、测试运行器,甚至支持 TypeScript 和 JSX 开箱即用。根据官方基准测试,Bun 的启动速度和 HTTP 吞吐量都显著优于 Node.js。
这篇文章将带你从零开始,逐步了解 Bun 的核心功能,并通过一个完整的 REST API 示例,展示如何在实际项目中应用它。我们还会探讨 Bun 的生态现状、最佳实践以及一些常见的坑。
—
1. 安装 Bun
Bun 支持 macOS、Linux 和 Windows(WSL)。安装非常简单,一行命令即可:
# macOS / Linux
curl -fsSL https://bun.sh/install | bash
# Windows (使用 PowerShell)
irm bun.sh/install.ps1 | iex
安装完成后,验证版本:
bun --version
# 输出示例:1.1.34
💡 注意:Bun 的版本迭代非常快,建议定期使用 bun upgrade 更新到最新版。
—
2. 第一个 Bun 程序
创建一个简单的 hello.ts 文件:
const message: string = "Hello, Bun!";
console.log(message);
直接运行:
bun run hello.ts
你会发现 Bun 直接执行了 TypeScript 文件,无需任何编译步骤。这是 Bun 的一大亮点:原生支持 TypeScript 和 JSX。
—
3. 使用 Bun 作为包管理器
Bun 内置了包管理器,兼容 npm 生态,但速度更快。初始化项目:
mkdir bun-demo && cd bun-demo
bun init -y
这会生成 package.json、tsconfig.json 等文件。安装依赖:
bun add express
bun add -d @types/express
Bun 会生成 bun.lockb 二进制锁文件,比 package-lock.json 更紧凑。
💡 最佳实践:在 CI 环境中使用 bun install --frozen-lockfile 确保依赖一致性。
—
4. 构建一个 REST API
让我们用 Bun 原生 HTTP 服务器(Bun.serve)创建一个简单的用户管理 API。
创建 server.ts:
interface User {
id: number;
name: string;
email: string;
}
const users: User[] = [
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" },
];
const server = Bun.serve({
port: 3000,
async fetch(req) {
const url = new URL(req.url);
// GET /users
if (req.method === "GET" && url.pathname === "/users") {
return Response.json(users);
}
// GET /users/:id
const match = url.pathname.match(/^\/users\/(\d+)$/);
if (req.method === "GET" && match) {
const id = parseInt(match[1]);
const user = users.find((u) => u.id === id);
if (!user) {
return new Response("User not found", { status: 404 });
}
return Response.json(user);
}
// POST /users
if (req.method === "POST" && url.pathname === "/users") {
const body = await req.json();
const newUser: User = {
id: users.length + 1,
name: body.name,
email: body.email,
};
users.push(newUser);
return Response.json(newUser, { status: 201 });
}
return new Response("Not Found", { status: 404 });
},
});
console.log(`Server running at http://localhost:${server.port}`);
运行:
bun run server.ts
测试 API:
curl http://localhost:3000/users
curl http://localhost:3000/users/1
curl -X POST http://localhost:3000/users -H "Content-Type: application/json" -d '{"name":"Charlie","email":"charlie@example.com"}'
你会发现 Bun.serve 的 API 非常简洁,且性能出色。根据官方基准,它比 Node.js 的 HTTP 模块快数倍。
—
5. 使用 Bun 测试
Bun 内置了测试运行器,语法类似 Jest,但速度更快。创建 server.test.ts:
import { describe, expect, test, beforeAll, afterAll } from "bun:test";
let server: any;
beforeAll(() => {
// 启动测试服务器
server = Bun.serve({
port: 3001,
fetch: (req) => {
if (new URL(req.url).pathname === "/users") {
return Response.json([{ id: 1, name: "Alice" }]);
}
return new Response("Not Found", { status: 404 });
},
});
});
afterAll(() => {
server.stop();
});
describe("User API", () => {
test("GET /users returns list", async () => {
const res = await fetch("http://localhost:3001/users");
const data = await res.json();
expect(res.status).toBe(200);
expect(data).toHaveLength(1);
expect(data[0].name).toBe("Alice");
});
test("unknown route returns 404", async () => {
const res = await fetch("http://localhost:3001/unknown");
expect(res.status).toBe(404);
});
});
运行测试:
bun test
Bun 的测试运行器支持 TypeScript、JSX、模拟(mock)等,且无需额外配置。
—
6. 打包与构建
Bun 也可以作为打包器使用。例如,将 server.ts 打包成单个文件:
bun build ./server.ts --outdir ./dist --target bun
对于前端项目,可以指定 --target browser:
bun build ./src/index.tsx --outdir ./dist --target browser --minify
Bun 的打包器速度极快,且支持代码分割、Tree Shaking 等特性。
—
7. 生态概览与兼容性
Bun 的目标是兼容 Node.js 生态。目前,大部分 npm 包都可以直接在 Bun 中运行。但仍有少数包依赖 Node.js 内部模块或原生插件,可能无法工作。
兼容性现状:
- 核心 Node.js 模块(
fs、path、http等)已实现。 node-gyp原生模块支持正在完善中。- 许多流行框架(Express、Hono、Elysia)已适配 Bun。
Bun 专属生态:
- Elysia:一个为 Bun 设计的快速 Web 框架。
- Bun SQLite:内置 SQLite 驱动,无需安装。
- Bun FFI:直接调用 C 函数。
💡 建议:在新项目中可以大胆尝试 Bun;对于现有大型项目,建议先进行兼容性测试。
—
8. 常见坑与最佳实践
坑 1:环境变量加载
Bun 会自动加载 .env 文件,但不会覆盖已存在的环境变量。如果需要强制覆盖,使用 --env-file 或手动处理。
坑 2:TypeScript 配置
Bun 使用自己的 TypeScript 转译器,某些 tsconfig.json 选项可能不被支持。建议参考官方推荐的配置:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"types": ["bun-types"],
"strict": true,
"skipLibCheck": true
}
}
坑 3:与 Node.js 的差异
Bun.serve的fetch函数返回Response对象,而非 Node.js 的IncomingMessage。- 文件系统 API 略有不同,例如
Bun.file()返回BunFile对象。
最佳实践
- 使用
bun --watch实现热重载。 - 在
package.json中定义脚本,如"start": "bun run server.ts"。 - 利用
Bun.env访问环境变量。
—
9. 总结与下一步
Bun 是一个令人兴奋的运行时,它通过集成工具链和极致的性能,为 JavaScript 开发带来了新的可能。本文介绍了安装、包管理、HTTP 服务、测试、打包等核心功能,并给出了一个完整的 REST API 示例。
下一步学习方向:
- 探索 Elysia 框架构建更复杂的应用。
- 使用 Bun 的 SQLite 驱动进行数据持久化。
- 了解 Bun 的插件系统与 FFI。
Bun 仍在快速发展,建议关注官方博客和 GitHub 仓库,及时获取最新动态。
—
延伸阅读: