Bun

Bun v0.5.8


Ashcon Partovi · 2023 年 3 月 18 日

Bun v0.5.8 引入了 bun test 中的 expect() 快照(snapshot)測試、使用 bun --preload 預先載入模組、Web API 和 Node.js 相容性的改進、大量的錯誤修正,以及對未來發展方向的預告。

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

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

使用 bun test 進行快照測試

bun test 旨在成為高效能、可直接替換 Jest 的工具。現在它支援快照測試,使用 expect(value).toMatchSnapshot(),它支援與 Jest 相同的快照格式。以下是其運作方式

首先,建立一個測試。

snapshot.test.ts
import { test, expect } from "bun:test"; // "bun:test" imports are optional

test("can test a snapshot", async () => {
  const response = await fetch("https://example.com/");
  const body = await response.text();
  expect(body).toMatchSnapshot();
});

然後,使用 bun test 執行測試檔案。

bun test snapshot.test.ts

接著,您將在終端機中看到以下輸出。

 snapshot.test.ts:
can test a snapshot

1 pass
0 fail
snapshots: +1 added
 1 expect() calls
Ran 1 tests across 1 files [48.00ms]

最後,您會看到已產生新的快照檔案。Bun 使用與 Jest 相同的快照格式,這表示從 Jest 遷移到 bun test 時,您不需要重新產生快照。

snapshots /snapshot.test.ts.snap
exports[`can test a snapshot 1`] = `
"<!doctype html>
<html>
<head>
    <title>Example Domain</title>
</head>
</html>
"
`;

如果您需要更新快照,您可以傳遞 --update-snapshots 旗標,這將更新每個已執行測試檔案的快照。

bun test --update-snapshots

除了 toMatchSnapshot() 之外,Bun 現在還支援以下新的匹配器

我們還新增了一個旗標,可以多次重新執行測試檔案,以協助重現不穩定的測試中的錯誤。

bun test --rerun-each=5

這會重新執行每個測試檔案 5 次。

bun --preload <preload> [command]

Bun 現在可以在執行檔案或測試套件之前預先載入檔案。此行為類似於 node --require

若要透過 --preload 旗標預先載入檔案

bun --preload ./preload.ts run ./index.ts

若要在 bunfig.toml 中設定要 preload 的檔案清單

bunfig.toml
preload = ["./preload.ts"]

這對於註冊 plugins、注入全域變數或執行設定任務非常有用,而無需在您的腳本或進入點中加入額外的 import()require() 陳述式。

以下範例說明如何預先載入 Bun.plugin() 以載入 .yml 檔案。

index.ts
config.yml
yaml.plugin.ts
index.ts
import config from "./config.yml";

console.log(config);
config.yml
enabled: true
yaml.plugin.ts
import { plugin } from "bun";

plugin({
  name: "YAML",
  async setup(build) {
    const { load } = await import("js-yaml");
    const { readFileSync } = await import("fs");

    // when a .yaml file is imported...
    build.onLoad({ filter: /\.(yaml|yml)$/ }, (args) => {

      // read and parse the file
      const text = readFileSync(args.path, "utf8");
      const exports = load(text) as Record<string, any>;

      // and returns it as a module
      return {
        exports: {default: exports, ...exports},
        loader: "object", // special loader for JS objects
      };
    });
  },
});

您現在可以從您的進入點匯入 .yml 檔案

bun --preload ./yaml.plugin.ts index.ts
{
  enabled: true
}

若要避免使用 --preload 旗標,請設定 bunfig.toml

bunfig.toml
preload = ["./yaml.plugin.ts"]

現在執行 bun testbun run 將自動預先載入外掛程式。

bun run index.ts
{
  enabled: true
}

bun install workspaces 中的部分 glob 支援

現在 bun install"workspaces" 中支援以下模式

{
  "name": "myWorkspace",
  "workspaces": [
    // Make all folders with a package.json and a name in packages/ part of the workspace
    "packages/*"
  ]
}

您可以使用 /* 將所有符合前綴的資料夾新增到您的工作區。這對於具有許多套件的 monorepo 非常有用。

目前,僅支援在結尾的單一 glob 模式 (foo/*)。我們計劃在未來改進我們的 glob 支援。同時,當 glob 模式尚未實作時,我們也新增了更佳的錯誤訊息。

Web 相容性

由於 Bun 的測試覆蓋率有所提高,我們修復了 Bun 的 Web API 相容性中的許多錯誤。

request.bodyUsed & response.bodyUsed

當使用 nullundefined body 時,request.bodyUsedresponse.bodyUsed 與規範不一致。

const response = new Response(null);

await response.arrayBuffer();

console.log(response.bodyUsed);

/*

Incorrect:

   Bun v0.5.7: true

Correct:

   Bun v0.5.8: false
       Chrome: false
       Safari: false
*/

取用 RequestResponse 的 body

現在可以多次取用 nullundefinedRequestResponse body,這與 Chrome 和 Safari 的行為一致。

先前,當嘗試兩次取用 nullundefined body 時,Bun 會拋出錯誤

bun-0.5.7 response.js
1 | const response = new Response(null);
2 | await response.arrayBuffer();
3 | console.log(await response.arrayBuffer());
                ^
error: Body already used

現在,nullundefined body 上的 .arrayBuffer() 會改為傳回空的 ArrayBuffer

bun response.js

ArrayBuffer(0) [ ]

/*

Incorrect:

   Bun v0.5.7: <error> "Body already used"

Correct:

   Bun v0.5.8: ArrayBuffer(0) [ ]
       Chrome: ArrayBuffer(0) [ ]
       Safari: ArrayBuffer(0) [ ]
*/

同樣地,當沒有 body 時,Response.prototype.body 應該傳回 null,但 Bun 卻傳回空的 ReadableStream

const response = new Response(null);
console.log(response.body);

/*

Incorrect:

   Bun v0.5.7: ReadableStream { ... }

Correct:

   Bun v0.5.8: null
       Chrome: null
       Safari: null
*/

blob.slice() contentType 引數

blob.slice 接受選用的第三個引數,用於新 Blobtype。先前,Bun 不支援此引數。

const blob = new Blob(["Hello, world!"], { type: "text/plain" });
const slice = blob.slice(0, 5, "text/html; charset=utf-8");
console.log(slice.type); // "text/html; charset=utf-8"

/*

Incorrect:

   Bun v0.5.7: ""

Correct:

   Bun v0.5.8: "text/html; charset=utf-8"
       Chrome: "text/html; charset=utf-8"
       Safari: "text/html; charset=utf-8"
*/

Request 建構子

Bun 中的 Request 建構子有一些錯誤。

當給定兩個引數時,它總是預期第一個引數是字串,這是錯誤的。

// This didn't work: (inconsistent with the spec)
new Request(new Request("https://example.com"), {});

// But any of these did:
new Request(new Request("https://example.com"));
new Request("https://example.com", { method: "POST" });
new Request("https://example.com", {});

這已修正,現在第一個引數可以是字串或 Request 物件。

// This works now:
console.log(new Request(new Request("https://example.com"), {}).url);

// "https://example.com"

另一個錯誤:url 引數未正確驗證(在 fetch() 中驗證,但在 new Request() 中未驗證)

// this is supposed to throw:
const request = new Request("", { method: "POST" });

現在它(正確地)拋出錯誤

bun /tmp/app.js
1 | const request = new Request("", { method: "POST" });
                   ^
error: Failed to construct 'Request': url is required.

Bun 對於 Request 建構子的測試覆蓋率不足,且 Bun 的 fetch 實作(確實會驗證)未使用與 Request 建構子相同的程式碼路徑。

Node.js 相容性

Bun 持續改進 Node.js 相容性。以下是自上次發佈以來變更的內容。

Bun.sleepSync()

為了修正 Bun.sleep()Bun.sleepSync() 之間的不一致問題,有一個重大變更Bun.sleepSync() 現在接受毫秒,而不是秒。透過在 GitHub 上使用程式碼搜尋,我們發現大多數用法已經假設單位是毫秒。

Bun.sleepSync(1); // sleep for 1 ms (not recommended)
await Bun.sleep(1); // sleep for 1 ms (recommended)

接下來是什麼?

對於 Bun v0.6,您可以期待重大的變更,包括全新的打包器!

Bun 即將推出的打包器旨在讓建置現代化的全堆疊 JavaScript 和 TypeScript 應用程式更簡單(且更快速)。

當然,隨著 Bun 逐漸接近 1.0 版本,我們將繼續朝著 Node.js 相容性、整體穩定性和效能的優先事項邁進。為了衡量朝著這些目標的進展,我們大幅提高了 Bun、Node.js 和標準 Web API 的測試覆蓋率。敬請期待。

變更記錄

#2156修正了 {Request,Response}.body 不為 null 的問題,由 @cirospaciari 貢獻
#2115針對 macOS 實作了 os.cpus(),由 @jwhear 貢獻
#2161修正了 HTMLRewriter.onDocument() 未執行的問題,由 @jwhear 貢獻
#2144修正了 dns.{resolve4,resolve6}() 的傳回值不正確的問題,由 @cirospaciari 貢獻
599f63c支援舊版 macOS,包括 10.15,由 @Jarred-Sumner 貢獻
0a7309c改進了 EventEmitter 的效能,由 @Jarred-Sumner 貢獻
eb94e5b將 BoringSSL 變更為從 mimalloc 使用 heap,由 @Jarred-Sumner 貢獻
#2192改進了 bun pm ls 的穩定性,由 @alexlamsl 貢獻
693be3d改進了 ASCII 不區分大小寫比較的效能,由 @Jarred-Sumner 貢獻
#2202修正了 ANSI escape codes 未從 stdout 管道傳輸到檔案的問題,由 @alexlamsl 貢獻
5d296f6修正了 shasum 被剖析兩次的問題,由 @Jarred-Sumner 貢獻
#2213修正了 bun install 和重複依賴項的問題,由 @alexlamsl 貢獻
#2142實作了 os.networkInterfaces(),由 @jwhear 貢獻
#2191修正了 bun dev 的埠號不正確的問題,由 @xjmdoo 貢獻
#2143修正了關閉時 fetch({ signal }) 的問題,由 @cirospaciari 貢獻
#2223實作了 http.listen({ signal }),由 @cirospaciari 貢獻
#2222實作了 http.get({ signal }),由 @cirospaciari 貢獻
#2226移除了 sqlite 在給定空陳述式時的暫時性錯誤,由 @ThatOneBro 貢獻
#2231實作了 bun --preload <file>,由 @Jarred-Sumner 貢獻
#2249修正了空檔案上 Bun.file().arrayBuffer() 的問題,由 @cirospaciari 貢獻
#2258修正了 http.request() 不接受 URL 的錯誤,由 @ThatOneBro 貢獻
#2262改進了當 method 為 GET 或 HEAD 且具有 body 時 http.request() 的相容性,由 @ThatOneBro 貢獻
#2242[重大變更] Bun.sleepSync() 現在以毫秒為單位,而不是秒,由 @jwhear 貢獻
#2276修正了 os.tmpdir() 從移除尾部斜線的問題,由 @cirospaciari 貢獻
#2285修正了 node:httprequest.url 不包含 search params 的問題,由 @zhiyuang 貢獻
#2295變更了不帶參數的 bunx 以顯示說明頁面,由 @Zeko369 貢獻
#2288修正了 node:http 中標頭未小寫的問題,由 @ThatOneBro 貢獻
#2293修正了 bunx 無法找到 scoped npm 套件的問題,由 @Zeko369 貢獻
#2302修正了在 semver 範圍內未考量 "latest" 的問題,由 @alexlamsl 貢獻
#2307修正了 bun install 未向 npm 登錄檔報告連線錯誤的問題,由 @alexlamsl 貢獻
#2314實作了 expect().toThrow(RegExp),由 @alexlamsl 貢獻
#2315修正了 Linux 上 Blob 的錯誤訊息,由 @alexlamsl 貢獻
#2320process.{stdout,stderr} 實作了部分 tty.WriteStream,由 @ThatOneBro 貢獻
0a9cb0e修正了 HTMLRewriter 收到空字串時的問題,由 @Jarred-Sumner 貢獻
#2331修正了 crypto.scryptSync() 的參數錯誤,由 @dylan-conway 貢獻
#2341改進了 Buffer 與 Node.js 的相容性,由 @alexlamsl 貢獻
e16053c修正了 crypto.createHash().update("binary") 無法運作的問題,由 @Jarred-Sumner 貢獻
#2340改進了 Blob.type 的規格相符性,由 @Jarred-Sumner 貢獻
#2371修正了當 require.resolve() 引數為空時的錯誤,由 @paperclover 貢獻
#2337net.Server 中實作了 unix socket 支援,由 @cirospaciari 貢獻
4c38798修正了 Socket.remoteAddress 的編碼不正確的問題,由 @Jarred-Sumner 貢獻
27f5012修正了 node:https 為唯讀的問題,由 @Jarred-Sumner 貢獻
#2389實作了 expect().toBeInstanceOf(),由 @zhiyuang 貢獻
e613b50node:zlib 中實作了遺失的 constants,由 @Jarred-Sumner 貢獻
#2294實作了 expect().toMatchSnapshot(),由 @dylan-conway 貢獻
#2397修正了剖析格式錯誤的 bun.lockb 的問題,由 @alexlamsl 貢獻
#2400修正了 Bun.serve() 無法在 IPv6 上監聽的問題,由 @cirospaciari 貢獻
9a5f78f修正了 console.log() 未顯示 [Getter] 值的问题,由 @Jarred-Sumner 貢獻
#2404實作了 expect().toMatch(RegExp),由 @zhiyuang 貢獻

此外,如果您還沒聽說,Bun 現在有文件了!

非常感謝 @colinhacks,以及自上次發佈以來做出貢獻的許多人:@jakeboone02@charliermarsh@BrettBlox@damianstasik@Sheraff@johnnyreilly@fdaciuk@akash-joshi@TommasoAmici@raxityo@DreierF@rmorey@cunzaizhuyi@rodoabad@gaurishhs@maor-benami@aabccd021@pfgithub@bushuai@Zeko369@noahmarro@harisvsulaiman@nskins@milesj@jsoref