Bun

Bun v0.2.2


Jarred Sumner · October 27, 2022

升級方式

bun upgrade

安裝方式

curl https://bun.dev.org.tw/install | bash

重點整理

  • TCP/TLS Socket API
  • WebCrypto API
  • fs.createReadStream 現在可正常運作
  • Bun.peek
  • 使用 Homebrew 安裝 Bun
  • 多項錯誤修正

TCP 通訊端

Bun 現在支援 TCP 客戶端和伺服器。您可以使用它來實作資料庫客戶端、遊戲伺服器,或任何其他需要使用 TCP 而非 HTTP 的應用程式。

TCP echo 伺服器在 Bun 中的執行速度比 Node 快 24%

image

此 API 的設計目標是快速。與 Node.js EventEmitter 或標準 WebSocket API 等為每個 socket 使用 Promise 或指定回呼不同,此 API 的回呼僅需定義一次,以達到最佳效能和更佳的程式碼可讀性。

啟動 TCP 伺服器

import { listen } from "bun";

listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    open(socket) {},
    data(socket, data) {
      console.log(data instanceof Uint8Array); // true
    },
    drain(socket) {},
    close(socket) {},
    error(socket, error) {},
  },
});

啟動 TCP 客戶端

import { connect } from "bun";

connect({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {
      console.log("Received:", data);
    },
  },
});

同時也支援

  • TCP 通訊端熱重載,無需停機
  • 為通訊端指派自訂資料
  • TLS/SSL 支援

您可以在 README 中閱讀更多關於 TCP 通訊端的資訊。

此 API 非常新,我認為仍有一些錯誤需要修正。如果您遇到任何錯誤,請提交 issue!

錯誤修正

Bun 針對匯入內建模組具有特殊的轉換機制,可將非同步 ESM 匯入轉換為同步 ESM import.meta.require。當在這些內建的 Bun 模組中與其他具名匯入一起匯入 default 時,轉譯器中的錯誤導致了執行階段錯誤

// this code would break
import fs, { writeFileSync } from "fs";

// but this code worked
import * as fs from "fs";

此錯誤是因為 Bun 的轉譯器重寫這些匯入的方式所致。在此情況下,default 等同於命名空間物件(僅適用於這些內建模組,它們實際上可能並非指向 JavaScript 原始碼)

現在,Bun 將以上程式碼轉譯為

var fs = import.meta.require("node:fs");

// note: live bindings are not preserved
var { writeFileSync } = fs;

當匯入在建置時期解析失敗時,Bun 會拋出 ResolveErrorResolveError 包含一個 position 物件,其中公開了檔案原始匯入位置的詳細行號與欄號資訊。

當嘗試存取來自 await importposition 物件時,Bun 會崩潰,而該 await import 匯入了另一個解析失敗的檔案,此為一個錯誤。

檔案 A

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

describe("ResolveError", () => {
  it("position object does not segfault", async () => {
    try {
      await import("./file-b");
    } catch (e) {
      expect(Bun.inspect(e.position).length > 0).toBe(true);
    }
  });
});

file-b.js:

import "./does-not-exist.js";

此錯誤已修正。


搭配 HTTP 伺服器使用 new Response(Bun.file(fileDescriptorAsANumber)) 時的錯誤處理邏輯,預期應使用檔案路徑而非檔案描述符號數字,導致崩潰。感謝 @sno2 修正了此問題

export default {
  // This would crash due to incorrect error handling logic
  fetch(req) {
    return new Response(Bun.file(123));
  },
};

涉及具有後向斷言的十六進位跳脫 RegExp 字面值的邊緣案例,導致 v0.2.1 的 Oniguruma polyfill 拋出錯誤。感謝 @dylan-conway 修正了此問題


更多錯誤修正

Bun.peek

有時您的程式碼是 async,但您知道它實際上並非 async。新的 peek 函式可讓您在不使用 await.then 的情況下讀取 Promise 的結果,但前提是該 Promise 已經完成 (fulfilled) 或已拒絕 (rejected)。

import { peek } from "bun";

const promise = Promise.resolve("immediate");
const result = peek(promise); // no await!

console.log(result); // "immediate"

它適用於效能敏感的程式碼,在這些程式碼中,您希望減少額外的 microtick 數量。這是一個進階 API,除非您知道自己在做什麼,否則(可能)不應使用它。

您可以在 README 中閱讀更多關於 peek 的資訊。

Node.js streams

除了新的 API 之外,我們持續在 Node.js 相容性方面取得進展。Bun 現在支援 fs.createReadStream,並且整體上改進了對 Node.js streams 的支援。

import { createReadStream } from "node:fs";

// Reads the first 100 bytes of a file
const reader = createReadStream("example.txt", {
  encoding: "utf-8",
  start: 0,
  end: 100,
});

reader.on("data", (chunk) => {
  console.log(chunk);
});

WebCrypto API

標準 WebCrypto API 現在已實作,感謝 WebKit 的眾多貢獻者。

WebCrypto 是一個底層 API,因此我們僅建議在您對密碼學有一定程度的了解時才使用它。但是,現在有許多依賴 WebCrypto 的熱門函式庫,您可以在 Bun 中使用它們。

以下是使用依賴 WebCrypto 的套件的範例:jose,由 @panva 開發。

const jwt = await new jose.SignJWT({ "urn:example:claim": true })
  .setProtectedHeader({ alg: "ES256" })
  .setIssuedAt()
  .setIssuer("urn:example:issuer")
  .setAudience("urn:example:audience")
  .setExpirationTime("2h")
  .sign(privateKey);

console.log(jwt);

Homebrew

您現在可以使用我們的官方 Homebrew tap 安裝或升級 Bun。

brew tap oven-sh/bun
brew install bun

您也可以安裝特定版本。

brew install bun@0.2.2

您也可以使用 brewbun 升級。

brew upgrade bun
bun upgrade # still works

所有 PR

  • 改進 issue 範本,由 @Electroid 貢獻,詳見 https://github.com/oven-sh/bun/pull/1353
  • Cache dir loader: Prefer $BUN_INSTALL and $XDG_CACHE_HOME to $HOME. 由 @lgarron 貢獻,詳見 https://github.com/oven-sh/bun/pull/1351
  • Fix Bun.serve error handler error param by @zhiyuang in https://github.com/oven-sh/bun/pull/1359
  • chore: remove outdated var usages by @sno2 in https://github.com/oven-sh/bun/pull/1364
  • 修正 spawn exitcode,由 @zhiyuang 貢獻,詳見 https://github.com/oven-sh/bun/pull/1371
  • fix(fetch): stop new Response(null) from segfaulting by @sno2 in https://github.com/oven-sh/bun/pull/1383
  • Add Web Crypto API by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/1384
  • fix(web): stop segfault on invalid fd error by @sno2 in https://github.com/oven-sh/bun/pull/1386
  • oniguruma regex lookbehind and multibyte hex fix by @dylan-conway in https://github.com/oven-sh/bun/pull/1363
  • TCP & TLS Socket API by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/1374
  • Fix lexer expected token error by @zhiyuang in https://github.com/oven-sh/bun/pull/1387
  • Update Dev Containers extension name by @jpaquim in https://github.com/oven-sh/bun/pull/1393
  • Minor fixes to README.md by @jpaquim in https://github.com/oven-sh/bun/pull/1395

新貢獻者

  • @Electroid 在 https://github.com/oven-sh/bun/pull/1353 中完成了他們的首次貢獻
  • @lgarron 在 https://github.com/oven-sh/bun/pull/1351 中完成了他們的首次貢獻
  • @jpaquim 在 https://github.com/oven-sh/bun/pull/1393 中完成了他們的首次貢獻

完整變更日誌