Skip to content

Bun 热重载

Bun 提供了高效的热重载(Hot Reload)和监听模式(Watch Mode),大幅提升开发效率。本章介绍 Bun 的热重载功能。

Watch 模式

基本用法

使用 --watch 标志监听文件变化并自动重新运行:

bash
# 监听模式运行脚本
bun --watch index.ts

# 监听模式运行服务器
bun --watch server.ts

工作原理

┌─────────────────────────────────────────┐
│             Watch Mode                   │
├─────────────────────────────────────────┤
│  1. 启动应用                             │
│  2. 监听文件系统变化                      │
│  3. 检测到变化 → 终止当前进程            │
│  4. 重新启动应用                         │
│  5. 返回步骤 2                           │
└─────────────────────────────────────────┘

监听的文件

Bun 会自动监听:

  • 入口文件
  • 所有导入的模块
  • 相关的配置文件
typescript
// index.ts
import { helper } from "./utils/helper";  // 会监听
import config from "./config.json";        // 会监听
import { library } from "some-package";    // node_modules 不监听

console.log("应用启动");

Hot 模式

热重载(不重启进程)

使用 --hot 标志启用真正的热重载:

bash
bun --hot server.ts

热重载 vs 监听模式

特性--watch--hot
进程重启
状态保留
速度更快
适用场景脚本、CLIHTTP 服务器
连接保持

HTTP 服务器热重载

typescript
// server.ts
const server = Bun.serve({
  port: 3000,
  
  fetch(request) {
    return new Response("Hello, Hot Reload!");
  },
});

console.log(`服务器运行在 http://localhost:${server.port}`);

// 导出 server 以支持热重载
export default server;

运行:

bash
bun --hot server.ts

修改代码后,服务器会热更新,无需重启,现有连接保持。

配置监听

额外监听文件

bash
# 监听额外的文件
bun --watch index.ts --watch-file config.json
bun --watch index.ts --watch-file .env

package.json 脚本

json
{
  "scripts": {
    "dev": "bun --watch src/index.ts",
    "dev:hot": "bun --hot src/server.ts",
    "dev:all": "bun --watch src/index.ts --watch-file .env --watch-file config.json"
  }
}

状态保留

热重载状态

typescript
// 在热重载时保留状态
declare global {
  var __hotState: Map<string, any>;
}

// 初始化全局状态(只在首次运行时)
globalThis.__hotState ??= new Map();

// 使用状态
function getCounter(): number {
  return globalThis.__hotState.get("counter") ?? 0;
}

function incrementCounter(): number {
  const count = getCounter() + 1;
  globalThis.__hotState.set("counter", count);
  return count;
}

// 热重载后计数器值会保留
console.log("当前计数:", incrementCounter());

导出 default

typescript
// 对于 HTTP 服务器,导出 default 来支持热重载
const server = Bun.serve({
  port: 3000,
  fetch(request) {
    return new Response("Hello!");
  },
});

// 必须导出才能热重载
export default server;

实际应用

开发服务器

typescript
// dev-server.ts
const port = parseInt(Bun.env.PORT || "3000");

let requestCount = 0;

const server = Bun.serve({
  port,
  
  fetch(request) {
    requestCount++;
    const url = new URL(request.url);
    
    console.log(`[${requestCount}] ${request.method} ${url.pathname}`);
    
    // API 路由
    if (url.pathname.startsWith("/api/")) {
      return handleApi(request);
    }
    
    // 静态文件
    return serveStatic(url.pathname);
  },
});

async function handleApi(request: Request): Promise<Response> {
  const url = new URL(request.url);
  
  if (url.pathname === "/api/status") {
    return Response.json({
      status: "ok",
      requests: requestCount,
      uptime: process.uptime(),
    });
  }
  
  return Response.json({ error: "Not Found" }, { status: 404 });
}

async function serveStatic(pathname: string): Promise<Response> {
  const filePath = `./public${pathname === "/" ? "/index.html" : pathname}`;
  const file = Bun.file(filePath);
  
  if (await file.exists()) {
    return new Response(file);
  }
  
  return new Response("Not Found", { status: 404 });
}

console.log(`开发服务器运行在 http://localhost:${server.port}`);
console.log("使用 --hot 模式运行以启用热重载");

export default server;

运行:

bash
bun --hot dev-server.ts

开发工具集成

typescript
// dev.ts
import { $ } from "bun";

// 并行运行多个服务
const processes = [
  // 前端开发服务器
  $`bun --hot src/client/dev-server.ts`.quiet(),
  
  // 后端 API 服务器
  $`bun --hot src/server/api.ts`.quiet(),
  
  // 监听样式变化
  $`bun --watch src/styles/build.ts`.quiet(),
];

console.log("开发环境已启动");
console.log("- 前端: http://localhost:3000");
console.log("- API: http://localhost:3001");

// 等待所有进程
await Promise.all(processes);

测试监听模式

监听测试

bash
# 监听模式运行测试
bun test --watch

测试文件变化时会自动重新运行测试。

只运行相关测试

bash
# 只运行变化相关的测试
bun test --watch --only

自定义监听逻辑

使用 fs.watch

typescript
import { watch } from "node:fs";

// 自定义监听目录
watch("./data", { recursive: true }, async (event, filename) => {
  console.log(`文件变化: ${event} - ${filename}`);
  
  if (filename?.endsWith(".json")) {
    console.log("重新加载配置...");
    await reloadConfig();
  }
});

async function reloadConfig() {
  const config = await Bun.file("./data/config.json").json();
  console.log("配置已更新:", config);
}

console.log("监听 ./data 目录的变化...");

// 保持进程运行
await Bun.sleep(Infinity);

防抖处理

typescript
import { watch } from "node:fs";

let timeout: Timer | null = null;

function debounce(fn: () => void, delay: number) {
  return () => {
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(fn, delay);
  };
}

const rebuild = debounce(async () => {
  console.log("重新构建...");
  
  const result = await Bun.build({
    entrypoints: ["./src/index.ts"],
    outdir: "./dist",
  });
  
  if (result.success) {
    console.log("构建完成!");
  } else {
    console.error("构建失败");
  }
}, 100);

watch("./src", { recursive: true }, (event, filename) => {
  if (filename?.match(/\.[jt]sx?$/)) {
    console.log(`检测到变化: ${filename}`);
    rebuild();
  }
});

console.log("监听源文件变化...");

生产环境注意事项

不要在生产环境使用

typescript
// ❌ 不要这样做
// bun --hot production-server.ts

// ✅ 生产环境
// bun production-server.ts

环境区分

json
{
  "scripts": {
    "dev": "bun --hot src/server.ts",
    "start": "NODE_ENV=production bun src/server.ts"
  }
}
typescript
// server.ts
const isDev = Bun.env.NODE_ENV !== "production";

if (isDev) {
  console.log("开发模式 - 热重载已启用");
}

const server = Bun.serve({
  port: 3000,
  fetch(request) {
    return new Response("Hello!");
  },
});

export default isDev ? server : undefined;

常见问题

热重载不生效

typescript
// 确保导出 server
const server = Bun.serve({ ... });

// ❌ 缺少导出
// 结束

// ✅ 正确导出
export default server;

状态丢失

typescript
// 使用 globalThis 保留状态
globalThis.__state ??= {
  counter: 0,
  cache: new Map(),
};

// 现在热重载后状态会保留

监听不到某些文件

bash
# 明确指定要监听的文件
bun --watch index.ts --watch-file .env --watch-file config.toml

小结

本章介绍了:

  • ✅ Watch 模式(--watch)自动重启
  • ✅ Hot 模式(--hot)无重启热更新
  • ✅ 状态保留技巧
  • ✅ 开发服务器配置
  • ✅ 测试监听模式
  • ✅ 自定义监听逻辑

下一步

继续阅读 SQLite 数据库 了解 Bun 的内置数据库支持。

本站内容仅供学习和研究使用。