Bun

Bun v1.0.8


Ashcon Partovi · November 2, 2023

Bun v1.0.8 修復了 138 個錯誤 (處理了 257 個 👍 反應),讓 require() 使用記憶體減少 30%,在 bun test 中新增了模組模擬,修復了更多 bun install 錯誤,並修復了更多執行階段錯誤。

Bun 是一個速度極快的 JavaScript 執行環境、打包器、轉譯器和套件管理器 — 功能 All-in-One。如果您錯過了,以下是 Bun 最近的一些變更

  • v1.0.0 - 第一個穩定版本!
  • v1.0.1 - 為 .json 和 .toml 檔案新增具名匯入,修復了 bun installnode:pathBuffer
  • v1.0.2 - 讓 --watch 更快,並修復了許多錯誤
  • v1.0.3 - 支援 emitDecoratorMetadata 和 Nest.js,修復了私有 registry 等問題
  • v1.0.4 - server.requestIP、執行階段外掛程式中的虛擬模組及其他
  • v1.0.5 - 修復了 fetch() 的記憶體洩漏、在 node:crypto 模組中支援 KeyObjectbun:test 中的 expect().toEqualIgnoringWhitespace 及其他
  • v1.0.6 - 修復了 3 個錯誤 (處理了 85 個 👍 反應),在 package.json 中實作了 overridesresolutions,並修復了影響 Bun Docker 使用的效能衰退問題
  • v1.0.7 - 修復了 59 個錯誤 (處理了 78 個 👍 反應),在 bun install 中實作了選用的同層級相依性,並改善了 Node.js 相容性。

安裝 Bun

curl
npm
brew
docker
curl
curl -fsSL https://bun.dev.org.tw/install | bash
npm
npm install -g 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

require() 最高可減少 30% 記憶體用量

我們在使用 require() 時發現了記憶體洩漏,這是因為 Bun 的某些內建模組從 ESM 重構為 CommonJS 時引入的。我們還為 Bun 的 JavaScript 解析器新增了一個小的效能最佳化,適用於建立許多作用域的大型檔案。

Bun v1.0.7: (before)

❯ bun discordy.js
[92.39ms] require("discord.js")
Memory: 73.5625 MB

Bun v1.0.8: (after)

❯ bun discordy.js
[90.22ms] require("discord.js")
Memory: 55.1875 MB

bun test 中的模組模擬

bun test 現在支援模組模擬。

  • 模組模擬同時支援 ESM 和 CJS。
  • 現有的匯入會就地更新。這表示模組模擬在執行階段運作 (與其他在建置時進行模擬的測試執行器不同)。
  • 您可以覆寫內建模組、本機檔案和套件。
import { mock, test, expect } from "bun:test";
import { fn, iCallFn, variable } from "./mock-module-fixture";

test("mocking a local file", async () => {
  expect(fn()).toEqual(42);
  expect(variable).toEqual(7);

  mock.module("./mock-module-fixture.ts", () => {
    return {
      fn: () => 1,
      variable: 8,
    };
  });
  expect(fn()).toEqual(1);
  expect(variable).toEqual(8);

  mock.module("./mock-module-fixture.ts", () => {
    return {
      fn: () => 2,
      variable: 9,
    };
  });
  expect(fn()).toEqual(2);
  expect(variable).toEqual(9);

  mock.module("./mock-module-fixture.ts", () => {
    return {
      fn: () => 3,
      variable: 10,
    };
  });
  expect(fn()).toEqual(3);
  expect(variable).toEqual(10);

  expect(require("./mock-module-fixture").fn()).toBe(3);
  expect(require("./mock-module-fixture").variable).toBe(10);
  expect(iCallFn()).toBe(3);
});

bun install 同層級相依性重複版本錯誤修復

先前,即使已安裝同層級相依性,bun install 仍會一律解析為最新版本。這可能會導致安裝同一套件的重複版本,進而增加 node_modules 的大小,並可能導致衝突。感謝 @dylan-conway,此問題已獲得修復。


bar@1.0.1
foo@1.0.0
bar@^1.0.1

Bun v1.0.7: (before)


bar@1.0.1
bar@1.0.2

Bun v1.0.8: (after)


bar@1.0.1

bun install 尊重預先發布標籤的順序

導致 bun install 未尊重預先發布標籤順序的錯誤已修復,感謝 @dylan-conway。先前,Bun 只會依詞彙順序排序預先發布標籤,但現在如果存在 semver 優先順序,也會依 semver 優先順序排序。

package.json
{
  "dependencies": {
    "foo": "^1.0.0-beta.0.0.1"
  }
}

錯誤修復

已修復:Bun.spawn 無法在 Google Cloud、Vercel 和舊版 Linux 核心中運作

Bun.spawn 是使用系統呼叫 pidfd_open 實作的,但 gVisor (包含 Google Cloud Platform 和 Vercel) 和舊版 Linux 核心未實作此系統呼叫。我們實作了一個變通方案,Bun 會在此方案中產生執行緒、將並行任務加入佇列,然後在每個 pid 上呼叫 waitpid。此變通方案大致上是以 libuv 的預設行為為基礎。

如果您遇到此錯誤,請升級至 Bun v1.0.7,現在應該就能正常運作。

// This error is fixed:
error: "pidfd_open(2)" system call is not supported by your Linux kernel

已修復:macOS 上的 Bun.spawn 有時無法偵測到程序結束

macOS 上 Bun.spawn 中的長期錯誤已修復。先前,當事件在傳送訊號前不久發生時,macOS 上的 Bun.spawn() 可能無法偵測到程序何時結束。這是因為來自 kqueue 的事件通知中存在競爭條件,程序可能會收到來自作業系統的通知,但尚未結束,然後當我們訂閱來自作業系統的通知以偵測程序何時結束時,作業系統會告訴我們程序已結束。

In text-speak, the bug was this

macOS: "嘿,程序 123456 發生了一些事"

bun: "酷,程序 123456 結束了嗎?"

macOS: "沒有"

bun: "好吧...告訴我程序 123456 何時結束"

macOS: "我無法告訴你,因為它已經結束了"

bun: "???"

現在,我們會處理這種情況,方法是辨識 macOS 何時回報程序已結束 (在此之前,macOS 回報程序尚未結束)。

已修復:process.stdin 未傳送 close 事件

當 Bun 完成從 process.stdin 讀取時,它不會傳送 close 事件。感謝 @liz3,此問題已獲得修復。

已修復:setTimeout(cb, 0) 行為不正確

setTimeout 現在的最小持續時間為 1,這與 Node.js 和瀏覽器的行為一致。先前,setTimeout 設定為 0 會導致奇怪的行為,例如在任務佇列排空後才移至下一個刻度時,會發生無限迴圈。

已修復:setImmediate() 行為不正確

setImmediate 現在有獨立的任務佇列,這讓 setImmediate 的行為與 Node.js 一致。先前,setImmediate 類似於 queueMicrotask,這是錯誤的。

已修復:server.requestIP 有時會傳回錯誤的 IP 位址

造成 server.requestIP 有時會傳回格式錯誤 IP 位址的錯誤已修復,感謝 @Hanaasagi

Bun v1.0.7: (before)

{
  "address": "4294967232.4294967208.68.57",
  "family": "IPv4",
  "port": 40174
}

Bun v1.0.8: (after)

{
  "address": "192.168.68.57",
  "family": "IPv4",
  "port": 40174
}

已修復:util.promisifynode:dns 的邊緣案例

造成 util.promisify 無法與 node:dns 正常運作的錯誤已修復,感謝 @antongolub

Bun v1.0.7: (incorrect)

const { promisify } = require("node:util");
const { lookup } = require("node:dns");

await promisify(lookup)("example.com"); // "45.33.20.235"

Bun v1.0.8: (correct)

const { promisify } = require("node:util");
const { lookup } = require("node:dns");

await promisify(lookup)("example.com"); // { address: "45.33.20.235", family: 4 }

已修復:在未加上 new 的情況下呼叫 ScriptFile 時會當機

感謝 @krk 修復了在未加上 new 的情況下叫用特定類別時發生的當機問題。我們計畫透過改善 API 繫結來減輕此類錯誤。

Bun v1.0.7: (before)

File(); // <crash>
Script(); // <crash>

Bun v1.0.8: (after)

File(); // "Class constructor File cannot be invoked without 'new'"
Script(); // "Class constructor Script cannot be invoked without 'new'"

已修復:case undefined 的 Minifier 列印錯誤

感謝 @krk 修復了 case undefined 縮小時缺少空格,導致 JavaScript 語法無效的錯誤。

switch (true) {
  case undefined: {
  }
}

Bun v1.0.7: (before)

switch(true){caseundefined:{}} // SyntaxError: Unexpected token 'caseundefined'

Bun v1.0.8: (after)

switch(true){case undefined:{}}

已修復:巨集導致當機的邊緣案例

使用巨集時,有些邊緣案例會導致當機,而不是顯示根本錯誤。感謝 @I-A-S,此問題已獲得修復。

已修復:Buffer.readUintBE 的行為不正確

有一個解碼錯誤導致 Buffer.readUintBE 在某些情況下傳回不正確的值。感謝 @Hanaasagi 修復此問題。

已修復:fetch() 未針對不受信任的憑證擲回錯誤

fetch 中 BoringSSL 的錯誤處理程式碼中的錯誤,導致當 fetch() 中的伺服器憑證驗證失敗時,Bun 未擲回錯誤,並非有意地忽略了 BoringSSL 的某些錯誤。

感謝 @ansg191 發現並回報此問題。感謝 @cirospaciari 實作修復程式碼並改善我們的測試涵蓋率。

新增功能:支援列印 MapSet 迭代器

現在 Bun 會在 console.log 中列印 MapSet 迭代器,感謝 @liz3

const set = new Set([1, "123", { a: [], str: "123123132", nr: 3453 }]);
console.log(set.keys());

SetIterator {
  1,
  "123",
  {
    a: [],
    str: "123123132",
    nr: 3453
  },
}

新貢獻者

感謝 26 位貢獻者

感謝下列 26 位人士為 Bun 的此版本做出貢獻

完整變更記錄: https://github.com/oven-sh/bun/compare/bun-v1.0.7...bun-v1.0.8