Bun

Bun v1.0.19


Jarred Sumner · 2023 年 12 月 22 日

Bun v1.0.19 修復了 26 個錯誤(解決了 92 個 👍 反應)。使用 @types/bun 而不是 bun-types。修復了「lockfile had changes, but is frozen」錯誤。bcryptargon2 套件現在可以運作了。setTimeoutsetInterval 獲得了 4 倍更高的吞吐量。bun:test 中的模組模擬解析了指定符。最佳化了 Linux 上大型 stdio 的 spawnSync()。Bun.peek() 速度提高了 90 倍,expect(map1).toEqual(map2) 速度提高了 100 倍。修復了 NAPI、bun install 和 Node.js 相容性改進的錯誤

Bun 是一個速度極快的 JavaScript 執行時環境、打包器、轉譯器和套件管理器 — 功能All-in-One。如果您錯過了,以下是 Bun 最近的一些變更

  • v1.0.14 - Bun.Glob,一個使用 glob 模式比對檔案和字串的快速 API。它還修復了在 bun install 期間提取相依性時的競爭條件,改進了 node_modules 中的 TypeScript 模組解析,並使錯誤訊息更易於閱讀。
  • v1.0.15 - 修復了 23 個錯誤(解決了 117 個 👍 反應),tsc 啟動速度提高了 2 倍。穩定的 WebSocket 客戶端、語法突顯錯誤、更清晰的堆疊追蹤,使用 expect.extend() 新增自訂測試匹配器 + 其他 expect 匹配器。
  • v1.0.16 - 修復了 49 個錯誤(解決了 38 個 👍 反應)。Bun.file 和 Bun.write 的並行 IO 速度提高了 3 倍,現在支援 Google Cloud Run 和 Vercel,Bun.write 會自動建立父目錄(如果不存在),expect.extend 在 preload 內部運作,napi_create_object 速度提高了 2.5 倍,修復了影響 Astro v4 和 p-limit 的模組解析錯誤,console.log 錯誤修復
  • v1.0.17 - 修復了 15 個錯誤(解決了 152 個 👍 反應)。bun install postinstall 腳本適用於前 500 個套件,bunx supabase 啟動速度比 npx supabase 快 30 倍,bunx esbuild 啟動速度比 npx esbuild 快 50 倍,以及 bun install 的錯誤修復
  • v1.0.18 - 修復了 27 個錯誤(解決了 28 個 👍 反應)。已修復影響 create-vite 和 create-next 和 stdin 的卡頓問題。已修復生命週期腳本回報「node」或「node-gyp」找不到的問題。expect().rejects 現在像 Jest 一樣運作,以及更多錯誤修復

安裝 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

重新引入 @types/bun(以前稱為 bun-types

@types/bun 為您提供 Bun 的類型定義。它是一個與 Bun 本身分開的套件,以便更輕鬆地將 Bun 與您的文字編輯器或 IDE 一起使用。

以前,這個套件稱為 bun-types,並且存在許多問題

  • 您必須在 tsconfig.json 中設定 types,這破壞了使用 @types 資料夾慣例載入套件
  • 我們嵌入了稍微修改過的 @types/node 版本,這經常與真正的 @types/node 套件衝突
  • 除非您正確設定,否則它無法在 TypeScript 中「直接運作」
  • DOM/Web 類型偶爾會與 Bun 的類型衝突

現在,@types/bun 應該可以直接運作。它重新匯出真正的 @types/node 套件,因此不會有衝突。由於它現在位於 @types 命名空間中,因此它應該可以在不破壞 @types/* 套件的情況下運作。

安裝 @types/bun

bun add -d @types/bun

或者您可以使用 bun init

bun init

bcrypt & argon2 套件現在可以運作了

N-API 相容性改進解鎖了 Bun 中的 bcryptargon2 套件支援。這些套件廣泛用於安全地雜湊和驗證密碼。

Bun.password 也可讓您使用 bcrypt 或 argon2 雜湊和驗證密碼,而無需安裝任何相依性。

已修復:「lockfile had changes, but is frozen」錯誤

--frozen-lockfile 使用的程式碼路徑有時會錯誤地回報鎖定檔已變更(即使它沒有變更),以偵測鎖定檔是否已變更。這會導致類似以下的錯誤

error: lockfile had changes, but is frozen

為了修復此問題,我們變更了定義「frozen」的方式。我們不再依賴可能因不相關原因而變更的檔案系統輸入,而是切換為使用套件名稱的雜湊及其版本號碼(按字母順序排序)。我們認為這是一種更可靠的方法。

若要查看鎖定檔的雜湊值,請執行

bun pm hash-string

檢視範例輸出

setTimeoutsetInterval 獲得了 4 倍更高的吞吐量

Bun 的 setTimeoutsetInterval 實作在 Linux x64 上現在快了 4 倍。我們新增了一個計時器堆積,以更有效率地管理計時器。

❯ bun setTimeout-leak-test.js
Executed 1003520 timers in 421.560553 ms

❯ bun-1.0.18 setTimeout-leak-test.js
Executed 1003520 timers in 2287.405973 ms

感謝 @mitchellhlibxev,提供計時器堆積實作。

為什麼計時器效能很重要?

您可能會想到類似以下的想法

「計時器會延遲程式碼執行。速度快有什麼關係?」

計時器排程對您的程式碼效能有顯著影響,許多程式庫都使用計時器來排程具有輕微延遲的工作。計時器不必觸發得更快,但計時器排程需要快速。

Bun 之前的計時器實作有點不負責任。在 Linux 上,它為每個計時器建立一個 timerfd。這表示每個計時器都涉及多個系統呼叫並佔用檔案描述器。對於可能非常頻繁運行的程式碼來說,這是一個很大的負擔。

Bun 的新計時器實作使用計時器堆積。這是一種資料結構,可讓我們有效率地排程可能數百萬個計時器。

已修復:setInterval 有時在 clearInterval 之後仍然運行

存在一個錯誤,已取消的 setInterval 呼叫偶爾仍然會運行一次。這在重寫計時器實作的過程中得到了修復。

針對在 async 函式外部使用 await 提供更好的錯誤訊息

當您在 async 函式外部使用 await 時,我們新增了更好的錯誤訊息。

❯ bun file.js # after
3 |   await fetch("https://example.com")
            ^
error: "await" can only be used inside an "async" function
    at file.js:3:9

2 | function ohNo() {
    ^
note: Consider adding the "async" keyword here
   at file.js:2:1

以前,它只會顯示

❯ bun-1.0.18 file.js # before
3 |   await fetch("https://example.com")
            ^
error: Expected ";" but found "fetch"
    at file.js:3:9

最佳化了 Linux 上大型輸入的 Bun.spawnSync

在 Linux 上,Bun.spawnSync 現在更聰明地處理如何從子程序讀取和寫入資料。我們已從必須由父程序迴圈讀取和寫入的管道切換到記憶體檔案描述器,這不會導致程序在讀取或寫入大量資料時封鎖。這也讓我們可以避免將資料從子程序複製到父程序,這對於大量資料來說可能很昂貴。

此變更使 Bun.spawnSync 在子程序有大量輸出時速度提高了 50%。

Bun.spawnSync performance improvements

Bun.peek() 速度提高了 90 倍

Bun.peek(promise) 可讓您讀取 Promise 的值,而無需等待其解析(如果不再處於擱置狀態)。這對於避免微任務並提高效能非常有用。

我們已將實作從依賴 C++ SPI 切換為使用 JavaScriptCore 位元組碼內建函式,這使其速度提高了 90 倍。

感謝 @paperclover

expect(map1).toEqual(map2) 速度提高了 100 倍

我們最佳化了比較 Map 實例時 expect(...).toEqual 的實作。這使 Map 的速度提高了 100 倍。這也使 Set 實例的速度更快。

我們還修復了一個錯誤,即大型 Map 上的 toEqual 有時會錯誤地回報 Map 不相等。

在 X 上檢視

bun:test 中的模組模擬解析指定符

Bun 支援使用 mock.module 函式在 bun:test 中模擬模組。以前,specifier 引數必須完全符合載入覆寫模組時使用的已解析模組指定符。

這非常令人困惑!人們通常不會考慮已解析模組指定符和模組指定符之間的差異,這表示當它實際運作時,它似乎無法運作。由於 ES 模組在評估模組之前會解析和連結模組,因此已解析模組指定符通常與您在 import 陳述式中使用的模組指定符不同。

現在,mock.module 在模擬模組之前解析指定符。這表示您可以使用模組指定符(您放在 import 陳述式中的路徑)而不是已解析模組指定符(您在錯誤訊息中看到的路徑)。

import { mock, test, expect } from "bun:test";
import _ from "lodash";

  // Before: you had to resolve it yourself:
  mock.module(require.resolve("lodash"), () => ({ default: "mocked" }));
  // Now: you can use the module specifier:
  mock.module("lodash", () => ({ default: "mocked" }));

test("lodash is mocked", () => {
  expect(_).toEqual("mocked");
});

記錄慢速 postinstall 腳本

如果 post-install 腳本的執行時間超過 500 毫秒,bun install 現在會將其記錄為警告。這對於識別慢速 post-install 腳本非常有用。

bun add v1.0.19 (7e59f287)

 installed re2@1.20.9

+warn: re2's install script took 57.7s

 92 packages installed [58.20s]

為了避免終端機回溯混亂,我們只記錄最慢的 post-install 腳本(而不是全部)。

感謝 @paperclover

已修復:執行 post-install 腳本時可能發生的卡頓

存在一個事件迴圈錯誤,可能會導致 bun install 在執行 post-install 腳本時可能卡頓(因為沒有意識到它們已結束)。這已修復,感謝 @dylan-conway

bun install --verbose 現在會串流 post-install 腳本輸出

當運行 bun install --verbose 時,post-install 腳本輸出現在會串流到終端機,而不是在結尾緩衝和列印。這讓您更容易查看正在發生的事情。感謝 @dylan-conway 實作此功能。

已修復:post-install 腳本輸出中缺少進度列

在某些情況下,bun install 在 post-install 腳本執行時不會顯示進度列。這已修復,感謝 @dylan-conway

已修復:字串化 SHA1、SHA256、MD5 雜湊有時會輸出過長的字串

將 SHA1、SHA256 或 MD5 雜湊的輸出編碼為 hexbase64 字串時,存在一個錯誤,有時會輸出比雜湊內容更長的字串。現在已修復。

這影響了

  • Bun.CryptoHasher
  • node:crypto 中的 createHash

將 SQLite 從 v3.38.5 升級到 v3.44.2

bun:sqlite 是一個內建於 Bun 的快速 SQLite 客戶端。在 Linux 上,bun:sqlite 是靜態連結的,這表示我們將 SQLite 程式庫嵌入到 Bun 本身中。這表示您無需在系統上安裝 SQLite 即可使用它。

我們已將嵌入式 SQLite 程式庫從 v3.38.5 升級到 v3.44.2。您可以在此處查看完整的變更記錄。

已修復:TypeScript 解析器邊緣案例

以前,以下輸入會錯誤地解析失敗

const a = <T = any>(): T => null as T;
const b = a<string>

現在已修復。感謝 @paperclover 修復此問題。

已修復:bun init 中的當機

bun init 中有時會發生的當機已修復,感謝 @paperclover

已修復:$NODE_ENV 的迴歸

在 Bun v1.0.18(先前版本)中,我們不小心移除了 NODE_ENV 的預設值設定。此重大變更不應包含在 Bun v1.01.8 中。我們未來可能會進行重大變更以取消設定預設值(在 bun test 之外),但我們不會在修補程式版本中執行此操作。

感謝 @paperclover 修復此問題。

已修復:空洞陣列的列印錯誤

存在一個錯誤,列印空洞陣列會遺漏分隔符號和逗號。現在已修復,感謝 @amartin96

之後

❯ bun -e 'console.log([1,,,2,1,3])' # After
[ 1, 2 x empty items, 2, 1, 3 ]

之前

❯ bun-1.0.18 -e 'console.log([1,,,2,1,3])' # Before
[ 12 x empty items, 2, 1, 3 ]

bun:test 中的新匹配器 expect().toContainEqual()

我們在 bun:test 中新增了一個名為 toContainEqual 的新匹配器。這與 toContain 類似,但它使用 toEqual 來比較值,而不是 ===

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

test("toContainEqual", () => {
  expect("hello world").toContainEqual("hello");
  expect("hello world").not.toContainEqual("jello");
});

感謝 @Electroid 實作此功能。

貢獻者

我們很高興看到新的貢獻者!以下是 9 位在此版本中首次為 Bun 做出貢獻的人

感謝 18 位貢獻者讓 Bun v1.0.19 成為可能