跳转至

Bun 运行时

为什么要学

Bun 是用 Zig 编写的全新 JavaScript/TypeScript 运行时,目标是替代 Node.js + npm + webpack 的整个工具链:

  • 极快的速度:启动速度比 Node.js 快 4 倍,包安装比 npm 快 25 倍
  • All-in-One:运行时 + 包管理器 + 打包器 + 测试运行器
  • 原生 TypeScript:无需 tsc 或 ts-node,直接运行 .ts 文件
  • Node.js 兼容:大部分 npm 包和 Node.js API 直接可用
  • 内置 Web API:fetch、WebSocket、FormData 等开箱即用
  • SQLite 内置:bun:sqlite 原生模块

如果你想要更快的 JS/TS 开发体验并减少工具链复杂度,Bun 值得尝试。

核心概念

白话解释

Bun 就像一个"瑞士军刀"——把你需要的 JavaScript 工具全集成在一个程序里: - 以前:Node.js(运行) + npm(安装包) + webpack(打包) + jest(测试) + tsc(TypeScript) - 现在:bun(全搞定)

核心概念对照表

Bun 功能替代工具提升
bun runnode / ts-node直接运行TS, 更快启动
bun installnpm / yarn / pnpm安装速度25x+
bun buildwebpack / esbuild内置打包
bun testjest / vitestJest兼容, 更快
Bun.serve()express / fastify内置HTTP服务器
bun:sqlitebetter-sqlite3原生SQLite
bunxnpx更快执行

安装配置

安装

# macOS/Linux
curl -fsSL https://bun.sh/install | bash

# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"

# Homebrew
brew install oven-sh/bun/bun

# 验证
bun --version

项目初始化

# 创建新项目
bun init

# 目录结构:
# ├── index.ts
# ├── package.json
# ├── tsconfig.json
# └── bun.lockb (二进制lockfile)

包管理

# 安装依赖(极快)
bun install

# 添加包
bun add express
bun add -d @types/express  # 开发依赖
bun add -g typescript      # 全局安装

# 移除包
bun remove express

快速上手

运行 TypeScript

// index.ts - 无需任何配置直接运行
const greeting: string = "Hello from Bun!";
console.log(greeting);

interface User {
  name: string;
  age: number;
}

const user: User = { name: "张三", age: 25 };
console.log(user);
bun run index.ts
# 或直接
bun index.ts

HTTP 服务器

// server.ts
const server = Bun.serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);

    if (url.pathname === "/") {
      return new Response("Hello Bun!");
    }

    if (url.pathname === "/json") {
      return Response.json({ message: "Hello", timestamp: Date.now() });
    }

    if (url.pathname === "/api/users" && req.method === "POST") {
      return handleCreateUser(req);
    }

    return new Response("Not Found", { status: 404 });
  },
});

async function handleCreateUser(req: Request): Promise<Response> {
  const body = await req.json();
  return Response.json({ id: 1, ...body }, { status: 201 });
}

console.log(`Server running at http://localhost:${server.port}`);
bun run server.ts

文件操作

// Bun内置快速文件API
const file = Bun.file("./data.json");

// 读取
const content = await file.text();
const json = await file.json();

// 写入
await Bun.write("./output.txt", "Hello World");
await Bun.write("./data.json", JSON.stringify({ key: "value" }));

// 文件信息
console.log(file.size);  // 字节数
console.log(file.type);  // MIME类型

进阶用法

1. 内置测试

// math.test.ts
import { expect, test, describe, beforeAll } from "bun:test";

describe("数学函数", () => {
  test("加法", () => {
    expect(1 + 1).toBe(2);
  });

  test("异步操作", async () => {
    const result = await fetchData();
    expect(result).toBeDefined();
  });

  test("快照测试", () => {
    const obj = { name: "test", values: [1, 2, 3] };
    expect(obj).toMatchSnapshot();
  });
});
bun test                # 运行所有测试
bun test --watch        # 监听模式
bun test --coverage     # 覆盖率

2. 打包构建

// build.ts
await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  target: "browser",  // browser | bun | node
  format: "esm",
  minify: true,
  sourcemap: "external",
  splitting: true,  // 代码分割
  external: ["react", "react-dom"],  // 外部依赖
});
bun build ./src/index.ts --outdir ./dist --minify

3. SQLite (内置)

import { Database } from "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 insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
insert.run("张三", "zhangsan@example.com");

// 查询
const users = db.query("SELECT * FROM users WHERE name LIKE ?").all("%张%");
console.log(users);

// 事务
const insertMany = db.transaction((users) => {
  for (const user of users) {
    insert.run(user.name, user.email);
  }
});

insertMany([
  { name: "李四", email: "lisi@example.com" },
  { name: "王五", email: "wangwu@example.com" },
]);

4. WebSocket 服务器

const server = Bun.serve({
  port: 3000,
  fetch(req, server) {
    // 升级到WebSocket
    if (server.upgrade(req)) return;
    return new Response("HTTP fallback");
  },
  websocket: {
    open(ws) {
      console.log("连接已建立");
      ws.subscribe("chat");
    },
    message(ws, message) {
      // 广播给所有订阅者
      ws.publish("chat", `用户说: ${message}`);
    },
    close(ws) {
      console.log("连接已关闭");
    },
  },
});

console.log(`WebSocket server on ws://localhost:${server.port}`);

5. 环境变量与配置

// .env文件自动加载(无需dotenv)
// .env
// DATABASE_URL=postgresql://localhost/mydb
// API_KEY=secret123

console.log(Bun.env.DATABASE_URL);
console.log(Bun.env.API_KEY);

// bunfig.toml - Bun配置文件
# bunfig.toml
[install]
registry = "https://registry.npmmirror.com"

[test]
coverage = true
coverageThreshold = { line = 0.8 }

6. Worker 线程

// worker.ts
self.onmessage = (event: MessageEvent) => {
  const result = heavyComputation(event.data);
  postMessage(result);
};

function heavyComputation(n: number): number {
  // CPU密集型任务
  let sum = 0;
  for (let i = 0; i < n; i++) sum += i;
  return sum;
}

// main.ts
const worker = new Worker(new URL("./worker.ts", import.meta.url));
worker.postMessage(100000000);
worker.onmessage = (event) => {
  console.log("结果:", event.data);
};

7. Shell 脚本

import { $ } from "bun";

// 像shell脚本一样执行命令
const result = await $`ls -la`.text();
console.log(result);

// 管道
const count = await $`cat data.txt | wc -l`.text();

// 变量插值
const dir = "./src";
await $`find ${dir} -name "*.ts" | head -5`;

// 错误处理
try {
  await $`exit 1`.throws(true);
} catch (e) {
  console.error("命令失败");
}

常见问题

Q1: Node.js 兼容性如何?

大部分 npm 包和 Node.js API 可以直接使用,但少数情况不兼容: - 原生 C++ 插件可能需要重新编译 - 某些 Node.js 特有 API 尚未完全实现 - 建议查看 Bun 兼容性页面

Q2: 和 Node.js 性能对比?

场景BunNode.js
启动速度~4x 快基线
HTTP 吞吐~2.5x 快基线
包安装~25x 快基线
文件I/O~10x 快基线

Q3: 生产环境可以用吗?

Bun 1.0+ 已声明生产就绪,但建议: - 先在非关键服务尝试 - 充分测试你的依赖兼容性 - 关注 Bun 的更新日志

Q4: 如何从 Node.js 迁移?

# 1. 安装Bun
# 2. 删除node_modules和package-lock.json
rm -rf node_modules package-lock.json
# 3. 用Bun安装依赖
bun install
# 4. 运行测试
bun test
# 5. 逐步替换启动命令
# "start": "node dist/index.js" → "start": "bun src/index.ts"

参考资源