此版本修正了 128 個錯誤(解決了 349 個 👍)。Bun 獲得了功能完整的前端開發工具鏈,具有極快速的熱重載和捆綁功能。Bun.serve() 的內建路由使建構網路應用程式更加簡單。Bun.SQL 獲得了 sql.array、sql 片段、sql.file 以及許多錯誤修正。Node.js 相容性改進,適用於 Buffer 和 Node-API (napi)。
安裝 Bun
curl -fsSL https://bun.dev.org.tw/install | bash
npm install -g bun
powershell -c "irm bun.sh/install.ps1|iex"
scoop install bun
brew tap oven-sh/bun
brew install bun
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun
升級 Bun
bun upgrade
使用 bun ./index.html
開發前端應用程式
在 Bun 成為 JavaScript 執行環境(以及測試執行器、套件管理器)之前,Bun 最初是一個前端開發伺服器——而今天,在 Bun v1.2.3 中,我們將其帶回來了。
在 Bun 的下一個版本中
— Jarred Sumner (@jarredsumner) 2025 年 2 月 11 日
Bun.serve() 獲得了對前端應用程式熱重載的內建支援。pic.twitter.com/D7vu7ozqiO
您現在可以將 Bun 作為靜態網站、到達頁面和網路應用程式的前端開發伺服器,方法是直接執行 .html
檔案。
這使用 Bun 的捆綁器、JavaScript/JSX/TypeScript 轉譯器和 CSS 解析器,以提供現代化的前端開發工具鏈,而無需任何配置。
對於單頁應用程式
對於多頁應用程式,將 glob 模式傳遞給命令
React 預設即支援。熱重載開箱即用。Svelte 和 Vue 的外掛程式即將推出,具有與我們現有的 Bun.build() API 相同的外掛程式 API。
Bun.serve() 的內建路由
將應用程式的前端和後端部分一起運行應該很簡單。這不應該意味著需要協調多個命令才能一起運行。您不應該需要代理伺服器。您不應該需要重寫 URL 或標頭。在本地端,您的後端和前端應該在同一個進程中,從同一個伺服器運行。
為了使其運作良好,Bun 需要知道哪些路由指向前端程式碼,哪些路由指向後端程式碼。這就是我們為 Bun.serve()
引入新的 routes
選項的原因。
在 Bun 的下一個版本中
— Jarred Sumner (@jarredsumner) 2025 年 2 月 15 日
Bun.serve() 獲得了一個簡單的內建路由器。它支援參數。pic.twitter.com/CGFmg63JQi
Bun.serve() 現在支援具有動態路徑參數的內建路由。路由可以傳回非同步回應,並可以存取型別安全的路由參數。
這是一個 25 行程式碼的資料庫後端完整堆疊應用程式
import { serve, sql } from "bun";
import App from "./myReactSPA.html";
serve({
port: 3000,
routes: {
"/*": App,
"/api/users": {
GET: async () => Response.json(await sql`SELECT * FROM users LIMIT 10`),
POST: async (req) => {
const { name, email } = await req.json();
const [user] =
await sql`INSERT INTO users (name, email) VALUES (${name}, ${email}) RETURNING *`;
return Response.json(user);
},
},
"/api/users/:id": async (req) => {
const { id } = req.params;
const [user] = await sql`SELECT * FROM users WHERE id = ${id} LIMIT 1`;
if (!user) {
return new Response("User not found", { status: 404 });
}
return Response.json(user);
},
},
});
這使得使用 Bun 建構功能完整的網路應用程式更加簡單。
先前,您必須思考「我該如何讀取 URL 以找出要呼叫哪個路由?」或使用像 path-to-regexp
這樣的函式庫。現在,您可以只需定義您的路由,然後讓 Bun 為您匹配它們。在此過程中,當指定路由時,我們也使 fetch
處理常式成為可選項目。static
選項已重新命名為 routes
。
在 Bun.serve() 文件中了解更多資訊。
bun init
以啟動新的 React 專案
您現在可以使用 Bun 運行前端應用程式,但是您要如何開始一個空的專案呢?
bun init
? Select a project template - Press return to submit.
❯ Blank
React
Library
您可以在 bun init
中選擇 React 範本以取得新的 React 專案。
在 Bun 的下一個版本中
— Jarred Sumner (@jarredsumner) 2025 年 2 月 13 日
bun init 獲得了新的「React」選項 pic.twitter.com/g3qBiH8zou
如果您之前使用過 Create React App,這應該會感到熟悉。與 CRA 不同,Bun 的 React 範本包含輕量級的後端伺服器以及前端工具。
bun create ./MyComponent.tsx
對於現有的專案和 LLM 產生的 React 程式碼,您可以使用 bun create ./MyComponent.tsx
來配置 Bun 的前端開發伺服器,以捆綁和服務您的專案。這會
- 使用 Bun 的捆綁器和 JSX/TypeScript 轉譯器來掃描您的原始碼,以尋找匯入的相依性
- 使用
bun install
安裝任何遺失的相依性 - 偵測常見的前端工具,例如 TailwindCSS 和 shadcn/ui,並自動配置開發伺服器以使用它們
為 bun create ./MyComponent.tsx 新增了 @shadcn/ui 支援 pic.twitter.com/PliXnMeOzE
— Jarred Sumner (@jarredsumner) 2025 年 2 月 7 日
這使得開始使用 Bun 的新前端工具更加容易。
新增:bun install --analyze
bun install --analyze
從原始碼檔案掃描匯入的套件,並將任何遺失的套件新增到 package.json。
bun install --analyze src/**/*.ts
此命令使用 Bun 的捆綁器分析 JavaScript/TypeScript 原始碼檔案,以偵測匯入的套件,並確保將它們新增到 package.json。
Buffer 和 Node.js 相容性
從 NODE_EXTRA_CA_CERTS 載入完整憑證捆綁包
Bun 現在支援從 NODE_EXTRA_CA_CERTS
環境變數載入完整憑證捆綁包,與 Node.js 行為一致。這讓您可以為 TLS 連線指定額外的受信任 CA 憑證。
export NODE_EXTRA_CA_CERTS="/path/to/full/bundle.crt"
Buffer 相容性改進
現在有更多 Node.js Buffer 測試通過,影響了如下方法:
Buffer.copy()
Buffer.from()
Buffer.prototype.writeInt8()
Buffer.prototype.writeUInt8()
Buffer.prototype.writeInt16LE()
Buffer.prototype.writeUInt16BE()
Buffer.prototype.compare()
Buffer.prototype.includes()
Buffer.prototype.indexOf()
Buffer.prototype.lastIndexOf()
Buffer.prototype.write()
process.binding('buffer')
感謝 @nektro 的貢獻!
已修正:node:buffer
中的 Buffer 調整大小行為
修正了 node:buffer
無法正確處理可調整大小或可增長的共用緩衝區的錯誤。這提高了與 Node.js 的 buffer 實作的相容性。
const buffer = new ArrayBuffer(16, { maxByteLength: 32 });
const uint8 = new Uint8Array(buffer);
buffer.resize(32); // Now works correctly
感謝 @nektro 的貢獻!
已修正:create-midway
套件現在可以運作了
呼叫 process.binding("fs")
過去會擲回錯誤,阻止使用 create-midway
套件和其他套件。現在已實作此功能。

感謝 @nektro 的貢獻!
Buffer.prototype.inspect()
現在會印出十六進位
考慮以下範例,
let b = Buffer.allocUnsafe(4);
b.fill("1234");
b.specialnumber = 42;
console.log(b);
在 Bun v1.2.3 中,這現在將以十六進位和先前未顯示的其他欄位印出位元組內容。
❯ bun ./test.js
-Buffer(4) [ 49, 50, 51, 52 ]
+<Buffer 31 32 33 34, specialnumber: 42>
console.log()
(和其他 Console 函數)、Bun.inspect()
和 node:util.inspect()
中支援此行為。
感謝 @nektro 的貢獻!
Node-API 針對 ArrayBuffer 處理的改進
Bun 的 Node-API 實作現在可以在 napi_is_buffer()
和 napi_is_typedarray()
中正確處理 ArrayBuffers 和 TypedArrays。這與 Node.js 的行為一致,並提高了與原生附加元件的相容性。
// napi_is_buffer() now correctly returns true for:
new Uint8Array();
new BigUint64Array();
Buffer.alloc(0);
new DataView(new ArrayBuffer());
// napi_is_typedarray() returns true for:
new Uint8Array();
new BigUint64Array();
node:fs
支援單一檔案可執行檔中的嵌入式檔案
Bun 的單一檔案可執行檔中的嵌入式檔案現在支援 Node.js 檔案系統 API,例如 fs.stat
、fs.readFile
和 fs.existsSync
。先前,嵌入式檔案僅支援 fs.readFile
的同步版本。
// These now work in single-file executables:
import { promises as fs } from "node:fs";
import myEmbeddedFile from "./myEmbeddedFile.txt" with {type: "file"};
await fs.readFile(myEmbeddedFile);
await fs.stat(myEmbeddedFile);
import fs from "node:fs";
fs.readFileSync(myEmbeddedFile);
fs.statSync(myEmbeddedFile);
fs.existsSync(myEmbeddedFile);
先前,您只能將檔案系統中的真實檔案與 node:fs 一起使用。現在您也可以使用嵌入式檔案,這使得與現有程式碼和函式庫互操作變得更加容易。
感謝 @dylan-conway 的貢獻!
Bun.SQL 的新功能
.simple()
- 多語句查詢
Bun.sql 現在支援 PostgreSQL 簡單查詢協定,允許在單一查詢中執行多個語句。
// Multiple statements in one query
await sql`
SELECT 1;
SELECT 2;
`.simple();
這對於運行遷移或其他需要在單次資料庫往返中執行的多語句查詢非常有用。`
請注意,簡單查詢不能使用參數 (${value}
)。如果您需要參數,則必須將查詢拆分為單獨的語句。
prepare: false
- 可配置的預先處理語句
您現在可以透過在連線選項中設定 prepare: false
來停用 Bun.sql 中的預先處理語句。
const sql = new SQL({
// ... other options ...
prepare: false, // Disable prepared statements
});
當在交易模式下使用 PGBouncer、偵錯查詢執行計畫或使用需要頻繁重新產生查詢計畫的動態 SQL 時,這非常有用。
已改進:Bun.sql 中的陣列支援
Bun.sql 現在支援從 PostgreSQL 檢索陣列值,包括整數、文字、日期、時間戳記等的陣列。陣列正確處理 null 值,始終為 null 元素傳回 null
。先前,在許多情況下,Bun 會傳回錯誤。
const result = await sql`SELECT ARRAY[0, 1, 2, 3, 4, 5, NULL]::integer[]`;
console.log(result[0].array); // [0, 1, 2, 3, 4, 5, null]
const strings = await sql`SELECT ARRAY['Hello', 'World', NULL]::text[]`;
console.log(strings[0].array); // ['Hello', 'World', null]
感謝 @cirospaciari 的貢獻!
sql 必須作為標籤範本字串呼叫
先前,如果您將 Bun 的 SQL 用戶端作為函數而不是標籤範本字串呼叫,則不會擲回錯誤。
// ✅ Correct: Use as tagged template literal
const users = await sql`SELECT * FROM users`;
// ❌ Incorrect: Will throw ERR_POSTGRES_NOT_TAGGED_CALL
const users = await sql("SELECT * FROM users");
相反地,它應該作為標籤範本字串呼叫,或顯式 sql.unsafe(query)
呼叫。
這防止了您可能在不知不覺中引入 SQL 注入漏洞的 footgun。
已修正:Bun.sql 中的二進制數值
為了安全起見並與 postgres.js 保持一致,來自 PostgreSQL 的數值現在在使用二進制格式時始終以字串形式傳回。
import { sql } from "bun";
import { expect } from "bun:test";
const result = await sql`SELECT 1.23::numeric`;
expect(result).toEqual([{ "?column?": "1.23" }]);
感謝 @cirospaciari 的貢獻!
已修正:SQL 空閒逾時在查詢處理期間斷線
修正了 PostgreSQL 連線在仍在處理查詢結果時可能會錯誤地逾時並斷線的問題。現在,在主動處理來自資料庫的資料時,會正確停用空閒逾時。
const sql = new SQL({
url: "postgres://127.0.0.1:5432/mydb",
idleTimeout: 30, // Won't disconnect while processing results
});
const results = await sql`SELECT * FROM large_table`;
感謝 @cirospaciari 的貢獻!
已修正:Bun.sql 連線字串中的 URL 編碼憑證
SQL 用戶端現在可以正確處理 PostgreSQL 連線字串中 URL 編碼的使用者名稱、密碼和資料庫名稱。
// This now works correctly
const sql = new Bun.SQL(
"postgres://user%40domain:pass%40word@localhost/db%40name",
);
感謝 @cirospaciari 的貢獻!
已修正:SQL 範本字串片段
Bun.sql 現在可以正確處理巢狀 SQL 範本字串片段和參數的串聯。這允許更彈性的查詢組成。
// Create reusable query fragments
const orderBy = (field) => sql`ORDER BY ${sql(field)} DESC`;
// Use fragments in queries
const results = await sql`
SELECT * FROM posts
WHERE author_id = ${userId}
${shouldSort ? orderBy("created_at") : sql``}
`;
感謝 @cirospaciari 的貢獻!
已修正:ReadyForQuery 狀態
修正了一個可能導致 PostgreSQL 連線在經過一段時間後斷線並出現錯誤的錯誤。這是由於過早假設伺服器已準備好進行新的查詢而導致的。
已修正:SQL 查詢字串中的記憶體洩漏
已修正 SQL 查詢字串中的記憶體洩漏。這改進了執行許多 SQL 查詢時的記憶體使用量,尤其是使用大型查詢字串時。
import { sql } from "bun";
// Memory is now properly released after each query
for (let i = 0; i < 1000; i++) {
await sql`SELECT * FROM large_table WHERE id = ${i}`;
}
感謝 @cirospaciari 的貢獻!
已修正:verify-full
和 verify-ca
SSL 模式
修正了 PostgreSQL 連線的 TLS 憑證驗證錯誤地處理不同 SSL 模式(例如 verify-ca
和 verify-full
)的問題,導致在不應發生時擲回憑證錯誤。
感謝 @cirospaciari 的貢獻!
更快的 WebAssembly 啟動速度和更低的 IPInt 記憶體使用量
分層 WebAssembly 執行
越來越多的函式庫開始採用 WebAssembly (Wasm) 來運行效能關鍵的程式碼,或以系統語言編寫的現有函式庫,而無需為每個作業系統和架構分發二進制檔案的麻煩。JavaScriptCore 為 Bun 的 JS 和 Wasm 執行提供支援,長期以來一直使用即時 (JIT) 編譯從 Wasm 程式碼中提取最大效能,就像它對 JS 所做的那樣。這允許將熱路徑 Wasm 函數編譯為在使用者 CPU 上直接運行的最佳化機器碼。
但是 JIT 編譯具有並非總是值得付出的成本。編譯程式碼需要時間,並且在那段時間內您根本無法運行程式碼。因此,JSC 還包含了一個直譯器,稱為 LLInt(低階直譯器),它可以減少 Wasm 程式碼開始運行之前的延遲,並提高不運行足夠次數而值得 JIT 編譯的函數的效能。
新的 WebAssembly 直譯器
就地直譯器或 IPInt 是 Wasm 的新直譯器,它取代了 LLInt。LLInt 必須首先將整個 Wasm 模組轉換為不同的位元組碼格式才能執行,這需要很長時間並且需要大量記憶體。相反地,IPInt 主要直接執行 Wasm 程式碼,格式與其儲存在檔案系統上或透過網路傳輸的格式相同。IPInt 僅針對某些指令使用額外的元資料,並且此元資料是單獨儲存的,因此不需要修改 Wasm 程式碼。這有兩個好處:
- Wasm 程式碼現在可以更快地開始運行,因為產生元資料的成本低於將整個模組編譯為位元組碼。
- 運行 Wasm 程式碼所需的記憶體更少,因為元資料小於位元組碼。
IPInt 已包含在旗標後一段時間,但在此版本中,我們遵循 WebKit 的領導,預設啟用它。如果您在此版本中的 Wasm 模組中遇到新的錯誤,您可以使用環境變數 BUN_JSC_useWasmIPInt=0
還原為舊的直譯器,但也請向我們報告這些錯誤,以便我們可以幫助 WebKit 團隊追蹤它們。
非常感謝 Daniel Liu 和 WebKit 團隊的這項改進!
其他改進
Bun.file(path).stream() 使用更少的記憶體
我們最佳化了在 Bun 中使用來自 Bun.file(path).stream
的基於網路的 ReadableStream 時的記憶體使用量,特別是對於涉及讀取大量資料或長時間運行的串流的情況。
const reader = Bun.file(path).stream().getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log(value);
}
改進了 CLI 說明中的旗標顯示
當運行 --help
時,接受值的 CLI 旗標現在顯示 =<val>
以指示它們接受值。
--outfile Write to a file
--outfile=<val> Write to a file
這使得哪些旗標期望值與哪些旗標是簡單的切換開關更加明顯。
支援虛擬託管樣式 S3 端點
Bun 的 S3 用戶端現在支援與 S3 相容服務的虛擬託管樣式端點。當使用此樣式時,儲存貯體名稱是主機名稱的一部分,而不是路徑的一部分。
import { S3Client } from "bun";
const s3 = new S3Client({
accessKeyId: "access-key",
secretAccessKey: "secret-key",
bucket: "my-bucket",
virtualHostedStyle: true,
});
// Or specify the endpoint directly
const s3WithEndpoint = new S3Client({
accessKeyId: "access-key",
secretAccessKey: "secret-key",
endpoint: "https://my-bucket.s3.us-east-1.amazonaws.com",
virtualHostedStyle: true,
});
感謝 @cirospaciari 的貢獻!
已修正:expect().toEqual() 搭配 error.cause
Error 物件的深度相等比較邏輯已增強,可處理額外的屬性,例如 .cause
和可列舉屬性,同時正確地遵循嚴格模式比較。
import { expect } from "bun:test";
const err1 = new Error("message");
err1.cause = "cause";
err1.extra = "data";
const err2 = new Error("message");
err2.cause = "cause";
err2.extra = "data";
expect(err1).toEqual(err2); // Now passes
感謝 @DonIsaac 的貢獻!
bun pm pack
:修正以 "./" 開頭的 "files"
已修正從 package.json
中的 "files"
開始,以 "./"
開頭的路徑打包問題,這些路徑將正確地包含在產生的套件中。
{
"name": "my-package",
"version": "1.0.0",
"files": ["./dist", "!./subdir", "./src/index.ts"]
}
感謝 @RiskyMH 的貢獻!
HTML 導入中的環境變數
您現在可以透過在 bunfig.toml
檔案的 [serve.static]
區段中設定 env
,將環境變數傳遞到您的 HTML 檔案。
[serve.static]
# Make all BUN_PUBLIC_* environment variables available to client-side code via process.env.BUN_PUBLIC_MY_VAR
env = "BUN_PUBLIC_*"
已改進:Bun.Glob
我們修正了 Bun.Glob 中的幾個錯誤,特別是關於目錄匹配和 **
模式的處理。非常感謝 @probably-neb 和 @zackradisic 的貢獻!
CSS 改善
此版本包含 CSS 處理的多項改進,包括淺色/深色模式的修正、顏色降級和 box-shadow 最小化。
// Light/dark mode CSS now works correctly
const css = `
@media (prefers-color-scheme: dark) {
body { background: black; }
}
`;
// Box-shadow values are minified
const minified = `box-shadow: 0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -1px rgba(0, 0, 0, 0.06)`;
const minified = `box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f`;
錯誤修正
已修正 @-webkit-keyframes 的 CSS 解析
CSS 解析器現在可以正確處理樣式表中的 @-webkit-keyframes
規則。
@-webkit-keyframes slide {
from {
transform: translateX(0);
}
to {
transform: translateX(100px);
}
}
感謝 @ricky-pan 的貢獻!
已修正:檔案寫入器可能過早關閉檔案描述符
修正了 Bun 的檔案寫入器在呼叫 writer.end()
時,會關閉其不擁有的檔案描述符的問題。這可能會導致應用程式的其他部分仍需要該描述符時發生錯誤。
const fileHandle = await fsPromises.open("file.txt", "w");
const fd = fileHandle.fd;
// Previously this would incorrectly close the fd
await Bun.file(fd).writer().end();
// Now the fd remains open for use
await fsPromises.close(fd);
感謝 @pfgithub 的貢獻!
已修正:fetch 中的 FormData boundary 引號
multipart form data 的 Content-Type
標頭不再在 boundary 參數周圍包含引號,與 Node.js 行為一致,並提高了與某些伺服器的相容性。
const form = new FormData();
form.append("file", "content");
const req = new Request("https://example.com", {
method: "POST",
body: form,
});
// Content-Type: multipart/form-data; boundary="..."
// Content-Type: multipart/form-data; boundary=...
已修正:Windows 上 bunx "exec" 錯誤
在某些情況下,bunx
在 Windows 上執行命令時可能會拋出錯誤,因為它將命令視為 "exec" 而不是實際的命令。此問題已修正,感謝 @riskymh。
已修正 bun.lock 格式
Bun 的 lockfile 現在一致地格式化套件 bin 條目和依賴項,在鍵和值之間使用適當的換行符和空格。
// Before
{
"pkg1-1": "bin-1.js""pkg1-2": "bin-2.js"
}
// After
{
"pkg1-1": "bin-1.js",
"pkg1-2": "bin-2.js"
}
感謝 @dylan-conway 的貢獻!
已修正:靜態檔案的 React JSX 開發運行時
當將 Bun 的靜態檔案伺服與 React 結合使用時,開發與生產運行時的載入現在可以根據 NODE_ENV
正確運作。先前,react-jsx
和 react-jsxdev
的載入之間可能存在不匹配。
// Development (NODE_ENV=development)
import * as jsx from "react/jsx-dev-runtime";
// Production (NODE_ENV=production)
import * as jsx from "react/jsx-runtime";
感謝 @paperclover 的貢獻!
已修正:UDP 多播成員資格崩潰
當未指定介面位址的情況下呼叫 addMembership()
或 dropMembership()
時,node:dgram
模組不再崩潰。
import dgram from "node:dgram";
const socket = dgram.createSocket("udp4");
socket.addMembership("224.0.0.1"); // No longer crashes
已修正:stdin 在 unref/ref 後喚醒
process.stdin 流現在在 unref 和 ref 後可以正確地恢復讀取輸入。先前,在涉及 unref/ref 循環的某些情況下,stdin 可能會變得無響應。
// This now works correctly
process.stdin.ref();
process.stdin.unref();
process.stdin.ref();
process.stdin.on("readable", () => {
const chunk = process.stdin.read();
if (chunk !== null) {
console.log(chunk.toString());
}
});
已修正:bun install 中的 HTTP 錯誤處理
修正了在 bun install
期間列印 HTTP 錯誤時可能發生的崩潰問題。這使得套件下載失敗時的錯誤報告更加可靠。
已修正:舊版 TypeScript 裝飾器中的計算屬性名稱
已修正舊版 TypeScript 裝飾器中計算屬性名稱的錯誤。
// Simple logging decorator
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${propertyKey} with:`, args);
return originalMethod.apply(this, args);
};
}
const kGreet = Symbol("greet");
class Example {
@log
[kGreet](name: string) {
return `Hello ${name}!`;
}
}
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
已修正:Bun.file().stat() 和 Bun.file().delete/unlink() 中的非 ASCII 路徑
已修正導致 Bun.file().stat()
和 Bun.file().delete()
無法正確處理非 ASCII 路徑的錯誤。
const file = Bun.file("😀.txt");
await file.stat();
await file.delete();
感謝 @dylan-conway 的貢獻!