Bun

Bun v0.3.0


Ashcon Partovi · 2022 年 12 月 7 日

今天,Bun 有兩個主要優先事項:與 Node.js 和 Web API 穩定性相容性。在 v0.3.0 中,我們在這兩個目標上都取得了重大進展。有很多變更要介紹,因此我們先從重點開始。

注意 — 我們是一個小型團隊,致力於讓使用 JavaScript 進行建置更快更簡單。如果您有興趣加入我們,請查看我們的職涯頁面,我們正在招聘 JavaScript、C/C++ 和 Zig 工程師!

安裝方式

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

升級方式

bun upgrade

穩定性改進

  • Bun 現在在負載下使用的記憶體減少 3-5 倍。先前,Bun 未協調事件迴圈排程垃圾收集。(請參閱此處的基準測試)

  • Bun 現在針對 console.log() 具有更好的格式設定(對於偵錯很重要!)

    Better formatting for console.log()

  • Bun 已修正文字編碼的數個錯誤,現在使用 simdutf 以實現 速度快 3 倍TextEncoder.encodeInto()

    Bun now has 3x faster text encoding

  • Bun 現在可在更多 Linux 環境中運作,包括 Amazon Linux 2 以及適用於 Vercel 和 Cloudflare Pages 的組建。(先前,您可能看過類似「version 'GLIBC_2.29' not found」的錯誤)

還有許多其他變更

Node.js 相容性

Bun 現在支援下列 Node.js API

全新和改進的 API

一覽,以下是變更內容

console 現在是 AsyncIterable

Bun 正在使用對非瀏覽器有意義的 API,讓您更容易從主控台讀取輸入。console 現在是 AsyncIterable,可讓您透過對 console 進行 for await 迴圈,從 stdin 串流文字行。

for await (const line of console) {
  console.log("Received:", line);
}

若要寫入 stdout,您也可以使用 console.write(),這會略過 console.log() 的格式設定。

console.write("hello");
console.write("hello", "world", "\n");

const response = await fetch("https://example.com/");
console.write("Response: ", await response.arrayBuffer());

從 npm 自動安裝套件

當沒有 node_modules 目錄時,Bun 現在會自動從 npm 安裝 import 上的套件。為了節省磁碟空間,套件會下載到共用全域快取目錄中。為了安全起見,不會執行 postinstall 指令碼。

react-version

若要指定套件版本,您可以繼續使用 package.json,也可以在 import 路徑中包含範圍指定詞。只有在沒有 package.json 的情況下才支援這些範圍指定詞。

import { renderToReadableStream } from "react-dom@latest/server";
import { serve } from "bun";

serve({
  async fetch(req) {
    const stream = await renderToReadableStream(
      <html>
        <body>
          <h1>Hello, world!</h1>
        </body>
      </html>,
    );
    return new Response(stream);
  },
});

Bun 繼續支援 node_modules 資料夾,這表示這不是重大變更。如果您想要停用此功能,可以使用 --no-install 旗標執行 Bun。

FileSystemRouter

Bun 現在公開 FileSystemRouter,這是一個快速 API,用於針對檔案系統路由器解析傳入路徑。初始化後,它可以快速針對路由器解析路徑或 Request

請考慮下列 Next.js 樣式 pages 目錄

/path/to/project
├── server.ts
├── pages
  ├── index.tsx
  ├── settings.tsx
  ├── blog
  │   ├── index.tsx
  │   └── [slug].tsx
  └── [[...catchall]].tsx

server.ts 中,您可以初始化指向 pages 目錄的 FileSystemRouter

import { FileSystemRouter } from "bun";

const router = new FileSystemRouter({
  dir: import.meta.dir + "/pages",
  style: "nextjs",
});

路由器樣式 — 目前,唯一支援的 stylenextjs。我們計劃在未來支援其他樣式,包括 Next.js 13 樣式 app 目錄。

您可以使用 router 執行個體來針對您定義的頁面解析傳入的要求。此比對是在原生程式碼中實作,而且比以 JavaScript 為基礎的路由器快得多。

router.match("/");
// { filePath: "/pages/index.tsx" }

router.match("/blog");
// { filePath: "/pages/blog/index.tsx" }

router.match("/blog/my-first-post?foo=bar");
// {
//   filePath: "/pages/blog/[slug].tsx" }
//   params: { slug: "hello-world" },
//   query: { foo: "bar" }
// }

bun:test 中的 Expect 比對器

已在 bun:test 中實作 expect() 比對器上的更多方法。我們也對 expect() 進行效能改進,這使得 toEqual() 比 Jest 快 100 倍。長期而言,我們希望 bun:test 成為使用 Jest 和 Vitest 的公司的極快速直接替換方案。

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

test("new expect() matchers", () => {
  expect(1).not.toBe(2);
  expect({ a: 1 }).toEqual({ a: 1, b: undefined });
  expect({ a: 1 }).toStrictEqual({ a: 1 });
  expect(new Set()).toHaveProperty("size");
  expect([]).toHaveLength(0);
  expect(["bun"]).toContain("bun");
  expect(true).toBeTruthy();
  expect(Math.PI).toBeGreaterThan(3.14);
  expect(null).toBeNull();
});

注意 — 您可以使用 bun wiptest 試用測試執行器。

Headers 上的新方法

Headers 類別現在實作 .getAll().toJSON() 方法。這些在技術上都是非標準方法,但我們認為它們會讓您的生活更輕鬆。

const headers = new Headers();
headers.append("Set-Cookie", "a=1");
headers.append("Set-Cookie", "b=1; Secure");

console.log(headers.getAll("Set-Cookie")); // ["a=1", "b=1; Secure"]
console.log(headers.toJSON()); // { "set-cookie": "a=1, b=1; Secure" }

可調整大小的 ArrayBuffer 和可成長的 SharedArrayBuffer

在 WebKit 中實作了 .resize() ArrayBuffer.grow() SharedArrayBuffer 的能力,現在 Bun 中已提供。感謝 WebKit!

const buffer = new ArrayBuffer({
  byteLength: 1024,
  maxByteLength: 2048,
});

console.log(buffer.byteLength); // 1024
buffer.resize(2048);
console.log(buffer.byteLength); // 2048

Array.fromAsync()

WebKit 中也實作了 Array.fromAsync() 方法,現在 Bun 中已提供。它類似於 Array.from(),但它接受非同步可迭代輸入。再次感謝 WebKit!

async function* listReleases() {
  for (let page = 1; ; page++) {
    const response = await fetch(
      `https://api.github.com/repos/oven-sh/bun/releases?page=${page}`,
    );
    const releases = await response.json();
    if (!releases.length) {
      break;
    }
    for (const release of releases) {
      yield release;
    }
  }
}

const releases = await Array.fromAsync(listReleases());

變更記錄

還有許多其他變更!以下是完整清單