Skip to content

Bun 通過 CLI 標志支持兩種自動重新加載:

  • --watch 模式,當導入的文件更改時硬重啟 Bun 的進程。
  • --hot 模式,當導入的文件更改時軟重新加載代碼(不重啟進程)。

--watch 模式

監聽模式可以與 bun test 一起使用,或在運行 TypeScript、JSX 和 JavaScript 文件時使用。

要以 --watch 模式運行文件:

bash
bun --watch index.tsx

要以 --watch 模式運行測試:

bash
bun --watch test

--watch 模式下,Bun 跟蹤所有導入的文件並監視它們的更改。當檢測到更改時,Bun 重啟進程,保留初始運行中使用的相同 CLI 參數和環境變量集。如果 Bun 崩潰,--watch 將嘗試自動重啟進程。

NOTE

⚡️ 重新加載很快。 你可能習慣的文件系統監聽器有幾層庫包裝原生 API,或者更糟,依賴輪詢。

相反,Bun 使用操作系統原生文件系統監聽器 API(如 kqueue 或 inotify)來檢測文件更改。Bun 還做了許多優化,使其能夠擴展到更大的項目(例如為文件描述符設置高 rlimit,靜態分配文件路徑緩沖區,盡可能重用文件描述符等)。

以下示例顯示 Bun 在編輯文件時實時重新加載文件,VSCode 配置為 每次按鍵時保存

sh
bun run --watch watchy.tsx
tsx
import { serve } from "bun";

console.log("I restarted at:", Date.now());

serve({
  port: 4003,
  fetch(request) {
    return new Response("Sup");
  },
});

在這個示例中,Bun

以監聽模式運行 bun test 並啟用 save-on-keypress

bash
bun --watch test

NOTE

**`--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 不會硬重啟整個進程。相反,它檢測代碼更改並使用新代碼更新其內部模塊緩存。

NOTE

這與瀏覽器中的熱重新加載不同!許多框架提供"熱重新加載"體驗,你可以編輯和保存前端代碼(比如 React 組件)並在瀏覽器中看到更改而無需刷新頁面。Bun 的 `--hot` 是這種體驗的服務器端等效。要在瀏覽器中獲得熱重新加載,使用像 [Vite](https://vite.dev) 這樣的框架。
bash
bun --hot server.ts

從入口點(上面示例中的 server.ts)開始,Bun 構建所有導入的源文件(不包括 node_modules 中的文件)的注冊表並監視它們的更改。當檢測到更改時,Bun 執行"軟重新加載"。所有文件都被重新評估,但所有全局狀態(特別是 globalThis 對象)都被保留。

ts
// 讓 TypeScript 開心
declare global {
  var count: number;
}

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

// 防止 `bun run` 退出
setInterval(function () {}, 1000000);

如果你用 bun --hot server.ts 運行這個文件,你會看到每次保存文件時重新加載計數遞增。

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

傳統的文件監聽器如 nodemon 重啟整個進程,所以 HTTP 服務器和其他有狀態對象會丟失。相比之下,bun --hot 能夠在不重啟進程的情況下反映更新的代碼。

HTTP 服務器

例如,這使得可以在不關閉服務器本身的情況下更新 HTTP 請求處理程序。當你保存文件時,你的 HTTP 服務器將使用更新的代碼重新加載,而進程不會被重啟。這導致非常快的刷新速度。

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

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

NOTE

**注意** — 在未來版本的 Bun 中,計劃支持 Vite 的 `import.meta.hot` 以更好地管理熱重新加載的生命周期並與生態系統保持一致。

實現細節">

在熱重新加載時,Bun:

  • 重置內部 require 緩存和 ES 模塊注冊表(Loader.registry
  • 同步運行垃圾回收器(以最小化內存洩漏,以運行時性能為代價)
  • 從頭開始重新轉譯所有代碼(包括 sourcemaps)
  • 用 JavaScriptCore 重新評估代碼

這個實現還沒有特別優化。它重新轉譯未更改的文件。它沒有嘗試增量編譯。這是一個起點。

Bun學習網由www.bunjs.com.cn整理維護