Bun

Bun v0.6.3


Ashcon Partovi · 2023年5月22日

我們正在招募 C/C++ 和 Zig 工程師,一同打造 JavaScript 的未來! 加入我們的團隊 →

上週,我們在 Bun v0.6.0 中推出了全新的 JavaScript 打包器

今天,我們發布了對 node:vm 的支援、node:tlsnode:http 的改進 — 這修復了對 socket.iomongodb 的支援、對 bun test 的改進 — 引入了 test.todo()、測試逾時和更佳的預先載入,以及 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

介紹 node:vm

Bun 現在支援內建的 node:vm 模組。它可以用於執行程式碼,類似於 eval(),但可以更精確地控制程式碼在哪個 globalThis JavaScript 環境中執行。

image

import { runInContext } from "node:vm";

let context = {
  foo: "bar",
  baz: 123,
};

runInContext(`foo = "fizz"; delete baz;`, context);

console.log(context.foo); // "fizz"
console.log(context.baz); // undefined

您也可以使用 runInNewContext 在獨立的 JavaScript 環境中執行程式碼。

import { runInNewContext } from "node:vm";

runInNewContext(`globalThis.fetch = undefined;`);

console.log(globalThis.fetch); // [Function fetch]

感謝 @silversquirl 實作此功能!

node:tlsnode:http 的修正

我們修正了許多關於 TLS 和 HTTP 的程式碼,例如 TLS 交握,因此您現在可以在 Bun 中使用 socket.iomongodb 驗證。

感謝 @cirospaciari 致力於此!

bun test 的改善

test.todo()

您現在可以使用 test.todo() 來標記您稍後想要實作的測試。

image

expect().toBeCloseTo()

您也可以使用 expect().toBeCloseTo() 來比較兩個浮點數。

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

test("toBeCloseTo()", () => {
  expect(3 + 0.14).toBeCloseTo(3.14);
  expect(3.14).toBeCloseTo(Math.PI, 2);
});

感謝 @blackmann 致力於這兩項功能!

測試逾時

您現在可以使用 test() 的第三個參數為您的測試設定逾時時間。

import { test } from "bun:test";

test("i took too long", async () => {
  await Bun.sleep(100);
}, 50); // the last argument is a timeout in milliseconds

image

使用 --preload 的 Hook 支援

您現在可以搭配 --preload 標記使用 beforeAllbeforeEachafterEachafterAll

這讓您可以在所有檔案之前和之後執行程式碼,而不僅僅是目前的檔案。這對於需要在執行測試之前初始化的函式庫非常有用。

import { test, beforeAll, beforeEach, afterEach, afterAll } from "bun:test";

beforeEach(() => {
  console.log("This runs before each test in every file");
});

美化列印的修正

我們也修正了一個錯誤,該錯誤會導致像這樣的程式碼在測試執行器中將值列印為 undefined

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

test("wat", () => {
  const left = {};
  const right = {};
  for (let i = 0; i < 2; i++) {
    left[i] = i + 1;
    right[i] = i + 2;
  }
  expect(left).toBe(right);
});
之前之後
image
image

bun build 的修正

  • 將 Bun.js 作為打包器使用 中強調的,當啟用多個入口點的 --minify 時發生的崩潰問題已獲修正。這是合併相鄰的頂層變數宣告時發生的競賽條件。

  • 已修正導致資產複製到不正確輸出路徑的錯誤。

  • 已修正涉及範本字串不正確合併的最小化器錯誤。

  • 已修正產生來源地圖時可能發生的競賽條件。

  • 已修正允許產生的變數名稱以數字開頭的錯誤。

  • 已修正儲存到磁碟後,建立 BuildArtifact 物件時可能發生的崩潰問題。

  • 已修正在日誌中的記憶體洩漏問題。

  • 改善了在為瀏覽器建置時使用 Node.js 內建函式庫的錯誤訊息,建議使用者使用 --target 選項來指定 nodebun

fetch() 記憶體洩漏

已修正 fetch() 中發現的兩個記憶體洩漏問題。

  1. 回呼建立了對 Promise<Response> 物件的兩個強參考,這阻止了它被垃圾回收。
  2. 輸入驗證邏輯可能會建立一個強持有的 Promise<Response> 並立即丟棄它,而沒有釋放強參考。這阻止了 Promise<Response> 被垃圾回收。

這令人尷尬,我們已改善記憶體洩漏測試的測試覆蓋率,以確保這種情況不再發生。以下是記憶體洩漏的圖表,由 @dimka3553 提供

console.log() 的改善

引號不匹配

先前,console.log() 會為非 ASCII 屬性名稱列印不匹配的引號。現在已修正此問題。

{
  '🐛 Bug with mismatched quotes": 'fixed'
}

設定深度限制

先前,console.log() 會列印無限量的巢狀物件,排除循環參考。這有時是不希望發生的,並且在列印足夠大的物件時會導致崩潰。此問題已透過深度限制 8 修正。

移除不必要的引號識別符

先前,Bun 會在 console.log 中不必要地引用物件鍵,這有點雜亂。在 Twitter 投票 90% 贊成移除引號後,我們就這麼做了。

WebSocket 的變更

publishToSelf 行為的破壞性變更

Bun 在其伺服器端 WebSocket API 中支援 發布/訂閱。您可以使用 Server.publish()ServerWebSocket.publish() 將訊息發送到每個連線的用戶端。

但是,我們在 ServerWebSocket.publish() API 中犯了一個設計錯誤,因為它也會將訊息發送給自己 — 而典型的行為是排除自己。我們透過引入可選的 publishToSelf 選項來修補此錯誤,但預設行為仍然令人困惑,正如 各種 問題 所強調的那樣。

因此,我們不情願地修正了此行為,進行了破壞性變更,以符合開發人員的直覺。我們很少做出這種類型的決定,但當我們這樣做時,我們會確保有壓倒性的證據和回饋表明,維持現狀比任何潛在的破壞更有害。

const server = Bun.serve({
  websocket: {
    open(ws) {
      ws.subscribe("topic");
      // <= Bun v0.6.2
      ws.publish("topic", "send to all clients, including `ws`");
      // >= Bun v0.6.3
      ws.publish("topic", "send to all clients, excluding `ws`");
    },
  },
  fetch(request, server) {
    if (server.upgrade(request)) {
      return;
    }
    return new Response();
  },
});

WebSocket 訊息中的 Buffer 支援

許多 npm 套件期望 Buffer 物件作為 WebSocket 訊息。Bun 現在允許您直接接收二進制 WebSocket 訊息的 "nodebuffer" 值,而不是要求您在傳遞到函式庫時自行重新建立 Buffer 物件。

const server = Bun.serve({
  websocket: {
    open(ws) {
      ws.binaryType = "nodebuffer";
      ws.send(Buffer.from("hello world"));
    },
    message(ws, message) {
      console.log(Buffer.isBuffer(message)); // true
    },
  },
  fetch(request, server) {
    if (server.upgrade(request)) {
      return;
    }
    return new Response("hello world");
  },
});

const client = new WebSocket("ws://127.0.0.1:3000");
client.binaryType = "nodebuffer";
client.onmessage = ({ data }) => {
  console.log(Buffer.isBuffer(data)); // true
};

更多錯誤修正

  • fs.writeFile({ flag: "a" }) 現在會附加到檔案而不是覆寫它
  • 現在使用正確的資料指標和終結器提示呼叫 N-API 終結器
  • 已修正一個在綁定函式內建立許多 Error 物件時可能發生的崩潰問題,感謝 @Constellation
  • 在此版本中,設定 megamorphic 屬性值變得更快,感謝 @Constellation

變更日誌

2544742修正了 BuildErrorResolveError 的記憶體洩漏,由 @Jarred-Sumner 貢獻
4f7198f修正了 fs.writeFile({ flag: "a" }) 的不正確行為,由 @Jarred-Sumner 貢獻
aacbef3改善了無法解析節點內建函式庫時的錯誤訊息,由 @Jarred-Sumner 貢獻
#2939修正了 utf8 屬性名稱的編碼不正確問題,由 @Jarred-Sumner 貢獻
#2937修正了 String.raw 輸出不正確的錯誤,由 @dylan-conway 貢獻
#2870實作了 expect().toBeCloseTo(),由 @blackmann 貢獻
#2947修正了使用多個入口點進行捆綁時的崩潰問題,由 @Jarred-Sumner 貢獻
#2949修正了「數字分隔符號不允許在數字字面量的末尾」的問題,由 @Jarred-Sumner 貢獻
5bec025修正了捆綁期間 cwd 無法寫入的問題,由 @Jarred-Sumner 貢獻
b76974a修正了 IncomingMessage.socket 無法寫入的錯誤,由 @Jarred-Sumner 貢獻
#2785實作了 node:vm,由 @silversquirl 貢獻
#2962改善了 node-fetch polyfill 以包含更多導出,由 @Jarred-Sumner 貢獻