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 |
|---|---|---|
| 进程重启 | 是 | 否 |
| 状态保留 | 否 | 是 |
| 速度 | 快 | 更快 |
| 适用场景 | 脚本、CLI | HTTP 服务器 |
| 连接保持 | 否 | 是 |
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 .envpackage.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 的内置数据库支持。