Bun

Bun v1.1.4


Jarred Sumner · 2024 年 4 月 16 日

Bun 是一個速度極快的 JavaScript 執行環境、打包器、轉譯器和套件管理器 — 功能All-in-One。

Bun v1.1.4 修復了 40 個錯誤(解決了 84 個 👍 反應)。bun run --filter <workspace> <script> 讓您可以平行運行多個工作區腳本。重新安裝在 bun install 中速度提升高達 50%。bun install 的重要可靠性修復。bun:sqlite 支援用於資源清理的 using,並修復了一些錯誤。影響 Next.js Standalone 和 Web Streams 的記憶體洩漏已修復。Node.js 相容性改進 fschild_process。「連線已關閉」fetch() 的錯誤修復。Bundows 的一些錯誤修復。

先前的版本

  • v1.1.3 Bun v1.1.3 修復了 5 個錯誤。bun install 在 Windows 上速度提升 50%。已修復在極少數情況下可能導致 bun install 掛起的錯誤。已修復 bun install 中的某些錯誤不會產生非零退出代碼的錯誤。已修復可能導致特定依賴項組合安裝失敗的錯誤。已修復 Windows 上在 cmd.exe 上退出 bun 後,CTRL + C 行為異常的錯誤。已修復 Windows 上讀取目錄缺少權限可能導致崩潰的錯誤。
  • v1.1.2 Bun v1.1.2 修復了 4 個錯誤(解決了 44 個 👍 反應)。已修復 Windows 上 vite dev、next dev 和儲存 bun.lockb 中的 EBUSY 錯誤。Bun Shell 支援 seq、yes、basename 和 dirname。已修復 TypeScript 解析的邊緣案例。已修復導致「無法到達的程式碼」錯誤的錯誤。Windows 上的 fs.watch 已重寫,以提高效能和可靠性。
  • v1.1.1 Bun v1.1.1 修復了 20 個錯誤(解決了 60 個 👍 反應)。
  • v1.1.0 Bundows。Windows 支援來了!此外,還有 JSON IPC Node <-> Bun。

安裝 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

bun install 修復

bun --filter 平行運行工作區腳本

假設您有一個包含兩個套件的 monorepo:packages/apipackages/frontend,兩者都有一個 dev 腳本,用於啟動本機開發伺服器。

通常,您必須開啟兩個單獨的終端機標籤,cd 進入每個套件目錄,然後運行 bun dev

使用 --filter,您可以一次在兩個套件中運行 dev 腳本,使用 glob 模式來篩選要運行腳本的專案

bun --filter='*' dev

兩個命令都將平行運行,您將看到一個漂亮的終端機 UI 顯示它們各自的輸出

您可以將多個篩選器傳遞給 --filter

bun --filter 'packages/api' --filter 'packages/frontend' dev

您可以將其視為 npm run --workspace <workspace> <script> 的更強大替代品。

感謝 pnpm 的啟發,以及 @gvilums 實作此功能。

bun install 中重新安裝速度提升高達 50%

node_modules 中的依賴項必須重新安裝時(例如,因為磁碟上的版本不同),bun install 現在速度提升高達 50%。

在 Macbook Pro M3 上具有 450 MB node_modules 的儲存庫中

❯ hyperfine "bun install --ignore-scripts" "bun-1.1.3 install --ignore-scripts" --prepare="rm -rf node_modules/**/package.json" --warmup=2
Benchmark 1: bun install --ignore-scripts
  Time (mean ± σ):     501.6 ms ±  15.6 ms    [User: 18.0 ms, System: 1174.0 ms]
  Range (min … max):   491.1 ms … 543.8 ms    10 runs

Benchmark 2: bun-1.1.3 install --ignore-scripts
  Time (mean ± σ):     771.4 ms ±  13.4 ms    [User: 13.9 ms, System: 616.6 ms]
  Range (min … max):   756.0 ms … 800.4 ms    10 runs

Summary
  bun install --ignore-scripts ran
    1.54 ± 0.05 times faster than bun-1.1.3 install --ignore-scripts

我們將刪除舊套件檔案的動作移至單獨的執行緒,以加快實際時間並減少主要執行緒上的封鎖 I/O。

已修復:提升別名套件

Bun 以前沒有提升別名 npm 套件。這表示我們會不必要地在 node_modules 中多次安裝相同的別名套件。

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

已修復:在 CI 環境中,bun install 有時不穩定

已修復可能導致 bun install 在 CI 環境中偶爾失敗的錯誤。

在子 node_modules 資料夾中,等待依賴項 node_modules 的程式碼,並非總是正確地等待父項完成安裝,然後再安裝子項。這可能導致在 node_modules 中建立父項依賴項資料夾、安裝套件,然後將其刪除。

當在磁碟上沒有可用的快取版本時,同時安裝同一套件的許多不同版本時,此錯誤最常發生。例如,此錯誤可能導致 string-width 在 Node.js 中使用時可能拋出 ERR_REQUIRE_ESM

感謝 @dylan-conway 修復此問題。

Node.js 相容性改進

fs.close() 回呼是選用的

先前,以下程式碼在 Node.js 中可以運作,但在 Bun 中則不行

import fs from "fs";

fs.open("file.txt", "r", (err, fd) => {
  // missing the callback in the 2nd argument!
  fs.close(fd);
});

現在,回呼在 Bun 中也是選用的。

感謝 @gvilums 修復此問題。

fs.writeFile(fd, data) 不應截斷

在 Node.js 中,當使用檔案描述符呼叫 fs.writeFile 時,它不會截斷檔案。當使用路徑呼叫時,它會截斷檔案。

先前在 Bun 中,當使用檔案描述符或路徑呼叫時,fs.writeFile 會截斷檔案。此問題已修復,現在符合 Node.js 的行為,並且僅在使用路徑呼叫時才截斷。

import { writeFile } from "fs/promises";
import { openSync } from "fs";

const fd = openSync("file.txt", "w");
await writeFile(fd, "hello"); // does not truncate
await writeFile("file.txt", "hello"); // truncates

感謝 @gvilums 修復此問題。

FileHandle#appendFile 會附加

在 Node.js 中,FileHandle#appendFile 會附加到檔案。先前在 Bun 中,它會在附加之前截斷檔案。此問題已修復。

import { open } from "fs/promises";

const file = await open("file.txt", "a");
await file.appendFile("hello"); // appends

bun:sqlite 改進

新增:using Database 和 Statement

bun:sqlite 中的 DatabaseStatement 物件現在支援 using 語法。此語法將在範圍結束時自動呼叫 Database#closeStatement#finalize

import { Database } from "bun:sqlite";

{
  // Automatically close the Database at the end of this scope
  using db = new Database("file.db");

  // Automatically finalize the statement at the end of this scope.
  using query = db.query("SELECT * FROM users");
  for (const row of query.all()) {
    console.log(row);
  }
}

using 是 stage3 TC39 提案 Explicit Resource Management 的一部分。

新增:Database#fileControl 方法

低階 sqlite3_file_control 方法現在在 bun:sqlite 中公開為 Database#fileControl

import { Database, constants } from "bun:sqlite";

const db = new Database();
// Ensure WAL mode is NOT persistent
// this prevents wal files from lingering after the database is closed
db.fileControl(constants.SQLITE_FCNTL_PERSIST_WAL, 0);

新增:Database#close(throwOnError: boolean = false) 引數

您現在可以將 throwOnError 引數傳遞給 Database#close,以便在資料庫因任何原因無法關閉時拋出錯誤。

import { Database, constants } from "bun:sqlite";

const db = new Database();
const query = db.query("SELECT * FROM users");
db.close(true); // "Database is locked"
db.close(false); // no error, stop new queries from being created

在內部,當 throwOnError 為 true 時,會呼叫 sqlite3_close 而不是 sqlite3_close_v2

這不是一個重大變更,因為先前 close 不接受任何引數,並且如果未傳遞任何引數,行為仍然相同。引數預設為 false。

已修復:在垃圾回收時關閉資料庫

Database 物件由於不再使用而被垃圾回收時,Database 現在將在 sqlite 中自動關閉。

先前,bun:sqlite 僅在程序結束時自動關閉資料庫。這還不夠好。

已修復:在 JOIN 中繫結到重複的欄位名稱的錯誤

已修復與使用 bun:sqlite 時 JOIN 查詢中重複的欄位名稱相關的長期錯誤。

import { Database } from "bun:sqlite";

const db = new Database();

db.query(
  "CREATE TABLE Users (Id INTEGER PRIMARY KEY, Name VARCHAR(255));",
).run();

db.query(
  "CREATE TABLE Cars (Id INTEGER PRIMARY KEY, Driver INTEGER, FOREIGN KEY (Driver) REFERENCES Users(Id))",
).run();

db.query('INSERT INTO Users (Id, Name) VALUES (1, "Alice");').run();
db.query("INSERT INTO Cars (Id, Driver) VALUES (1, 1);").run();

const car = db.query("SELECT * FROM Cars JOIN Users ON Driver=Users.Id").get();

console.log(car);

db.close();

先前,上述程式碼會錯誤地記錄

{
  Id: 1,
  Driver: 1,
  Name: 1,
}

現在,它正確地記錄

{
  Driver: 1,
  Id: 1,
  Name: "Alice",
}

這符合流行的 better-sqlite3 套件的行為。

感謝 @gvilums 修復此問題,並感謝 @Hanaasagi 進行初步調查。

Bundows 改進

windowsHidewindowsVerbatimArguments

Node.js child_process API 支援 windowsHidewindowsVerbatimArguments 選項。現在 Bun 也支援這些選項,感謝 @nektro

Bun.serve() 多餘的位元組

已修復 Bun.serve() 可能會使用特定輸入傳送額外重複資料位元組的錯誤,感謝 @cirospaciari

此回歸始於 Bun v1.1.1,我們已改進測試涵蓋率,以防止這種情況再次發生。

Bun.which() 忽略大小寫的檔案副檔名

在 Windows 上,檔案名稱通常不區分大小寫。Bun.which() 現在也比對 Windows 上不區分大小寫的檔案副檔名。這表示您可以在 Windows 上開啟 cmd.EXE 以及 cmd.exe(以及所有其他大小寫排列組合)。

--cwd 旗標在 Windows 上運作

--cwd 旗標現在在 Windows 上如預期般運作。

bun --cwd=.\my-app run hey

這會在運行 hey 腳本之前,將目前的工作目錄變更為 .\my-app。這讓您不必在運行腳本之前 cd 進入目錄。

執行環境改進

新增:AbortSignal.any

Bun 現在支援 AbortSignal.any,讓您可以建立一個新的 AbortSignal,當傳遞的任何 AbortSignal 發出訊號時,該訊號會中止。它有點像 Promise.race 用於 AbortSignal

const first = new AbortController().signal;
const second = new AbortController().signal;
fetch("https://example.com", {
  signal: first,
});
fetch("https://example.com", {
  signal: second,
});

const abortSignal = AbortSignal.any([first, second]);

// Cancel this when either `first` or `second` is aborted
await fetch("https://example.com/slow", { signal: abortSignal });

此程式碼直接來自 WebKit/Safari,因此感謝 WebKit 團隊實作此功能。

已修復:Web Streams 中影響 Next.js 的記憶體洩漏

已修復 Web Streams 中的記憶體洩漏。此錯誤可能導致 Next.js Standalone 在回應請求時洩漏記憶體。

感謝 @lithdew 修復此問題。

已修復:fetch() 「連線已關閉」錯誤

某些伺服器依賴 TLS v1.2 重新協商,這讓伺服器可以在連線建立後變更驗證用戶端的方式。這在 TLS v1.3 中已被棄用,但許多伺服器仍在使用它。先前,當遇到使用 TLS 重新協商的伺服器時,Bun 會拋出「連線已關閉」錯誤。我們現在允許用戶端進行 TLS 重新協商,但繼續不允許伺服器進行重新協商。對於伺服器,TLS 重新協商是一種 DoS 攻擊媒介,BoringSSL 不支援它,並且通常不建議使用。

當在 Bun 中使用 fetch() 時,此錯誤有時會表現為收到 Connection closed 錯誤。

感謝 @cirospaciari 修復此問題,並感謝 @lithdew 縮小問題範圍。

已修復:shell 命令中逸出的換行符

已修復 shell 命令中逸出的換行符與 bash 行為不符的錯誤,感謝 @zackradisic。此錯誤影響 Windows 上的 bun run 以及運行時的 Bun.$。感謝 @zackradisic 修復此問題。

感謝 11 位貢獻者!