Bun热重载 BunHotReloading

Bun热重载技能用于在开发过程中实现代码的自动重载,支持监视模式和热模式,加快开发周期,适用于HTTP服务器和前端开发,关键词包括Bun、热重载、HMR、JavaScript开发工具、TypeScript、自动代码更新。

后端开发 0 次安装 0 次浏览 更新于 3/8/2026

name: Bun热重载 description: 在使用Bun实现热重载时使用,包括–hot、–watch、HMR或开发期间的自动代码重载。涵盖监视模式、热模式和HTTP服务器重载。 version: 1.0.0

Bun热重载

Bun提供内置的热重载功能,以加快开发周期。

监视模式 vs 热模式

特性 --watch --hot
行为 重启进程 重载模块
状态 重载时丢失 保留
速度 ~20ms重启 即时重载
使用场景 任何文件类型 Bun.serve HTTP

监视模式 (–watch)

当文件变化时重启整个进程。

# 基本监视模式
bun --watch run src/index.ts

# 监视特定脚本
bun --watch run dev

# 监视测试运行器
bun --watch test

package.json脚本

{
  "scripts": {
    "dev": "bun --watch run src/index.ts",
    "dev:server": "bun --watch run src/server.ts",
    "test:watch": "bun --watch test"
  }
}

监视行为

  • 自动监视导入的文件
  • 触发任何.ts.tsx.js.jsx变化
  • 也监视.json导入
  • 用新状态重启

热模式 (–hot)

无需重启进程,原地重载模块。

bun --hot run src/server.ts

HTTP服务器热重载

// src/server.ts
let counter = 0; // 状态在热重载间保留

export default {
  port: 3000,
  fetch(req: Request) {
    counter++;
    return new Response(`请求 #${counter}`);
  },
};
bun --hot run src/server.ts

当修改server.ts时,模块即时重载,而counter保持其值。

Bun.serve 热重载

// src/server.ts
const server = Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response("你好!");
  },
});

// 热重载处理器
if (import.meta.hot) {
  import.meta.hot.accept(() => {
    console.log("热重载!");
  });
}

console.log(`服务器运行在端口 ${server.port}`);

import.meta.hot API

// 检查热重载是否可用
if (import.meta.hot) {
  // 接受此模块的更新
  import.meta.hot.accept();

  // 带回调接受
  import.meta.hot.accept((newModule) => {
    console.log("模块更新:", newModule);
  });

  // 重载前清理
  import.meta.hot.dispose(() => {
    // 关闭连接、清除间隔等
    clearInterval(myInterval);
  });

  // 拒绝热重载(强制完全重启)
  import.meta.hot.decline();

  // 使此模块无效(触发父模块重载)
  import.meta.hot.invalidate();
}

HTTP服务器模式

Express-like模式

// src/server.ts
import { createApp } from "./app";

const app = createApp();

const server = Bun.serve({
  port: 3000,
  fetch: app.fetch,
});

// 热重载:重新创建应用
if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    // 使用新的fetch处理器重载
    server.reload({
      fetch: newModule.default.fetch,
    });
  });
}

有状态服务器

// src/server.ts
// 存储在globalThis中以在重载后存活
globalThis.connections ??= new Set();

const server = Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response(`连接数:${globalThis.connections.size}`);
  },
  websocket: {
    open(ws) {
      globalThis.connections.add(ws);
    },
    close(ws) {
      globalThis.connections.delete(ws);
    },
  },
});

if (import.meta.hot) {
  import.meta.hot.accept();
}

自定义监视实现

// dev-server.ts
import { watch } from "fs";

const srcDir = "./src";
let server: ReturnType<typeof Bun.serve> | null = null;

async function startServer() {
  // 带缓存清除的动态导入
  const module = await import(`./src/server.ts?t=${Date.now()}`);

  if (server) {
    server.stop();
  }

  server = Bun.serve(module.default);
  console.log(`服务器启动在端口 ${server.port}`);
}

// 初始启动
await startServer();

// 监视变化
watch(srcDir, { recursive: true }, async (event, filename) => {
  if (filename?.endsWith(".ts") || filename?.endsWith(".tsx")) {
    console.log(`
[${event}] ${filename}`);
    await startServer();
  }
});

console.log("监视变化中...");

WebSocket实时重载

服务器

// src/dev-server.ts
const clients = new Set<ServerWebSocket>();

const server = Bun.serve({
  port: 3000,
  fetch(req, server) {
    if (req.headers.get("upgrade") === "websocket") {
      server.upgrade(req);
      return;
    }

    // 在开发中注入重载脚本
    const html = `
      <!DOCTYPE html>
      <html>
        <body>
          <h1>你好!</h1>
          <script>
            const ws = new WebSocket('ws://localhost:3000');
            ws.onmessage = (e) => {
              if (e.data === 'reload') location.reload();
            };
          </script>
        </body>
      </html>
    `;
    return new Response(html, {
      headers: { "Content-Type": "text/html" },
    });
  },
  websocket: {
    open(ws) {
      clients.add(ws);
    },
    close(ws) {
      clients.delete(ws);
    },
  },
});

// 文件变化时通知客户端
watch("./src", { recursive: true }, () => {
  clients.forEach((ws) => ws.send("reload"));
});

Vite集成

用于前端开发与HMR:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  server: {
    port: 5173,
    hmr: true,
  },
});
# 使用Bun运行Vite
bunx --bun vite

测试与监视

# 监视测试
bun --watch test

# 监视特定文件
bun --watch test src/utils.test.ts

# 带bail(首次失败停止)
bun --watch test --bail

环境检测

// 检查是否以--hot运行
const isHot = !!import.meta.hot;

// 检查是否以--watch运行
const isWatch = process.env.BUN_WATCH === "1";

// 开发模式
const isDev = process.env.NODE_ENV !== "production";

if (isDev) {
  console.log("运行在开发模式");
  console.log(`热重载:${isHot}`);
  console.log(`监视模式:${isWatch}`);
}

常见问题

状态未保留

// ❌ 热重载时状态丢失
let cache = new Map();

// ✅ 热重载时状态保留
globalThis.cache ??= new Map();
const cache = globalThis.cache;

清理未运行

// ❌ 重载后间隔继续运行
setInterval(() => console.log("tick"), 1000);

// ✅ 在dispose时清理
const interval = setInterval(() => console.log("tick"), 1000);

if (import.meta.hot) {
  import.meta.hot.dispose(() => {
    clearInterval(interval);
  });
}

模块未重载

// ❌ 导入未监视
const config = require("./config.json");

// ✅ 使用import进行监视
import config from "./config.json";

常见错误

错误 原因 修复
未检测到变化 文件未导入 检查导入链
状态丢失 使用--watch 使用--hot或globalThis
端口使用中 服务器未停止 实现server.stop()
内存泄漏 无清理 使用dispose回调

何时加载参考

加载 references/advanced-hmr.md 当:

  • 自定义HMR协议
  • 模块联邦
  • 复杂状态管理

加载 references/debugging.md 当:

  • HMR不工作
  • 状态问题
  • 性能调试