Bun

监视模式

Bun 通过 CLI 标志支持两种自动重载方式

  • --watch 模式,在导入的文件发生更改时,会硬重启 Bun 的进程。
  • --hot 模式,在导入的文件发生更改时,会软重载代码(不重启进程)。

--watch 模式

--watch 模式可与 bun test 或运行 TypeScript、JSX 和 JavaScript 文件一起使用。

运行文件并启用 --watch 模式

bun --watch index.tsx

--watch 模式下运行您的测试

bun --watch test

--watch 模式下,Bun 会跟踪所有导入的文件并监视它们的更改。检测到更改时,Bun 会重启进程,并保留与初始运行相同的 CLI 参数和环境变量。如果 Bun 崩溃,--watch 会尝试自动重启进程。

⚡️ 重载速度很快。 您可能习惯的文件系统监视器通常有多个库层包装原生 API,或者更糟的是,依赖轮询。

取而代之的是,Bun 使用操作系统原生文件系统监视器 API,如 kqueue 或 inotify 来检测文件更改。Bun 还进行了许多优化,使其能够扩展到更大的项目(例如,为文件描述符设置高 rlimit,静态分配文件路径缓冲区,尽可能重用文件描述符等)。

以下示例展示了 Bun 在文件编辑时进行实时重载,VSCode 配置为每次按键时保存

bash
watchy.tsx
bun run --watch watchy.tsx
watchy.tsx
import { serve } from "bun";
console.log("I restarted at:", Date.now());

serve({
  port: 4003,

  fetch(request) {
    return new Response("Sup");
  },
});

在此示例中,Bun 正在

bun watch gif

在监视模式下运行 bun test 并启用了 save-on-keypress

bun --watch test

bun test gif

--no-clear-screen 标志在您不想清除终端的场景下非常有用,例如使用 concurrently 等工具同时运行多个 bun build --watch 命令时。没有此标志,一个实例的输出可能会清除其他实例的输出,可能导致一个实例的错误被另一个实例的输出隐藏。--no-clear-screen 标志类似于 TypeScript 的 --preserveWatchOutput,可以防止此问题。它可以与 --watch 结合使用,例如:bun build --watch --no-clear-screen

--hot 模式

使用 bun --hot 在使用 Bun 执行代码时启用热重载。这与 --watch 模式不同,因为 Bun 不会硬重启整个进程。相反,它会检测代码更改并用新代码更新其内部模块缓存。

注意 — 这与浏览器中的热重载不同!许多框架提供了“热重载”体验,您可以在其中编辑和保存前端代码(例如,一个 React 组件),并在不刷新页面的情况下在浏览器中看到更改。Bun 的 --hot 是这种体验的服务器端等价物。要获得浏览器中的热重载,请使用 Vite 等框架。

bun --hot server.ts

从入口点(上例中的 server.ts)开始,Bun 会构建一个所有导入的源文件(排除 node_modules 中的文件)的注册表,并监视它们的更改。检测到更改时,Bun 会执行“软重载”。所有文件都会被重新评估,但所有全局状态(特别是 globalThis 对象)都会被保留。

server.ts
// make TypeScript happy
declare global {
  var count: number;
}

globalThis.count ??= 0;
console.log(`Reloaded ${globalThis.count} times`);
globalThis.count++;

// prevent `bun run` from exiting
setInterval(function () {}, 1000000);

如果您使用 bun --hot server.ts 运行此文件,您会看到每次保存文件时重新加载计数器都会递增。

bun --hot index.ts
Reloaded 1 times
Reloaded 2 times
Reloaded 3 times

nodemon 这样的传统文件监视器会重启整个进程,因此 HTTP 服务器和其他有状态对象会丢失。相比之下,bun --hot 可以在不重启进程的情况下反映更新的代码。

HTTP 服务器

例如,这使得在不关闭服务器本身的情况下更新 HTTP 请求处理程序成为可能。当您保存文件时,您的 HTTP 服务器将使用更新的代码重新加载,而不会重启进程。这带来了极其快速的用户界面刷新速度。

server.ts
globalThis.count ??= 0;
globalThis.count++;

Bun.serve({
  fetch(req: Request) {
    return new Response(`Reloaded ${globalThis.count} times`);
  },
  port: 3000,
});

注意 — 在 Bun 的未来版本中,计划支持 Vite 的 import.meta.hot,以实现更好的热重载生命周期管理并与生态系统保持一致。

实现细节