Bun

Bun v1.2.1


Jarred Sumner · 2025年1月27日

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

此版本修正了 32 個錯誤。S3 儲存類別支援、crypto.generateKeyPair 中的 X25519 支援。fs.stat 使用更少的記憶體。node:fs、node:child_process 和 node:process 相容性改進。CSS 解析器錯誤修正。使用 --zero-fill-buffers 標記的零填充緩衝區。bun test 中縮排的內嵌快照。已改進:字串 GC 報告準確性。修正了 Bun.serve()、Bun.pathToFileURL 和某些字串中的記憶體洩漏。停用 HTML 匯入中的最小化。

安裝 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 儲存類別支援

您現在可以將 storageClass 選項傳遞給 Bun 的內建 S3 用戶端。

這可讓您設定 S3 物件儲存如何儲存您的物件,以便您可以針對成本或延遲進行最佳化。

it("should work with storage class", async () => {
  const s3file = s3("s3://bucket/credentials-test", s3Options);
  const url = s3file.presign({
    expiresIn: 10,
    storageClass: "GLACIER_IR",
  });
  expect(url).toBeDefined();
  expect(url.includes("X-Amz-Expires=10")).toBe(true);
  expect(url.includes("x-amz-storage-class=GLACIER_IR")).toBe(true);
  expect(url.includes("X-Amz-Date")).toBe(true);
  expect(url.includes("X-Amz-Signature")).toBe(true);
  expect(url.includes("X-Amz-Credential")).toBe(true);
  expect(url.includes("X-Amz-Algorithm")).toBe(true);
  expect(url.includes("X-Amz-SignedHeaders")).toBe(true);
});

crypto.generateKeyPair 中的 X25519 支援

crypto.generateKeyPair API 現在支援 X25519 曲線,用於金鑰產生和 Diffie-Hellman 金鑰交換。

import crypto from "node:crypto";
// Generate Alice's keys
const alice = crypto.generateKeyPairSync("x25519", {
  publicKeyEncoding: {
    type: "spki",
    format: "der",
  },
  privateKeyEncoding: {
    type: "pkcs8",
    format: "der",
  },
});

// Generate Bob's keys
const bob = crypto.generateKeyPairSync("x25519", {
  publicKeyEncoding: {
    type: "spki",
    format: "der",
  },
  privateKeyEncoding: {
    type: "pkcs8",
    format: "der",
  },
});

// Convert keys for DH computation
const alicePrivateKey = crypto.createPrivateKey({
  key: alice.privateKey,
  format: "der",
  type: "pkcs8",
});

const bobPublicKey = crypto.createPublicKey({
  key: bob.publicKey,
  format: "der",
  type: "spki",
});

先前,這會擲回 DOMException

NotSupportedError: The operation is not supported.

bun test 中縮排的內嵌快照

測試中 Jest 樣式的內嵌快照現在支援縮排,使測試檔案更易於閱讀。更新快照時,會自動偵測並保留縮排。

test("my test", () => {
  expect(value).toMatchInlineSnapshot(`
    {
      "foo": "bar",
      "baz": 123
    }
  `);
});

感謝 @pfgithub 的修正!

已改進:字串 GC 報告準確性

在 WebKit(和 Bun)中,字串是參考計數的。JavaScript 字串(會進行垃圾回收)會保留對參考計數字串的參考。垃圾收集器會將參考計數字串的記憶體使用量報告為字串的位元組長度除以參考計數

Source/WTF/wtf/text/StringImpl.h
inline size_t StringImpl::costDuringGC()
{
    if (isStatic())
        return 0;

    if (bufferOwnership() == BufferSubstring)
        return divideRoundedUp(substringBuffer()->costDuringGC(), refCount());

    size_t result = m_length;
    if (!is8Bit())
        result <<= 1;
    return divideRoundedUp(result, refCount());
}

先前,Bun 的 JavaScriptCore 繫結通常會有如下模式,用於建立要讓 JavaScript 取用的字串

bun.zig
fn myFunction(globalObject: *JSC.JSGlobalObject, input: []const u8) JSC.JSValue {
  // Reference count: 1
  const string = bun.String.createUTF8(input);

  // - Reference count: 1 (after the function returns)
  defer string.deref();

  // + Reference count: 2 (before the function returns)
  return string.toJS(globalObject);
}

因此,如果您使用 fs.readFileSync(path, "utf-8") 之類的函式來讀取包含 64 KB ASCII 資料的檔案,記憶體使用量會向 JavaScriptCore 的垃圾收集器報告為 32 KB 而不是 64 KB

我們已更新繫結以使用不同的模式,將為 JavaScript 建立字串的步驟合併為單一步驟,以便在傳回 JavaScript 字串之前,參考計數不會額外遞增一次。

bun.zig
fn myFunction(globalObject: *JSC.JSGlobalObject, input: []const u8) JSC.JSValue {
  // Reference count: 1
  return bun.String.createUTF8ForJS(globalObject, input);
}

這會減少記憶體使用量嗎?

可能偶爾會。

停用 HTML 匯入中的最小化

您現在可以透過在 bunfig.toml 中設定 minify 選項,來停用HTML 匯入的最小化。

bunfig.toml
[serve.static]
plugins = ["bun-plugin-tailwind"]
minify = false
# or
# minify.whitespace = false
# minify.identifiers = false
# minify.syntax = false

如果您遇到任何僅在 development: false 時發生的問題,請嘗試停用最小化。

如果未指定

  • 當您將 development: true 傳遞給 Bun.serve() 時,minifyfalse
  • 當您將 development: false 傳遞給 Bun.serve() 時,minifytrue

當您想要擁有最佳化組建,並減少要傳送給用戶端的程式碼時,最小化在生產環境中會有所幫助。

我們將在不久的將來公開 Bun.build 中的其餘選項。

使用 --zero-fill-buffers 標記的零填充緩衝區

Bun 現在支援 Node.js 的 --zero-fill-buffers 標記,這會強制所有新配置的緩衝區都進行零填充,以提高安全性。啟用後,Buffer.allocUnsafe() 之類的方法將始終傳回零填充的緩衝區。

// Run with: bun --zero-fill-buffers script.js
const buf = Buffer.allocUnsafe(20);
console.log(buf); // Will contain all zeros instead of arbitrary memory

感謝 @nektro

node:process 相容性改進

  • 修正了導致 process.stdin.refprocess.stdin.unref 在不應為 undefined 時卻為 undefined 的錯誤。
  • 修正了一個可能導致 process.stdout.write 在極少數情況下無法阻止程序退出的錯誤。

這些修正共同解決了影響 ink 的回歸問題。

node:fs 相容性改進

此版本修正了數個與以下項目相關的相容性問題

  • fs.{s,f}statSync
  • fs.promises.{s,f}stat
  • fs.promises.{s,f}statSync

fs.Stats

fs.Stats 建構函式現在與 Node.js 的行為一致。

以下差異;

const fs = require("fs");
const stats = new fs.Stats();
console.log(stats);

之前 vs 現在

Stats {
 atime: 1970-01-01T00:00:00.000Z,
 atime: Invalid Date,
 atimeMs: 0,
 atimeMs: undefined,
 birthtime: 1970-01-01T00:00:00.000Z,
 birthtime: Invalid Date,
 birthtimeMs: 0,
 birthtimeMs: undefined,
 blksize: 0,
 blksize: undefined,
 blocks: 0,
 blocks: undefined,
 ctime: 1970-01-01T00:00:00.000Z,
 ctime: Invalid Date,
 ctimeMs: 0,
 ctimeMs: undefined,
 dev: 0,
 dev: undefined,
 gid: 0,
 gid: undefined,
 ino: 0,
 ino: undefined,
 isBlockDevice: [Function: isBlockDevice],
 isCharacterDevice: [Function: isCharacterDevice],
 isDirectory: [Function: isDirectory],
 isFIFO: [Function: isFIFO],
 isFile: [Function: isFile],
 isSocket: [Function: isSocket],
 isSymbolicLink: [Function: isSymbolicLink],
 mode: 0,
 mode: undefined,
 mtime: 1970-01-01T00:00:00.000Z,
 mtime: Invalid Date,
 mtimeMs: 0,
 mtimeMs: undefined,
 nlink: 0,
 nlink: undefined,
 rdev: 0,
 rdev: undefined,
 size: 0,
 size: undefined,
 uid: 0,
 uid: undefined,
}

Node.js

Stats {
  dev: undefined,
  mode: undefined,
  nlink: undefined,
  uid: undefined,
  gid: undefined,
  rdev: undefined,
  blksize: undefined,
  ino: undefined,
  size: undefined,
  blocks: undefined,
  atimeMs: undefined,
  mtimeMs: undefined,
  ctimeMs: undefined,
  birthtimeMs: undefined,
  atime: Invalid Date,
  mtime: Invalid Date,
  ctime: Invalid Date,
  birthtime: Invalid Date
}

fs.fstatSync bigint 支援

先前,fs.fstatSync 方法忽略了 bigint 選項。

const fs = require("fs");
const stats = fs.fstatSync(0, { bigint: true });
console.log(stats);

現在它支援了。

BigIntStats {
  dev: 0n,
  ino: 15807n,
  mode: 8592n,
  nlink: 1n,
  uid: 501n,
  gid: 4n,
  rdev: 268435812n,
  size: 0n,
  blksize: 65536n,
  blocks: 0n,
  atimeMs: 1737726280078n,
  mtimeMs: 1737726280452n,
  ctimeMs: 1737726280452n,
  birthtimeMs: 0n,
  atimeNs: 1737726280078692000n,
  mtimeNs: 1737726280452662000n,
  ctimeNs: 1737726280452662000n,
  birthtimeNs: 0n,
  atime: 2025-01-24T13:44:40.078Z,
  mtime: 2025-01-24T13:44:40.452Z,
  ctime: 2025-01-24T13:44:40.452Z,
  birthtime: 1970-01-01T00:00:00.000Z,
}

EINTR

在某些情況下,Bun 未在 fs.writeFilefs.readFile 中處理 EINTR。

這些問題已修正。EINTR 可能會中斷系統呼叫,例如 read()write()truncate()ftruncate()fchmod() 等。正確的行為是在中斷時重試系統呼叫。

Stat 使用更少記憶體

node:child_process 錯誤修正

修正了在 child_process.spawn 中,當把多個通訊端作為額外檔案描述器關閉時,在控制代碼與子程序關聯之前發生的競爭條件,感謝 @anaisbetts

Worker 可靠性改進

我們對 Bun 的 Worker 實作進行了數項可靠性改進。Worker 仍然是實驗性的(如文件中所述),但現在更可靠了。

  • 修正了不會發出「close」等事件的情況。
  • 修正了 terminate 的 Promise 不會解析的情況。

更多錯誤修正

bun run 不再嘗試執行 JSON 檔案

先前,如果您執行 bun . 且存在 index.json 檔案,Bun 會嘗試執行它。現在,Bun 不會這樣做了。

感謝 @pfgithub 的修正!

已修正:fs.Dir.close 回歸

修正了 fs.Dir.close 中的回歸問題,感謝 @DonIsaac

Buffer.prototype.toLocaleString === Buffer.prototype.toString

Buffer.prototype.toLocaleString 現在是 Buffer.prototype.toString 的別名,與 Node.js 行為一致。

const buf = Buffer.from("Hello world");
console.log(buf.toString === buf.toLocaleString); // true

已修正:dgram 通訊端位址/埠重複使用

UDP 通訊端中的 reuseAddrreusePort 選項現在可以在跨平台更可靠地運作。在 Linux 上,reusePort 啟用了多個程序之間的負載平衡。在其他平台上,reuseAddr 允許重複使用已在使用的位址。

import { createSocket } from "node:dgram";

// Enable address reuse
const socket = createSocket({
  reuseAddr: true, // Allow reusing address
  reusePort: true, // Enable load balancing on Linux
});

socket.bind(8000);

感謝 @heimskr

已修正:Bun.inspect 中的 Symbol() 格式設定

現在,當使用 Bun.inspect()console.log() 時,具有空描述的空 Symbols 和 Symbols 會以括號正確格式化。

console.log(Symbol()); // Symbol()
console.log(Symbol("")); // Symbol()

已修正:Bun.pathToFileURL 中的記憶體洩漏

修正了 Bun.pathToFileURL 中的記憶體洩漏。這是由於參考計數遞增太多次所造成的。

已修正:Bun.serve() 中影響某些請求的記憶體洩漏

在某些情況下,對於具有特定 URL 的請求可能會發生記憶體洩漏。此問題已修正。這是由於在一個程式碼路徑中未遞減參考計數所造成的。

已修正:Bun v1.2 中某些字串的記憶體洩漏回歸

Bun 的 JavaScriptCore <> Zig 繫結中的一個問題導致某些字串的參考計數未遞減。此問題已修正。

已修正:AbortSignal GC 過早

修正了 AbortSignal 可能會過早進行垃圾回收的錯誤。當傳遞給 fetchBun.spawn 且未附加 "abort" 事件監聽器時,就會發生這種情況。此錯誤可能會導致不發出 "abort" 事件。

感謝 16 位貢獻者!