Bun

Bun v1.1.43


Jarred Sumner · 2025 年 1 月 8 日

我們正在舊金山招聘系統工程師,以打造 JavaScript 的未來!

此版本引入了一流的 S3 支援、HTML 打包、bun install --filter、V8 堆積快照、bun install --lockfile-only、bun add --peer、100% 的 node 路徑模組 Node.js 測試通過率、98% 的 zlib 測試通過率、Bun.file(path).stat()、Bun.file(path).delete(),以及許多可靠性改進和錯誤修復。

安裝 Bun

curl
npm
powershell
scoop
brew
docker
curl
curl -fsSL https://bun.dev.org.tw/install | bash
npm
npm install -g bun
powershell
powershell -c "irm bun.sh/install.ps1|iex"
scoop
scoop install bun
brew
brew tap oven-sh/bun
brew install bun
docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun

升級 Bun

bun upgrade

一流的 S3 支援

此版本在 Bun 中引入了一流的 S3 物件儲存支援。

現代面向使用者的生產伺服器經常選擇將檔案儲存在類似 S3 的物件儲存服務中,而不是本機 POSIX 檔案系統。將儲存容量與運算容量分離,可以防止一整類生產可靠性問題:磁碟空間不足、與檔案系統 i/o 相關的高 p95 回應時間、與持久儲存相關的安全性問題。

S3 是一種事實上的標準,其歷史比 ES6 早十年。POSIX 檔案系統 API 從未為網際網路時代設計(非阻塞常規檔案不是一回事!這太瘋狂了!)。

Bun 的 S3 API 旨在感覺類似於 Web 的 ResponseBlob API(類似於 Bun 的本機檔案系統 API)。

import { s3, write, S3Client } from "bun";

// Bun.s3 reads environment variables for credentials
// file() returns a lazy reference to a file on S3
const metadata = s3.file("123.json");

// Download from S3
const data = await metadata.json();
const text = await metadata.text();
const arrayBuffer = await metadata.arrayBuffer();
const uint8array = await metadata.bytes();

// Upload to S3
await metadata.write(JSON.stringify({ name: "John", age: 30 }));
await metadata.write(Bun.file("./123.json"));

// Presign a URL (synchronous - no network request needed)
const url = metadata.presign({
  acl: "public-read",
  expiresIn: 60 * 60 * 24, // 1 day
});

// Delete the file
await metadata.delete();

我們將此 API 新增到 Bun 中,因為許多伺服器不使用 fs,而是使用 S3。

您可以將 Bun 的 S3 用戶端與任何相容 S3 的物件儲存服務一起使用,例如

  • AWS S3
  • Google Cloud Storage
  • DigitalOcean Spaces
  • Cloudflare R2
  • Backblaze B2
  • MinIO
  • ...以及更多

文件中了解更多關於 Bun 的 S3 API 資訊。

HTML 打包器

Bun 現在原生支援將 HTML 檔案及其相關的 JavaScript、CSS 和資源一起打包。這使得使用 Bun 建構靜態網站和 Web 應用程式更加容易。

bun build --experimental-html --experimental-css ./index.html --outdir=dist


這會打包樣式表、JavaScript 和所有其他資源。多個巢狀層級的 JavaScript importrequire 會打包成一個檔案。CSS 檔案會被解析並串連成一個檔案(無論是使用 @import 還是多個 <link> 標籤)。

在 Bun v1.2 中,我們將移除 --experimental-html--experimental-css 標誌,它們將預設啟用。

bun install --filter <pattern>

bun install 獲得 --filter 支援。這讓您可以選擇性地在您的 monorepo 中安裝工作區套件。

感謝 @dylan-conway 實作此功能!

V8 堆積快照

Bun 現在支援輸出 V8 堆積快照。這讓您可以使用 Chrome DevTools 來檢查您的 Bun 應用程式的堆積。這在以前是不可能的,因為 Bun 沒有使用 V8 作為 JavaScript 引擎。Bun 使用 JavaScriptCore。為了實現此功能,我們在 WebKit/JavaScriptCore 的分支中新增了對此功能的支援。

相關地,我們也在 node:v8 中新增了對 v8.writeHeapSnapshotv8.getHeapSnapshot 的支援。

import { writeHeapSnapshot, getHeapSnapshot } from "node:v8";
const path = writeHeapSnapshot();
console.log(path); // Outputs the path to the generated heap snapshot

const snapshot = await Bun.file(path).json();
console.log(snapshot); // Outputs the parsed heap snapshot data


錯誤顯示更多屬性

先前,Bun 硬編碼了一個小的屬性列表,用於在列印頂層錯誤時顯示。現在我們列印錯誤的所有自有屬性。

已修復

❯ bun such.js
1 | const err = new Error("An example error");
                ^
error: An example error
  wow: "wow",
 such: "property",
 very: "information",

      at <file>.js:1:13

先前,Bun 在顯示錯誤時不會顯示像 wowsuchvery 這樣的屬性。現在它會顯示直接在錯誤物件上定義的所有內容。

❯ bun-1.1.42 such.js
1 | const err = new Error("An example error");
                ^
error: An example error
      at <file>.js:1:13

bun run

-F 代表 --filter

bun run --filter='*pkg' <script> 現在支援 -F 簡寫

bun run -F=<pattern> <script>
bun run --filter=<pattern> <script>
bun -F <pattern> <script>
bun -F=<pattern> <script>

--elide-lines=N 控制篩選器輸出行的長度

bun run --filter 中的 --elide-lines 選項控制在終端機中互動式執行腳本時顯示的輸出行的數量。這有助於避免在長腳本中遺漏錯誤,同時仍然顯示腳本的輸出。

bun run --filter ./packages/dep0 --elide-lines=5 script

感謝 @martinamps 實作此功能!

pnpxpnpm dlx 自動替換

當您使用 bun run 執行 package.json 腳本時,我們會將 yarn runnpm runpnpm run 替換為 bun run(這樣您就不必更新您的 package.json)。現在我們也將 pnpxpnpm dlx 替換為 bunx

感謝 @pfgithub 實作此功能!

bun install

新增:慢速 postinstall 腳本日誌記錄

npm 上有錯誤的 postinstall 腳本可能會導致您的安裝停滯。

為了幫助識別導致停滯的套件,bun install 現在會記錄任何執行時間超過 30 秒的 postinstall 腳本的套件名稱。

如果您使用 --verbose 執行 bun install,它將每 2 秒記錄套件名稱,而不是每 30 秒。

新增:bundle(d)Dependenciesbun install

Bun 現在支援處理 bun install 命令中的 bundle(d)Dependencies。此更新允許使用者指定應捆綁在一起的相依性,從而簡化套件管理。這使得使用者更容易建立一致且可管理的專案,尤其是在處理多個相依性時。

感謝 @dylan-conway 實作此功能!

新增:--lockfile-only 選項用於 bun install

您現在可以使用 bun install 命令的 --lockfile-only 選項來產生鎖定檔,而無需安裝任何相依性。當您想要根據您的 package.json 更新或建立鎖定檔,而不影響您的 node_modules 目錄的狀態時,這非常有用。

感謝 @dylan-conway 實作此功能!

新增:--peer 選項在 bun add

您現在可以使用 bun add 命令的 --peer 選項將套件新增為同級相依性。此功能允許使用者直接從其終端機指定同級相依性,從而增強 Bun 中套件管理的可用性。

bun add --peer @types/bun

感謝 @riskymh 實作此功能!

已修復:bun.lock 檔案權限

Bun 的文字鎖定檔被標記為世界可寫和可執行,這是沒有必要的。

此問題已修復,感謝 @dylan-conway

已修復:install.cache.dir 在 bunfig.toml 中

install.cache.dir 選項現在可以正確地從您的 bunfig.toml 中讀取快取目錄。此變更確保可以透過您的組態自訂快取目錄。

[install]
cache.dir = "./your_custom_cache_directory"

感謝 @chawyehsu 實作此功能!

已修復:bun patch --commit 中的崩潰

bun patch --commit 中的崩潰已修復,感謝 @dylan-conway

已修復:bun.lock 套件名稱中的引號逸出

package.json 檔案中的無效 "name" 欄位被持久化到 bun.lock 檔案中,而沒有逸出引號字元。此問題已修復,感謝 @dylan-conway

Node.js 相容性改進

node:path 測試現在 100% 通過

Bun 的 node:path 模組現在通過 100% 的 Node.js 測試套件。

已修復:在 node:path 中加入長 win32 路徑時可能發生的崩潰

使用 node:path 模組加入非常長的路徑時可能發生的崩潰已修復,感謝 @DonIsaac

node:zlib 測試現在 98.08% 通過

node:zlib 模組中除了 1 個測試外,其餘測試現在都通過了。

感謝 @nektro 的貢獻!

已修復:node:zlib 中的記憶體洩漏

node:zlib 模組中的記憶體洩漏已修復。這尤其影響了 Brotli 壓縮。

已修復:zlib 字典選項處理

zlib 中的 dictionary 選項現在可以如預期般運作。這修復了影響某些使用 Bun 的 Minecraft 伺服器的問題。

const deflate = zlib.createDeflate({ dictionary: Buffer.from("...") });

已修復:Node-API 中的 napi_set_last_error 方法

Node-API 中的 napi_set_last_error 方法現在會在返回之前設定適當的錯誤代碼。先前,我們沒有在從 Node-API 函數返回之前一致地設定錯誤代碼 - 這導致某些原生附加元件在函數呼叫失敗後沒有收到正確的錯誤代碼。

感謝 @190n 實作此功能!

已修復:process.kill 允許零或負 PID

一個不正確的驗證阻止了 process.kill 接受負 PID。負 PID 讓您可以終止整個程序組,而不僅僅是一個單一程序。

const { spawn, exec } = require("child_process");

// Starting a process
const child = spawn("some-command");

// Killing the process using a negative PID
process.kill(-child.pid);

感謝 @nektro 實作此功能!

--expose-gc 標誌新增 globalThis.gc

Bun 現在實作了 Node.js --expose-gc CLI 標誌,以及 Bun.gc() 方法。此 CLI 標誌將 gc 新增到全域範圍,讓您可以手動觸發程式碼中的垃圾回收。

bun --expose-gc <script.js>

Bun.gc() 方法與 globalThis.gc 相同。

已修復:process.memoryUsage().arrayBuffers

先前,process.memoryUsage().arrayBuffers 始終報告 0。現在我們盡力報告正確的數字。

關於這一點有趣的是 JavaScriptCore 和 V8 處理 ArrayBuffer 記憶體方式的差異。在 JavaScriptCore 中,類型化陣列的緩衝區由 TypedArray 類型「擁有」(例如 Uint8Array 而不是 ArrayBuffer)。在以下情況之前,它們不會在 Uint8ArrayArrayBuffer(或其他類型化陣列)之間變成「共享」:

  • 存取了 .buffer 屬性(建立 ArrayBuffer)。
  • 呼叫了 .subarray 方法(建立共享參考)。
  • 類型化陣列大小 > 512 位元組。
  • 類型化陣列是在 JavaScript 外部外部配置的(例如在 Bun 中讀取檔案時)

當 ArrayBuffer 的內容不屬於 JavaScriptCore 時,它們不會包含在 process.memoryUsage().arrayBuffers 統計資訊中,而是計入 process.memoryUsage().external 統計資訊中。

已改進:module.findSourceMap

呼叫 require("module").findSourceMap 不再拋出錯誤。先前,這會拋出錯誤,表示我們尚未實作 module.SourceMap。它仍然沒有實作,但是拋出錯誤在某些情況下導致 Next.js 出現問題 - 因此現在我們改為返回 undefined,這與 Node.js 在未找到來源地圖時的行為相符。

bun build

改進的堆疊溢位偵測

Bun 的 JavaScript 解析器現在主動檢查它是否即將耗盡堆疊空間,並拋出人工堆疊溢位錯誤。

已修復(現在是可復原的錯誤)

❯ bun lots-of-for-loop.js
286 | for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++)
                                                      ^
error: Maximum call stack size exceeded
    at lots-of-for-loop.js:286:49

先前,bun 會因硬體 SIGILL 而崩潰,這是不可復原的。

bun: killed SIGILL (core dumped)

已修復:大量 if 語句導致堆疊溢位

大量巢狀 if 語句導致堆疊溢位的兩個原因

  1. if 語句的語句解析步驟始終是遞迴的,即使 if 語句不是巢狀的。這種遞迴使用了過多的堆疊空間。現在它不再是遞迴的。

  2. Bun 的 JavaScript 解析器中的語句訪問步驟最初是一個約 1,300 行的函數。這使用了數千位元組的堆疊空間,當遞迴遍歷深度巢狀的 if/for 迴圈時,這會成為一個問題。我們將其拆分為更多函數,並更頻繁地避免遞迴。

已修復:#bun pragma

通常,bun 在執行階段轉譯每個檔案。為了避免潛在的多次轉譯同一個檔案,bun 會尋找 // @bun pragma 註解。

存在一個錯誤,Bun 的 JavaScript 詞法分析器有時會將註解中存在的字串 #bun 解釋為旨在停用轉譯的 bun pragma。

此問題已修復,感謝 @DonIsaac

已修復:在 bun build --compile 中針對 musl 進行交叉編譯

當我們在 Bun v1.1.40 中新增 musl 支援時,解析 bun build --compile--target 標誌的程式碼沒有更新。此問題已修復,感謝 @thecrypticace

已修復:sourcemap 註解 CSS 檔案

用於 JavaScript 檔案的 //# sourceMappingURL 註解被列印在 CSS 檔案中。此問題已修復。

已修復:解析格式錯誤的 TypeScript 列舉時崩潰

處理轉譯器中格式錯誤的列舉時發生的崩潰已修復。

// Example of a malformed enum that will generate a parse error
enum Foo { [2]: 'hi' }

感謝 @paperclover 實作此功能!

執行階段改進

覆寫 Bun.serve() 中的 "Content-Length"Transfer-Encoding

Bun.serve 現在支援覆寫 "Content-Length"Transfer-Encoding 標頭。

這對於 HEAD 請求特別有用,在這種情況下,您希望返回 Content-Length 但實際上不發送主體。

const app = Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response("Hello World", {
      headers: { "Content-Length": "7" },
    });
  },
});

感謝 @cirospaciari 實作此功能!

新增:Bun.file(path) 中的 stat 方法

您現在可以在 Bun 中使用 stat,而無需 node:fs

import { file } from "bun";

await file("./path-to-file.txt").stat();

這會傳回關於檔案的有用資訊,例如其大小、類型和上次修改日期。這會傳回與 node:fsstat 函數中相同的類型。

新增:Bun.file(path) 中的 delete 方法

您現在可以在 Bun 中刪除檔案,而無需 node:fs

import { file } from "bun";

await file("./path-to-file.txt").delete();

更精確的堆積快照

將條目新增到 performance.markperformance.measure 的記憶體成本現在在堆積快照中準確報告。

修復了使用 eval 和 node:vm 的堆疊追蹤

通常,Bun 在執行階段轉譯每個檔案。這也表示我們必須對堆疊追蹤和錯誤訊息進行來源地圖。

我們不轉譯 node:vm 或 eval 的程式碼(這會破壞相容性)。但是,在某些情況下,當堆疊追蹤中的某些堆疊框架來自 evalnode:vm,而某些來自 Bun 時,追蹤可能會被錯誤地來源地圖。

此外,//# sourceURL 註解並非始終在堆疊追蹤中得到尊重,這對於 evalnode:vm 特別沒有幫助,在這些情況下,可以傳入 sourceURL(對於 eval 透過註解,對於 node:vm 透過選項)。

此問題已修復。

已修正:console.log 中的堆疊溢位

已修正 console.log 中可能發生的堆疊溢位導致的無法恢復的崩潰問題。

現在,console.log 會主動檢查剩餘堆疊空間,並在即將耗盡時拋出 StackOverflowError 錯誤。

在此過程中,我們也修正了 Bun 在 Windows 上使用大量堆疊空間來處理檔案路徑緩衝區的幾個案例(Windows 檔案路徑最多可達 64 KB)。

已修正:WebSocket 用戶端中的記憶體洩漏

已修正影響 WebSocket 用戶端的記憶體洩漏問題。

HTMLRewriter 的 DocType 中的 removeisRemoved

Bun 的 HTMLRewriter 實作現在包含 remove()isRemoved() 方法。remove() 方法允許使用者在轉換期間從 HTML 文件中刪除 <!DOCTYPE> 宣告,而 isRemoved() 屬性是一個布林值,用於告知 <!DOCTYPE> 是否已被移除。

const html = "<!DOCTYPE html><html><head></head><body>Hello</body></html>";

const rewriter = new HTMLRewriter().onDocument({
  doctype(doctype) {
    doctype.remove();
    console.log(doctype.removed); // Logs: true
  },
});

const result = rewriter.transform(html);
console.log(result); // Logs: "<html><head></head><body>Hello</body></html>"

感謝 @kimberly 實作此功能!

已修正:Bun.inspect 中 Set 的格式化

已修正 Bun.inspect() 函數中 Set 物件的格式化問題。這確保當 Set 傳遞給 Bun.inspect() 時,它現在將正確顯示其格式化的內容。

import { it, expect } from "bun:test";

it("Set is propperly formatted in Bun.inspect()", () => {
  const set = new Set(["foo", "bar"]);
  const formatted = Bun.inspect({ set });
  expect(formatted).toBe(`{
  set: Set(2) {
    "foo",
    "bar",
  },
}`);
});

感謝 @laesse 實作此功能!

已修正:socket 關閉行為

在極少數情況下,socket 的 close 回呼可能會在 end 回呼之後被呼叫。此問題已修正。

已修正:迭代屬性時的理論性崩潰

我們 JavaScriptCore <-> Zig 綁定中的一個錯誤,可能導致原生程式碼在極少數情況下迭代物件的屬性時發生崩潰。此問題已修正。

已修正:錯誤訊息中的 export default <file-path>

已修正一個可能導致 bun 將 "export default '<file-path>'" 顯示為錯誤訊息原始碼的錯誤。

Bun.sql 即將準備就緒

在過去一年中,我的其中一個 side project 是一個快速、內建的 Bun PostgreSQL 用戶端,它即將準備就緒。

import { sql } from "bun";
import { expect } from "bun:test";

const result = await sql`select 1 as x`;
expect(result).toEqual([{ x: 1 }]);

Bun.sql 將在 Bun v1.2 中發布 - 在撰寫本文時的 13 天後。您可以在 Bun 的 canary build 版本中試用它。

以下是此版本中 Bun.sql 的新功能。

已修正:重複的欄位名稱 & 數字欄位名稱

已修正當查詢結果中傳回重複的欄位名稱時發生的崩潰問題。

const result = await sql`select 1 as x, 2 as x, 3 as x`;
expect(result).toEqual([{ x: 3 }]);

const result = await sql`select 1 as "1", 2 as "2", 3 as "3", 0 as "0"`;
expect(result).toEqual([{ "1": 1, "2": 2, "3": 3, "0": 0 }]);

先前,我們也不正確地支援數字欄位名稱。

已修正:JSONB 支援

Bun 的內建 PostgreSQL 用戶端現在支援 jsonb 資料類型。

import { sql } from "bun";
import { expect } from "bun:test";

test("jsonb support", async () => {
  const result = await sql`select '{"foo": "bar"}'::jsonb as x`;
  expect(result).toEqual([{ x: { foo: "bar" } }]);
});

onopenonclose 回呼

onopenonclose 會告知您資料庫連線何時開啟或關閉。

import { SQL } from "bun";

const sql = new SQL({
  url: "postgres://127.0.0.1:5432/mydb",
  onopen: () => console.log("Connection opened"),
  onclose: () => console.log("Connection closed"),
});

const [{ x }] = await sql`select 1 as x`;
console.log({ x });
await sql.close();
console.log("closed");

這會記錄

Connection opened
{ x: 1 }
Connection closed
closed

感謝 @dylan-conway 的這項新增功能!

PostgreSQL 錯誤的錯誤代碼

以下錯誤代碼現在可用於 PostgreSQL 錯誤。

  • "ERR_POSTGRES_AUTHENTICATION_FAILED_PBKDF2"
  • "ERR_POSTGRES_CONNECTION_CLOSED"
  • "ERR_POSTGRES_CONNECTION_TIMEOUT"
  • "ERR_POSTGRES_EXPECTED_REQUEST"
  • "ERR_POSTGRES_EXPECTED_STATEMENT"
  • "ERR_POSTGRES_IDLE_TIMEOUT"
  • "ERR_POSTGRES_INVALID_BACKEND_KEY_DATA"
  • "ERR_POSTGRES_INVALID_BINARY_DATA"
  • "ERR_POSTGRES_INVALID_BYTE_SEQUENCE"
  • "ERR_POSTGRES_INVALID_BYTE_SEQUENCE_FOR_ENCODING"
  • "ERR_POSTGRES_INVALID_CHARACTER"
  • "ERR_POSTGRES_INVALID_MESSAGE"
  • "ERR_POSTGRES_INVALID_MESSAGE_LENGTH"
  • "ERR_POSTGRES_INVALID_QUERY_BINDING"
  • "ERR_POSTGRES_INVALID_SERVER_KEY"
  • "ERR_POSTGRES_INVALID_SERVER_SIGNATURE"
  • "ERR_POSTGRES_LIFETIME_TIMEOUT"
  • "ERR_POSTGRES_MULTIDIMENSIONAL_ARRAY_NOT_SUPPORTED_YET"
  • "ERR_POSTGRES_NULLS_IN_ARRAY_NOT_SUPPORTED_YET"
  • "ERR_POSTGRES_OVERFLOW"
  • "ERR_POSTGRES_SASL_SIGNATURE_INVALID_BASE64"
  • "ERR_POSTGRES_SASL_SIGNATURE_MISMATCH"
  • "ERR_POSTGRES_SERVER_ERROR"
  • "ERR_POSTGRES_SYNTAX_ERROR"
  • "ERR_POSTGRES_TLS_NOT_AVAILABLE"
  • "ERR_POSTGRES_TLS_UPGRADE_FAILED"
  • "ERR_POSTGRES_UNEXPECTED_MESSAGE"
  • "ERR_POSTGRES_UNKNOWN_AUTHENTICATION_METHOD"
  • "ERR_POSTGRES_UNSUPPORTED_AUTHENTICATION_METHOD"
  • "ERR_POSTGRES_UNSUPPORTED_BYTEA_FORMAT"
  • "ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE"

其他變更

  • 用於 bun add 的完成清單現在已壓縮,這節省了大約 100 KB 的空間。
  • 我們重寫了檢查 Unicode 識別符號的程式碼,這減少了大約 250 KB 的空間。

感謝 22 位貢獻者!