Bun

Bun v0.5


Ashcon Partovi · 2023 年 1 月 18 日

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

Bun v0.5 滿載新功能,包含 npm workspacesBun.dns,以及支援 node:readline。也改善了與 node:tlsnode:net 的相容性,因此數個資料庫驅動程式首次能在 Bun 中運作,包含 Postgres.js、mysql2node-redis 以及其他。Bun 也持續變得更快更穩定 — Buffer 實例化速度提升 10 倍、crypto.createHasher() 速度提升 50 倍,而 bun install 修正了數十個錯誤。

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

# Upgrade to latest release of Bun
bun upgrade

package.json 中的 Workspaces

Bun 現在支援 package.json 中的 workspaces,而且速度很快。Bun 在 Linux 上安裝 Remix monorepo 約需 500 毫秒。

  • npm install 快 28 倍
  • yarn install (v1) 快 12 倍
  • pnpm install 快 8 倍

什麼是 workspaces?

Workspaces 讓開發複雜軟體變得容易,以包含數個獨立套件的 monorepo 形式。若要嘗試使用,請在您的 package.jsonworkspaces 欄位中指定子套件列表;慣例上會將這些子套件放置在名為 packages 的目錄中。

{
  "name": "my-project",
  "version": "1.0.0",
  "workspaces": ["packages/a", "packages/b"]
}

Bun 尚未支援 workspace 名稱的 glob 模式,但即將推出!

這有幾個主要優點。

  • 程式碼可以拆分為邏輯部分。 如果一個套件依賴另一個套件,您可以簡單地使用 bun add 將其新增為依賴項。如果套件 b 依賴 abun install 會將您的本地 packages/a 目錄符號連結到 bnode_modules 資料夾中,而不是嘗試從 npm 登錄檔下載它。
  • 依賴項可以重複資料刪除。 如果 ab 共用一個常見的依賴項,它將被提升 (hoisted) 到根 node_modules 目錄。這減少了多餘的磁碟使用量,並盡可能減少了與同時安裝多個套件版本相關的「依賴地獄」問題。

Bun.dnsnode:dns

Bun 現在可以使用內建的 Bun.dns API 解析網域名稱。目前,Bun.dns 公開一個單一函式:lookup

import { dns } from "bun";

const records = await dns.lookup("example.com", { family: 4 });
console.log(records); // [{ address: "93.184.216.34" }]

我們也新增了 Node.js node:dns最簡實作,底層使用 Bun.dns。它由 c-ares 和 MacOS 上的非阻塞 getaddrinfo 提供支援。

import { resolve4 } from "node:dns/promises";

const records = await resolve4("example.com");
console.log(records); // [ "93.184.216.34" ]

使用 node:tlsnode:net 的 Sockets

Bun 現在支援使用 net.connect()tls.connect() 建立 sockets。這解鎖了數個資料庫驅動程式庫。一些具代表性的範例:

使用 Postgres.js by @porsager 連接到 Bun 中的 Postgres

import postgres from "postgres";

const sql = postgres();
const [{ version }] = await sql`SELECT version()`;

console.log(version); // "PostgreSQL 14.2 ..."

使用 mysql2 client by @sidorares 連接到 Bun 中的 MySQL

import { createConnection } from "mysql2/promise";

const connection = await createConnection({
  host: "localhost",
  user: "root",
  database: "test",
});

const [rows] = await connection.execute("SELECT 1+2 AS count");
console.log(rows); // [{ count: 3 }]

使用官方 Node.js client 從 Bun 連接到 Redis

import { createClient } from "redis";

const client = createClient();
await client.connect();

await client.set("key", "Hello!");
const value = await client.get("key");

console.log(value); // "Hello!"

支援 node:readline

由於 Bun 現在支援 node:readline 模組,建置 CLI 工具應該會變得更加容易。

import * as readline from "node:readline/promises";

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: true,
});

const answer = await rl.question("How fast is Bun from 1 to 10?\n");
if (parseInt(answer) > 10) {
  console.log("Good answer!");
}

執行此腳本會產生

bun readline.ts
How fast is Bun from 1 to 10?
11
Good answer!

WebSocket 中的自訂 headers

WebSocket 規範 上一個長期存在的功能請求是,在開啟 WebSocket 時設定自訂 headers 的能力。雖然這尚未在 WebSocket 標準中實現,但 Bun 現在實作了它。這允許使用者自訂用於 WebSocket client 握手請求 的 headers。

const ws = new WebSocket("ws://127.0.0.1/chat", {
  headers: {
    Authorization: "...",
  },
});

bun wiptest 的改進

雖然 bun wiptest 仍是進行中的工作,但我們持續增加 Bun 與 Jest 的相容性。

test.skip()

您可以使用 test.skip() 來跳過不需要的測試。

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

describe("fetch()", () => {
  test.skip("can connect to localhost", async () => {
    const response = await fetch("https://127.0.0.1");
    expect(response.ok).toBe(true);
  });

  test("can connect to example.com", async () => {
    const response = await fetch("http://example.com");
    expect(response.ok).toBe(true);
  });
});

當您跳過測試時,它將在測試輸出中顯示為灰色。

bun wiptest output

expect(fn).toThrow()

您可以使用 expect(fn).toThrow() 來捕獲預期的錯誤。

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

test("catch error", async () => {
  expect(() => {
    throw new Error();
  }).toThrow();
});

describe 標籤包含在輸出中

先前,巢狀 describe 標籤未包含在測試執行器輸出中。感謝 @ethanburrell,此問題已修正。

之前

✓ outer > my test

之後

✓ outer > inner > my test

測試檔案

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

describe("outer", () => {
  describe("inner", () => {
    test("my test", () => {});
  });
});

效能提升

new Buffer() 快 10 倍

先前,Bun 中的 Buffer 實作使用 Object.setPrototypeOf() 來建立每個新實例。消除此瓶頸使在 Bun 中實例化小型 Buffer 快 10 倍。

10x faster Buffer

crypto.createHash() 快 50 倍

先前,Bun 使用純 JavaScript 實作 crypto.createHash()。現在它使用來自 BoringSSL 的原生程式碼實作,效能提升 50 倍。

支援 HTTPS_PROXY

Bun 現在將在發出外送 HTTP 請求時辨識 HTTPS_PROXYHTTP_PROXYNO_PROXY 環境變數,包含 fetch()bun install。這些變數讓您可以指定代理伺服器來轉發或不轉發特定的 HTTP 請求,在公司防火牆內執行 Bun 時非常有用。

export HTTPS_PROXY="http://proxy.example.com:8080"
export NO_PROXY="localhost,noproxy.example.com"

如果您想了解更多關於這些變數的資訊,GitLab 撰寫了一篇不錯的解釋文章

模組解析變更

模組解析有兩個變更可能會影響少數套件。

  1. Bun 不再檢查 package.json 中的 browser 屬性。這是因為某些套件會停用 Node.js 功能,這不是我們對 Bun 想要的。
  2. 為了更好的 Node.js 和 npm 相容性,Bun 的 JavaScript 執行時環境現在會讀取 package.json exports 中的 "node" 匯出條件。

Bun 的 JavaScript 執行時環境讀取 package.json "exports" 條件的順序為

["bun", "worker", "module", "node", "browser", "default"];

這表示如果套件具有 "node" 匯出條件,將會使用它來取代 "default""browser" 匯出條件。

變更日誌

當我們持續為 Bun 新增功能時,我們仍然專注於提高穩定性和修正錯誤。此版本修正了許多問題:

bun install 的修正

Bun 套件管理員的數個錯誤在此版本中已修正,主要由 @alexlamsl 完成。感謝 Alex!

#1664先前,使用 bun install 設定的 scoped 和 private 套件會具有 localhost 的登錄檔,這非常沒有道理。我們已修正此問題,如果未指定,private 登錄檔現在將預設為預設登錄檔,通常是 registry.npmjs.org
#1667通常,npm client 應該要傳遞 npm-auth-type header,但 bun install 沒有。我們已修正此問題,現在 bun install 將會傳遞 npm-auth-type header。
a345efd在某些 CI 環境中,例如 Vercel,連結 node_modules/.bin 會失敗,因為未掛載 /proc 檔案系統 (用於解析絕對檔案路徑)。我們已透過在 /proc/fd 無法使用時回退到 fchdirgetcwd 來修正此問題。
385c81dpackage.json 中的 "dependencies" 列表從空白變為非空白時,執行 bun add <package> 有時會發生當機。
#1665當設定 scopes 時,使用 npm 作為預設登錄檔
#1671修正 bun install 中的記錄詳細程度
#1799修正 bun install 中的生命週期腳本執行

新 API

6260aaa實作 crypto.scrypt() 和更多 node:crypto API
d726a17實作 Bun.RIPEMD160
940ecd0實作 process.uptime()process.umask()
85eda20實作 Bun.CryptoHasher
#1727實作 expect().toThrow()
#1659實作 Buffer.{swap16,swap32,swap64}@malcolmstill
c18165bBun.listen() 中新增對 ttl: true 的支援
734b5b8Server.stop()Socket.stop() 新增 closeActiveConnections 參數
8e9af05d變更 WebSocket 以接受具有 httphttps 協定的 URL

其他修正

#1670修正不正確的 206 Partial Content 回應
#1674修正 console.log({ name: "" }) 會印出不正確格式的錯誤
3d60b87修正 ReadableStream.pipeTo()
#1689修正 bun wiptest 未等待非同步生命週期 hooks
#1700修正 Bun.listen()Bun.connect() 的殘留程序
#1705 #1730修正未以 Bun.listen() 呼叫 connectError 回呼的問題
#1695修正影響 @tensorflow/tfjs-backend-wasm 的轉譯器錯誤 — @theoparis
#1716修正 TextDecoder 被匯出為 TextEncoder 的錯誤 (糟糕!) — @torbjorn-kvist
#1734修正未處理的 Promise 拒絕未導致錯誤結束代碼的問題
fadd1c0修正 Bun.connect() 不會在連線錯誤時拒絕的問題
2392e48修正 describe 區塊中未捕獲的錯誤會結束 bun wiptest 的問題
88ffdc5修正 export default class implements 的轉譯器錯誤
#1800修正 Response 不接受 2xx 以下 status 的問題
7dd28bb修正 Bun.which() 會意外偵測到 macOS 上的目錄的問題
修正各種錯誤並改善與 Node-API 的相容性:59655d0 f79301c 994e58b c505f17 02f0212 d54e23c 59655d0 f79301c

貢獻者

感謝所有為 Bun v0.5 做出貢獻的人!