观察模式
Bun 中的自动重载,支持 --watch 和 --hot 模式
Bun 支持两种自动重载方式:
--watch模式:当导入的文件发生更改时,Bun 会硬重启进程。--hot模式:当导入的文件发生更改时,Bun 会软重载代码(不重启进程)。
--watch 模式
观察模式可与 bun test 和 bun build 配合使用,也可用于运行 TypeScript、JSX 和 JavaScript 文件。
在 --watch 模式下运行文件:
bun --watch index.tsx
在 --watch 模式下运行测试:
bun --watch test
在 --watch 模式下,Bun 会跟踪所有导入的文件并监视它们的变化。当文件发生变化时,Bun 会使用与初始运行相同的 CLI 参数和环境变量重新启动进程。如果 Bun 崩溃,--watch 会尝试重新启动进程。
以下示例展示了 Bun 如何在你编辑文件时实时重载文件,并且 VSCode 已配置为每次按键时保存文件。
bun run --watch watchy.tsx
import { serve } from "bun";
console.log("我在此时重启:", Date.now());
serve({
port: 4003,
fetch(request) {
return new Response("Sup");
},
});

启用 save-on-keypress 后,在 watch 模式下运行 bun test:
bun --watch test

--hot 模式
使用 bun --hot 在使用 Bun 执行代码时启用热重载。与 --watch 模式不同,Bun 不会完全重启整个进程。它会检测代码变化,并使用新代码更新其内部模块缓存。
bun --hot server.ts
以入口文件(本例中为 server.ts)为起点,Bun 会构建一个包含所有导入源文件(不包括 node_modules 中的文件)的注册表,并监视这些文件的变化。当文件发生变化时,Bun 会执行“软重载”。Bun 会重新求值所有文件,但全局状态(尤其是 globalThis 对象)会保留。
// 让 TypeScript 不报错
declare global {
var count: number;
}
globalThis.count ??= 0;
console.log(`重载了 ${globalThis.count} 次`);
globalThis.count++;
// 防止 `bun run` 退出
setInterval(function () {}, 1000000);
如果你用 bun --hot server.ts 运行这个文件,每次保存文件时你都会看到重载计数递增。
bun --hot server.ts
Reloaded 0 times
Reloaded 1 times
Reloaded 2 times
像 nodemon 这样的传统文件监视器会重启整个进程,因此 HTTP 服务器和其他有状态对象都会丢失。相比之下,bun --hot 无需重启进程即可反映更新后的代码。
HTTP 服务器
你可以更新 HTTP 请求处理器,而无需关闭服务器:保存文件时,Bun 会使用更新后的代码重新加载服务器,同时不会重启进程。因此可以实现极快的刷新速度。
globalThis.count ??= 0;
globalThis.count++;
Bun.serve({
fetch(req: Request) {
return new Response(`重载了 ${globalThis.count} 次`);
},
port: 3000,
});
实现细节
热重载时,Bun 会:
- 重置内部的
require缓存和 ES 模块注册表(Loader.registry) - 同步运行垃圾回收(以减少内存泄漏,但会牺牲一定运行时性能)
- 重新从头转译所有代码(包括源映射)
- 使用 JavaScriptCore 重新求值代码
目前的实现并非特别优化,会重新转译未发生变化的文件,也没有尝试增量编译。这只是一个起点。