我們正在舊金山招聘系統工程師,以打造 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 -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
一流的 S3 支援
此版本在 Bun 中引入了一流的 S3 物件儲存支援。
現代面向使用者的生產伺服器經常選擇將檔案儲存在類似 S3 的物件儲存服務中,而不是本機 POSIX 檔案系統。將儲存容量與運算容量分離,可以防止一整類生產可靠性問題:磁碟空間不足、與檔案系統 i/o 相關的高 p95 回應時間、與持久儲存相關的安全性問題。
S3 是一種事實上的標準,其歷史比 ES6 早十年。POSIX 檔案系統 API 從未為網際網路時代設計(非阻塞常規檔案不是一回事!這太瘋狂了!)。
Bun 的 S3 API 旨在感覺類似於 Web 的 Response
和 Blob
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
在下一個版本的 Bun 中
— Jarred Sumner (@jarredsumner) 2024 年 12 月 22 日
bun build 支援從 .html 檔案打包資源、JS 和 CSS pic.twitter.com/5VpweY1HMn
這會打包樣式表、JavaScript 和所有其他資源。多個巢狀層級的 JavaScript import
和 require
會打包成一個檔案。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.writeHeapSnapshot
和 v8.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 中
— Jarred Sumner (@jarredsumner) 2025 年 1 月 2 日
Bun.generateHeapSnapshot("v8") 輸出 V8 的 .heapsnapshot 格式,因此您可以使用 Chrome DevTools 和 VSCode 來偵錯記憶體使用情況 pic.twitter.com/veIBqASLoi
錯誤顯示更多屬性
先前,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 在顯示錯誤時不會顯示像 wow
、such
或 very
這樣的屬性。現在它會顯示直接在錯誤物件上定義的所有內容。
❯ 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 實作此功能!
pnpx
和 pnpm dlx
自動替換
當您使用 bun run
執行 package.json 腳本時,我們會將 yarn run
、npm run
和 pnpm run
替換為 bun run
(這樣您就不必更新您的 package.json)。現在我們也將 pnpx
和 pnpm dlx
替換為 bunx
。
感謝 @pfgithub 實作此功能!
bun install
新增:慢速 postinstall 腳本日誌記錄
npm 上有錯誤的 postinstall 腳本可能會導致您的安裝停滯。
為了幫助識別導致停滯的套件,bun install
現在會記錄任何執行時間超過 30 秒的 postinstall 腳本的套件名稱。
如果您使用 --verbose
執行 bun install
,它將每 2 秒記錄套件名稱,而不是每 30 秒。
新增:bundle(d)Dependencies
在 bun 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
)。在以下情況之前,它們不會在 Uint8Array
和 ArrayBuffer
(或其他類型化陣列)之間變成「共享」:
- 存取了
.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 語句導致堆疊溢位的兩個原因
if
語句的語句解析步驟始終是遞迴的,即使if
語句不是巢狀的。這種遞迴使用了過多的堆疊空間。現在它不再是遞迴的。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:fs
的 stat
函數中相同的類型。
新增:Bun.file(path) 中的 delete
方法
您現在可以在 Bun 中刪除檔案,而無需 node:fs
。
import { file } from "bun";
await file("./path-to-file.txt").delete();
更精確的堆積快照
將條目新增到 performance.mark
和 performance.measure
的記憶體成本現在在堆積快照中準確報告。
修復了使用 eval 和 node:vm 的堆疊追蹤
通常,Bun 在執行階段轉譯每個檔案。這也表示我們必須對堆疊追蹤和錯誤訊息進行來源地圖。
我們不轉譯 node:vm 或 eval
的程式碼(這會破壞相容性)。但是,在某些情況下,當堆疊追蹤中的某些堆疊框架來自 eval
或 node:vm
,而某些來自 Bun 時,追蹤可能會被錯誤地來源地圖。
此外,//# sourceURL
註解並非始終在堆疊追蹤中得到尊重,這對於 eval
和 node:vm
特別沒有幫助,在這些情況下,可以傳入 sourceURL(對於 eval
透過註解,對於 node:vm
透過選項)。
此問題已修復。
在下一個版本的 Bun 中
— Jarred Sumner (@jarredsumner) 2025 年 1 月 7 日
修復了多個在使用 eval、node:vm 或 //# sourceURL= URL 時涉及堆疊追蹤和行號的錯誤 pic.twitter.com/ENkRaGgeFH
已修正:console.log 中的堆疊溢位
已修正 console.log
中可能發生的堆疊溢位導致的無法恢復的崩潰問題。
現在,console.log
會主動檢查剩餘堆疊空間,並在即將耗盡時拋出 StackOverflowError
錯誤。
在此過程中,我們也修正了 Bun 在 Windows 上使用大量堆疊空間來處理檔案路徑緩衝區的幾個案例(Windows 檔案路徑最多可達 64 KB)。
已修正:WebSocket
用戶端中的記憶體洩漏
已修正影響 WebSocket 用戶端的記憶體洩漏問題。
在下一個 Bun 版本中
— Jarred Sumner (@jarredsumner) 2024 年 12 月 31 日
已修正影響 WebSocket 用戶端的記憶體洩漏問題。
左:新的
右:先前 pic.twitter.com/XfxpmksZji
HTMLRewriter 的 DocType
中的 remove
和 isRemoved
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" } }]);
});
onopen
和 onclose
回呼
onopen
和 onclose
會告知您資料庫連線何時開啟或關閉。
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 的空間。