Bun

Bun v1.1.11


Jarred Sumner · 2024年6月1日

Bun v1.1.11 隆重登場!此版本修正了 36 個錯誤(解決了 362 個 👍)。bun update 會將依賴項更新儲存到 package.json。修正了 bun install 中的對等依賴項解析錯誤。setTimeout 在 Linux 上的吞吐量提高了 5 倍。Node.js 相容性改進,包括 fszlibtimershttpdgrammodule。macOS 上的事件迴圈改進。Windows 穩定性改進。

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

先前的版本

  • v1.1.10 修正了 20 個錯誤。Windows 上未快取的 bun install 速度提高 2 倍。fetch() 使用的記憶體最多減少 2.8 倍。多項針對 bun install、sourcemaps、Windows 穩定性改進和 Node.js 相容性改進的錯誤修正
  • v1.1.9 修正了 67 個錯誤(解決了 150 個 👍)。修正項目包括:bun install 中的工作區、bun build 中的 sourcemaps、IPv6 和 VPN 連線能力、載入 UNC 路徑、連接點、符號連結和 Windows 上的 pnpm、fetch() 速度更快、新增 dns.prefetch() API、atob() 速度提高 8 倍、toString('base64url') 速度提高 5 倍、expect().toBeReturned() matcher、Node.js 相容性改進、Bun Shell 修正,以及更多錯誤修正。
  • v1.1.0 Bundows。Windows 支援正式推出!

安裝 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 update 寫入 package.json

我們修正了一個長期存在的錯誤,該錯誤導致 bun update 會更新依賴項,但只將變更寫入 bun.lockb,而不會寫入 package.json

為了幫助防止重大變更,bun update 在選擇要更新的依賴項時會保留語意版本範圍。如果您想更新到最新版本,請使用 bun update --latest

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

已修正:bun install 對等依賴項解析

已修正一個可能導致對等依賴項被錯誤提升的錯誤,感謝 @dylan-conway。此錯誤經常在 ajvexpo npm 套件中重現。

以下是此錯誤可能導致的錯誤範例

Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Cannot find module 'ajv/dist/compile/codegen'
Require stack:
- repro/node_modules/ajv-keywords/dist/definitions/typeof.js
- repro/node_modules/ajv-keywords/dist/keywords/typeof.js
- repro/node_modules/ajv-keywords/dist/keywords/index.js
- repro/node_modules/ajv-keywords/dist/index.js
- repro/node_modules/schema-utils/dist/validate.js
- repro/node_modules/schema-utils/dist/index.js
- repro/node_modules/babel-loader/lib/index.js
- repro/node_modules/loader-runner/lib/loadLoader.js
- repro/node_modules/loader-runner/lib/LoaderRunner.js
- repro/node_modules/webpack/lib/NormalModuleFactory.js
- repro/node_modules/webpack/lib/Compiler.js
- repro/node_modules/webpack/lib/webpack.js
- repro/node_modules/webpack/lib/index.js
- repro/node_modules/webpack-cli/lib/webpack-cli.js
- repro/node_modules/webpack-cli/lib/bootstrap.js
- repro/node_modules/webpack-cli/bin/cli.js
- repro/node_modules/webpack/bin/webpack.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1144:15)
    at Module._load (node:internal/modules/cjs/loader:985:27)
    at Module.require (node:internal/modules/cjs/loader:1235:19)
    at require (node:internal/modules/helpers:176:18)
    at Object.<anonymous> (repro/node_modules/ajv-keywords/dist/definitions/typeof.js:3:19)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at Module.require (node:internal/modules/cjs/loader:1235:19)

我們已在 Bun 的儲存庫中新增整合測試,以防止此類型的錯誤再次發生。

bun install 中的一個錯誤導致工作區每次都會重新連結,即使它們不需要重新連結。

現在

bun install
bun install v1.1.11

Checked 9 installs across 10 packages (no changes) [5.00ms]
bun install
bun install v1.1.11

Checked 9 installs across 10 packages (no changes) [5.00ms]

先前

bun-1.1.10 install
bun install v1.1.10

- work2@workspace:packages/work2
- work3@workspace:packages/work3

2 packages installed [4.00ms]
bun-1.1.0 install
bun install v1.1.10

- work2@workspace:packages/work2
- work3@workspace:packages/work3

2 packages installed [4.00ms]

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

新增:setTimeout 吞吐量提高 5 倍

我們已重新實作 setTimeoutsetImmediatesetInterval,以提高效能、修正錯誤並解決 Node.js 相容性問題。

在 Linux x64 上執行 setTimeout 2,000,000 次

每次呼叫 setTimeoutsetIntervalsetImmediate 都有成本。在此版本中,我們將 Linux 上 setTimeout 的成本降低了 5 倍。

差異執行時間執行時間峰值 RSS
-Bun v1.1.11648 毫秒484 MB
5 倍Bun v1.1.103454 毫秒710 MB
1.8 倍Node.js 221182 毫秒487 MB

查看基準測試

已修正:setTimeout this 值現在是 Timeout 物件

在 Bun 中,this 先前是 undefined。在 Node.js 中,setTimeout 回呼中的 thisTimeout 物件。這是一個錯誤,我們已修正。

setTimeout(function () {
  console.log(this); // Timeout
}, 1000);

與之前一樣,您可以繼續將 Timeout 物件或逾時 ID 傳遞給 clearTimeout

const timer = setTimeout(() => {}, 1000);

// Timeout implements Symbol.toPrimitive, which lets you use it as a number:
const myTimerID = timer[Symbol.toPrimitive]();
const myTimerID2 = timer + 0;

clearTimeout(timer);
clearTimeout(myTimerID);
clearTimeout(myTimerID2);

此修正也適用於 setIntervalsetImmediate

已修正:setInterval 重新排程行為與 Node.js 相符

在 Node.js 中,setInterval 計時器會根據計時器回呼被呼叫的時間重新排程。

這表示如果您有一個緩慢的同步回呼,則下一個間隔將根據回呼開始的時間排程,而不是根據回呼結束的時間排程。

let last = performance.now();
setInterval(function () {
  const now = performance.now();
  console.log("It's been", (now - last) | 0, "ms since the last interval");
  for (let i = 0; i < 1e9; i++) {}
  this.refresh();
  last = performance.now();
}, 500);

在 Bun v1.1.11 和 Node.js v22 中,此程式碼會印出類似以下內容

❯ bun set.js # Bun v1.1.11 & Node.js v22
It's been 502 ms since the last interval
It's been 0 ms since the last interval
It's been 231 ms since the last interval
It's been 239 ms since the last interval
It's been 247 ms since the last interval
It's been 244 ms since the last interval
It's been 220 ms since the last interval
It's been 220 ms since the last interval

先前,Bun 會印出

❯ bun set.js # Bun v1.1.10 and earlier
It's been 502 ms since the last interval
It's been 501 ms since the last interval
It's been 499 ms since the last interval
It's been 501 ms since the last interval
It's been 501 ms since the last interval
It's been 501 ms since the last interval
It's been 501 ms since the last interval
It's been 501 ms since the last interval

已修正:setTimeout 不應等待 Promise

先前,Bun 會等待從 setTimeoutsetInterval 傳回的 Promise。

這表示以下程式碼會掛起

setTimeout(async () => {
  return new Promise();
}, 1000);

Bun 不再等待從 setTimeoutsetInterval 傳回的 Promise。

感謝 @zawodskoj 修正此問題!

Node.js 相容性改進

此版本包含多項 Node.js 相容性改進。

已修正:fs.promises.cp 應在 Linux 上建立目錄

在 Linux 上,fs.promises.cp 現在會在目錄不存在時建立目錄。這與 Node.js 行為一致,並且在 Windows 和 macOS 上已如預期般運作。

感謝 @nektro 修正此問題!

已修正:node:zlib brotli 參數

node:zlib 中的一個錯誤阻止了在 zlib.brotliCompresszlib.brotliDecompress 中設定 params 引數。此問題已修正,感謝 @nektro

新增:node:events 中的 addAbortListenergetMaxListeners

已在 node:events 中實作了 addAbortListenergetMaxListeners 方法(適用於 EventEmitter,但尚不適用於 EventTarget)。

已修正:path.toNamespacedPath 與反斜線的邊緣案例

已修正 path.toNamespacedPath 中的一個邊緣案例,感謝 @dylan-conway 和 @huseyinacacak-janea。此錯誤也發生在 Node.js 中。

以下斷言現在通過

assert.strictEqual(path.win32.toNamespacedPath("\\\\?\\foo\\"), "\\\\?\\foo\\");
assert.strictEqual(path.win32.toNamespacedPath("\\\\?\\foo"), "\\\\?\\foo\\");
assert.strictEqual(
  path.win32.toNamespacedPath("\\\\?\\c:\\Windows/System"),
  "\\\\?\\c:\\Windows\\System",
);

已修正:node:http 伺服器最大請求主體大小

Node.js 預設不設定最大請求主體大小。Bun 設定了預設的最大請求主體大小,而一個錯誤導致它也被應用於 node:http 伺服器的最大請求主體大小。此問題已修正,感謝 @JonnyBurger

已修正:未捕獲的例外狀況現在會在 bun test 中失敗

當測試案例之間發生未捕獲的例外狀況時,Bun 會更清楚地表明它發生在測試案例之間。

重大變更:當測試案例之間發生未捕獲的例外狀況或未處理的拒絕時,bun test 的結束代碼現在為 1。這應該一直是這樣,也是您對測試執行器的期望。

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

test("uncaught rejection", async () => {
  setTimeout(() => {
    throw new Error("Uh-oh!");
  }, 100);
  await Bun.sleep(99);
});

現在會輸出以下內容

bun test a.test.ts
bun test v1.1.11

a.test.ts:
✓ uncaught rejection [100.05ms]

# Unhandled error between tests
-------------------------------
1 | import { test, expect } from "bun:test";
2 |
3 | test("uncaught rejection", async () => {
4 |   setTimeout(() => {
5 |     throw new Error("Uh-oh!");
              ^
error: Uh-oh!
      at a.test.ts:5:11
-------------------------------

 1 pass
 0 fail
 1 error
Ran 1 tests across 1 files. [106.00ms]

先前,此輸出不太清楚。它沒有清楚地顯示錯誤發生在測試案例之間,也沒有顯示發生了多少拒絕錯誤。

bun-1.1.10 test a.test.ts
bun test v1.1.10 (5102a944)

a.test.ts:
✓ uncaught rejection [100.32ms]
1 | import { test, expect } from "bun:test";
2 |
3 | test("uncaught rejection", async () => {
4 |   setTimeout(() => {
5 |     throw new Error("Uh-oh!");
              ^
error: Uh-oh!
      at a.test.ts:5:11

 1 pass
 0 fail
Ran 1 tests across 1 files. [111.00ms]

已修正:堆疊追蹤中的自訂函式 name

當您動態設定函式的 name 屬性時,Bun 現在會在堆疊追蹤中使用該名稱。

const fn = function OriginalName() {
  console.trace();
};
Object.defineProperty(fn, "name", { value: "NewName" });
fn();

在 Bun v1.1.11 中,此程式碼會印出

at NewName (abc.js:2:3)
at abc.js:5:1

先前,Bun 會印出

at OriginalName (abc.js:2:3)
at abc.js:5:1

此問題在 Bun v0.6.12 中回歸,現已修正,感謝 @refi64。我們已新增測試以防止此問題再次發生。

已修正:程式碼分割的 Sourcemaps

當在 bun build 中啟用程式碼分割時,一個錯誤可能導致縮小的 Sourcemaps 在某些情況下無效。此問題已修正,感謝 @paperclover

macOS 穩定性改進

macOS、Linux 和 Windows 各自使用不同的系統呼叫來等待 I/O 相關事件。在 macOS 上,我們事件迴圈程式碼中的一個錯誤可能導致 Bun 花費額外時間等待 I/O 事件發生。先前,我們假設 kqueue 事件只會是可讀或可寫

int events = LIBUS_SOCKET_READABLE;
if (kev.flags & EVFILT_WRITE) {
  events = LIBUS_SOCKET_WRITABLE;
}

這是錯誤的。kqueue 事件可以是可讀且可寫的。我們已修正此錯誤。

已修正:UDP socket 中的掛起

在 macOS x64 和 Windows x64 上從 Bun 中的 UDP socket 讀取可能會掛起。這是由我們事件迴圈程式碼中的一個問題引起的。我們已修正此錯誤。

Windows 穩定性改進

已修正:Bun.build CPU 使用率

已修正一個導致 Windows 上 Bun.build 中的轉譯器執行緒無限循環使用 CPU 的錯誤,感謝 @paperclover

已修正:帶有反斜線的外部匯入

在 Windows 上,使用 --external 建置以下程式碼會失敗

bun build --external="*" ./index.js
import { loadFonts } from "../base";
console.log(loadFonts);

感謝 @paperclover 修正此問題!

已修正:Windows 上的各種 DNS 問題

我們已更新 c-ares 非同步 DNS 解析函式庫,它修正了 Windows 上的多個錯誤,使其與 Linux 和 macOS 更加一致。

模糊測試

對 Bun 執行階段 API 的部分進行模糊測試,導致在此版本中進行了多項錯誤修正。

已修正:在未帶 new 呼叫 Bun.CryptoHasher 時崩潰

Bun 的 JavasScriptCore 綁定產生器中的一個錯誤導致在未帶 new 呼叫 Bun.CryptoHasher 時崩潰。此問題已修正。我們已新增測試以確保此問題不會再次發生。

已修正:在 Linux 上讀取 Bun.file() 錯誤時崩潰

已修正一個在 Linux 上非同步讀取 Bun.file() 錯誤時可能發生的崩潰。此問題已被多次回報,並由一個新測試重現。

已修正:在未帶引數呼叫 Bun.$.escape() 時崩潰

已修正在未帶引數呼叫 Bun.$.escape() 時發生的崩潰。此問題已由一個新測試重現。

已修正:在未帶引數呼叫 bun:ffi read 函式時崩潰

bun:ffi 中未帶引數呼叫 read.u32() 時,可能會發生崩潰。此問題已修正。

已修正:在 Node.js Module.prototype._compile 中崩潰

當沒有引數或無效引數傳遞給 Module.prototype._compile 時,在擲回例外狀況時可能會發生崩潰。此問題已修正。

已修正:在 CryptoHasher.byteLength 中崩潰

在使用某些雜湊演算法呼叫 Bun.CryptoHasher.byteLength 時可能會發生崩潰。此問題已修正,感謝 @nektro

感謝 16 位貢獻者!