Bun v1.0.15 修正了 23 個錯誤(解決了 117 個 👍 反應),tsc
啟動速度快 2 倍,Prettier 快 40%。穩定的 WebSocket
用戶端、語法突顯錯誤、更清晰的堆疊追蹤、使用 expect.extend()
新增自訂測試匹配器 + 其他 expect 匹配器、TensorFlow.js 支援,以及更多功能。
Bun 是一個極其快速的 JavaScript 執行環境、打包工具、轉譯器和套件管理器 — 功能All-in-One。如果您錯過了,以下是 Bun 最近的一些變更
v1.0.12
- 新增bun -e
以評估腳本、bun --env-file
以載入環境變數、server.url
、import.meta.env
、expect.unreachable()
、改進的 CLI 說明輸出,以及更多功能v1.0.13
- 修正了 6 個錯誤(解決了 317 個 👍 反應)。現在可以使用 'http2' 模組和 gRPC.js。Vite 5 和 Rollup 4 可以運作。實作 process.report.getReport(),改進對 ES5 'with' 語句的支援,修正了 bun install 中的回歸錯誤,修正了列印例外時的崩潰問題,修正了 Bun.spawn 錯誤,並修正了 peer dependencies 錯誤v1.0.14
-Bun.Glob
,一個使用 glob 模式匹配檔案和字串的快速 API。它還修正在bun install
期間提取依賴項時的競爭條件,改進了node_modules
中的 TypeScript 模組解析,並使錯誤訊息更易於閱讀。
安裝 Bun
curl -fsSL https://bun.dev.org.tw/install | bash
npm install -g bun
brew tap oven-sh/bun
brew install bun
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun
升級 Bun
bun upgrade
轉譯器快取使像 tsc
這樣的 CLI 速度提高 2 倍
Bun 讓您可以執行 TypeScript 和 JSX 檔案,而無需建置步驟。這是透過在載入檔案之前執行 Bun 的 JavaScript 轉譯器來實現的。在此版本中,我們為大於 50KB 的檔案引入了內容可尋址快取,以避免重複轉譯相同檔案的效能開銷。這使得像 tsc
這樣的 CLI 執行速度提高了 2 倍。
與 Bun v1.0.14 相比,tsc --help
獲得了 2 倍的加速
Benchmark 1: bun --bun ./node_modules/.bin/tsc --help
Time (mean ± σ): 82.2 ms ± 2.6 ms [User: 70.1 ms, System: 14.3 ms]
Range (min … max): 78.4 ms … 87.1 ms 37 runs
Benchmark 2: bun-1.0.14 --bun ./node_modules/.bin/tsc --help
Time (mean ± σ): 197.0 ms ± 3.6 ms [User: 172.0 ms, System: 27.2 ms]
Range (min … max): 192.4 ms … 204.4 ms 14 runs
Benchmark 3: node ./node_modules/.bin/tsc --help
Time (mean ± σ): 113.8 ms ± 3.2 ms [User: 103.6 ms, System: 16.0 ms]
Range (min … max): 110.0 ms … 123.4 ms 23 runs
Summary
bun --bun ./node_modules/.bin/tsc --help ran
1.38 ± 0.06 times faster than node ./node_modules/.bin/tsc --help
2.40 ± 0.09 times faster than bun-1.0.14 --bun ./node_modules/.bin/tsc --help
Prettier 速度提高達 40%(與 Bun v1.0.14 相比)
Benchmark 1: bun --bun ./node_modules/.bin/prettier --write ./examples/hashing.js
Time (mean ± σ): 124.5 ms ± 3.2 ms [User: 144.5 ms, System: 23.4 ms]
Range (min … max): 119.9 ms … 131.8 ms 23 runs
Benchmark 2: bun-1.0.14 --bun ./node_modules/.bin/prettier --write ./examples/hashing.js
Time (mean ± σ): 184.4 ms ± 4.1 ms [User: 202.7 ms, System: 28.6 ms]
Range (min … max): 175.2 ms … 192.9 ms 15 runs
Benchmark 3: node ./node_modules/.bin/prettier --write ./examples/hashing.js
Time (mean ± σ): 162.9 ms ± 3.7 ms [User: 161.8 ms, System: 42.5 ms]
Range (min … max): 158.2 ms … 170.7 ms 17 runs
Summary
bun --bun ./node_modules/.bin/prettier --write ./examples/hashing.js ran
1.31 ± 0.04 times faster than node ./node_modules/.bin/prettier --write ./examples/hashing.js
1.48 ± 0.05 times faster than bun-1.0.14 --bun ./node_modules/.bin/prettier --write ./examples/hashing.js
為了最大限度地減少磁碟使用量,轉譯器快取是全域的,並在所有專案之間共享。隨時刪除快取是安全的,而且由於它是內容可尋址的,因此不會包含重複條目。如果您正在使用臨時檔案系統(例如 Docker)執行 Bun,建議停用快取。
如果您想自訂這些檔案的快取路徑,可以設定 BUN_RUNTIME_TRANSPILER_CACHE_PATH
環境變數。您也可以將該值設定為 0
以完全停用快取。
穩定的 WebSocket
用戶端
此版本包括(最終)穩定的 WebSocket
用戶端。Bun 已經支援 WebSocket
一段時間了,但它有各種協定錯誤,例如過早斷線或未正確處理訊息分段。現在,它已穩定,應該可以與大多數 WebSocket 伺服器一起運作。
const ws = new WebSocket("wss://echo.websocket.org/");
ws.addEventListener("message", ({ data }) => {
console.log("Received:", data);
});
ws.addEventListener("open", () => {
ws.send("Hello!");
});
為了測試合規性,我們使用了 Autobahn 測試套件,這是測試 WebSocket 實作的事實標準。Bun 通過了 100% 的 Autobahn 測試,排除了那些測試壓縮的項目。(我們的 WebSocket 用戶端尚不支援壓縮,但即將推出。)
這表示所有這些 問題 以及更多問題都已修正。
感謝 @cirospaciari 修正這些錯誤並使 Autobahn 通過測試!
expect.extend()
和更多匹配器
您現在可以使用 expect.extend()
定義自訂測試匹配器。當您想要建立可在多個測試中重複使用的自訂匹配器時,這非常有用。例如,您可以建立一個自訂匹配器來檢查數字是否在範圍內
import { test, expect } from "bun:test";
expect.extend({
toBeWithinRange(received, floor, ceiling) {
const pass = received >= floor && received <= ceiling;
if (pass) {
return {
message: () =>
`expected ${received} not to be within range ${floor} - ${ceiling}`,
pass: true,
};
} else {
return {
message: () =>
`expected ${received} to be within range ${floor} - ${ceiling}`,
pass: false,
};
}
},
});
test("toBeWithinRange()", () => {
expect(1).toBeWithinRange(1, 99); // ✅
expect(100).toBeWithinRange(1, 99); // ❌ expected 100 to be within range 1 - 99
});
Bun 還支援更多非對稱匹配器,包括
除了上述非對稱匹配器之外,Bun 還引入了兩個適用於 Promise 的新非對稱匹配器。
expect.resolvesTo
expect.rejectsTo
例如,您可以使用 expect.resolvedTo
檢查解析為值的 Promise
import { test, expect } from "bun:test";
import { getTempurature, getForecast } from "./weather";
test("expect.resolvedTo", async () => {
const weather = {
tempurature: getTempurature(),
forecast: getForecast(),
};
await expect(weather).toMatchObject({
tempurature: expect.resolvedTo.closeTo(10, 5),
forecast: expect.resolvedTo.stringMatching(/rain|snow|sleet/),
});
});
感謝 @otgerrogla 實作這些功能,並修正 expect()
的各種錯誤。
還有更多可用的模擬匹配器,包括
expect().toHaveBeenCalledWith()
expect().toHaveBeenLastCalledWith()
expect().toHaveBeenNthCalledWith()
您可以使用這些匹配器來檢查函數是否使用特定引數調用
import { test, mock, expect } from "bun:test";
test("toHaveBeenCalledWith()", () => {
const fn = mock(() => {});
sum(1, 2, 3);
expect(fn).toHaveBeenCalledWith(1, 2, 3); // ✅
expect(fn).toHaveBeenCalledWith(1, 2); // ❌
});
感謝 @james-elicx 實作這些匹配器並改進各種錯誤訊息。
錯誤的語法突顯
當 Bun 中發生例外時,它會將堆疊追蹤列印到控制台,並附帶多行原始碼預覽。現在,原始碼預覽會進行語法突顯,使其更易於閱讀。
語法突顯器還擴展到所有其他包含原始碼的錯誤,例如在使用 bun install
時,多個工作區套件共享相同名稱時發生的錯誤。
感謝 @paperclover 致力於此!
更好的 Error.stack
追蹤
我們對 Error.stack
追蹤的格式化方式進行了一些改進。
堆疊追蹤現在包含較少的雜訊,例如與錯誤無關的內部函數。
1 | throw new Error("Oops");
^
error: Oops
at /Users/jarred/Desktop/oops.js:1:7
- at globalThis (/Users/jarred/Desktop/oops.js:3:14)
- at overridableRequire (:1:20)
at /Users/jarred/Desktop/index.js:3:8
- at globalThis (/Users/jarred/Desktop/index.js:3:8)
我們還修正了一個錯誤,即 Bun 無法偵測 Error.stack
屬性是否被修改。如果您使用的函式庫修改了堆疊追蹤(例如將多個追蹤連接在一起),則可能會發生這種情況。
const err = new Error("Oops 1");
err.stack += "\n" + new Error("Oops 2").stack;
throw err;
Bun 現在重新解析 error.stack
,以便正確偵測和格式化修改後的堆疊追蹤。
fs.readdir()
中的 recursive
選項比 Node.js 快 40 倍
Bun 現在支援 fs.readdir()
中的 recursive
選項,該選項用於遞迴讀取目錄。
import { readdir } from "fs/promises";
const results = await readdir(__dirname, { recursive: true });
console.log(results); // ["a.js", "b/c.js" ...
在 Bun 儲存庫的 test/
目錄中執行 readdir()
時,在 Linux 上,它比 Node.js v21.2.0 快 40 倍。
已修正。https://127.0.0.1/WhuVBhNdc3
— Jarred Sumner (@jarredsumner) 2023 年 11 月 24 日
CommonJS 模組速度提升 1%
我們對 Bun 載入 CommonJS 模組的方式進行了一些改進,這使得它們的速度提高了 1%。
這是因為我們簡化了 CommonJS 的內部包裝函數。以前,我們的包裝函數是用 JavaScript 撰寫的,並在 Bun 的轉譯器的協助下完成。現在,這是在原生程式碼中完成的,因此速度更快,且使用的記憶體更少。
感謝 @paperclover 實作此功能!
TensorFlow.js 現在可以運作了
Bun 在 napi_create_string_utf16
和 napi_create_arraybuffer
的實作中存在一個未解決的錯誤,該錯誤阻止了 TensorFlow.js 的運作。現在已修正此問題。
import * as tf from "@tensorflow/tfjs-node";
const model = tf.sequential({
layers: [
tf.layers.dense({ units: 128, activation: "relu", inputShape: [1] }),
tf.layers.dense({ units: 3 }),
tf.layers.softmax(),
],
});
model.compile({
optimizer: "adam",
loss: "categoricalCrossentropy",
metrics: ["categoricalAccuracy"],
});
const result = model.predict(tf.tensor([0]));
if (Array.isArray(result)) throw new Error("Expected a single tensor");
const prediction = await result.data();
console.log(prediction); // Float32Array(3) [...]
支援 crypto.sign
和 crypto.verify
Bun 現在支援 node:crypto
模組中的 sign
和 verify
,可用於使用私鑰簽署和驗證資料。
import { sign, generateKeyPairSync } from "node:crypto";
const { privateKey } = generateKeyPairSync("ed25519");
const signature = sign(undefined, Buffer.from("foo"), privateKey);
console.log(signature); // Buffer(64) [ ... ]
感謝 @cirospaciari 實作此功能!
bun install
從 package-lock.json
v2 遷移
Bun 現在能夠遷移 lockfileVersion
為 2
的 package-lock.json
檔案。如果您要從 npm 遷移到 Bun,這會很有用。
❯ cat package-lock.json | jq .lockfileVersion
2
❯ bun install
bun install v1.0.15
[3.57ms] migrated lockfile from package-lock.json
+ svelte@4.0.0 (v4.2.8 available)
21 packages installed [265.00ms]
bun install
重複工作區錯誤修正
感謝 @dylan-conway,已修正有關重複工作區套件的錯誤。
console.log
的尾隨逗號
Bun 現在包含使用 console.log
印出的物件的尾隨逗號。這使得從控制台複製貼上輸出、進行搜尋和取代變得更容易,並與像 prettier
這樣的程式碼格式化工具的做法相符。
console.log({ a: 1, b: 2, c: "3" });
{
a: 1,
b: 2,
- c: "3"
+ c: "3",
}
感謝 @hustLer2k 實作此改進,並感謝 @ArnaudBarre 的建議!
已實作:console.timeLog
存在一個阻止 console.timeLog
運作的錯誤。感謝 @lqqyt2423,此問題已得到修正。
已修正:ReadableStream
的分離使用
存在一個當 ReadableStream
分離時會拋出 undefined is not an object
錯誤的錯誤,現在已修正此問題。
const { exited, stdout } = Bun.spawn(["echo", "hello"], {
stdout: "pipe",
});
await exited;
// Since the process has exited, the `stdout` ReadableStream is detached.
console.log(await Bun.readableStreamToText(stdout));
// Before: error: undefined is not an object
// After: "hello\n"
已修正:fs.opendir()
具有 path
屬性
以前,fs.opendir()
沒有 path
屬性,現在感謝 @samfundev,此問題已得到修正。
import { test, expect } from "bun:test";
import { opendir } from "fs/promises";
test("opendir() has `path` property", () => {
const result = await opendir(".");
expect(result).toHaveProperty("path", ".");
});
已修正:重複的 Content-Range
標頭
存在一個 Bun 會傳送重複 Content-Range
標頭的錯誤。
const file = Bun.file("video.mp4");
const start = 0;
const end = 1000;
const range = file.slice(start, end);
return new Response(range, {
status: 206,
headers: {
"Content-Range": `bytes ${start}-${end}/${file.size}`,
},
});
Bun 無法正確偵測到已設定 Content-Range
標頭,並會傳送重複的標頭。
content-range: bytes 0-1000/10000
- content-range: bytes 0-1000/*
感謝 @libersoft-org,此問題已得到修正。
已修正:各種轉譯器錯誤
tsconfig.json
中的連字號鍵
存在一個如果 tsconfig.json
包含包含連字號的鍵,解析將會失敗的錯誤。感謝 @DontBreakAlex,此問題已得到修正。
{
"key-with-hyphens": "value"
}
在 JSX 中擴展元素
存在一個將子元素擴展到父元素中會導致意外錯誤的錯誤。感謝 @rhyzx,此問題已得到修正。
輸入
const a = <h1>{...[123]}</h1>;
輸出
- error: Unexpected ...
+ var a = jsx_dev_runtime.jsxDEV("h1", {
+ children: [...[123]]
+ }, undefined, true, undefined, this);
已壓縮程式碼中的堆疊溢位
「堆疊溢位」不僅僅是一個網站。程式在堆疊中執行程式碼,如果堆疊使用過多記憶體,則會溢位。
Bun 的剖析器是一個遞迴下降剖析器,這表示它使用遞迴來剖析程式碼。這使得實作更簡單,但如果輸入原始碼二元運算式巢狀太深,則可能會導致堆疊溢位。此版本修正了該問題。
例如,如果您要撰寫一個包含如下內容的檔案
const chain =
`globalThis.a = {};` +
"\n" +
`globalThis.a + globalThis.a +`.repeat(1000000) +
`globalThis.a` +
"\n";
await Bun.write("stack-overflow.js", chain);
然後使用 bun stack-overflow.js
執行它,則會由於堆疊溢位而在 bun 的轉譯器中崩潰。
感謝 @dylan-conway,此問題現已修正。
當使用 Bun 的執行環境以 Prettier 格式化 TypeScript 檔案時,此錯誤會顯現出來。
TypeScript 建構函式中的 override
關鍵字
存在一個 TypeScript 建構函式中的 override
關鍵字會導致意外錯誤的錯誤。
class Foo {}
class Bar extends Foo {}
class Fizz {
constructor(readonly foo: Foo) {}
}
class Buzz extends Fizz {
constructor(override bar: Bar) {
super(foo);
}
}
new Buzz(new Bar());
- 10 | constructor(override foo: FooChild) {
- ^
- error: Expected ")" but found "foo"
- at example.ts:10:23
已修正:bun build --compile
中動態載入的 CommonJS 模組
當 require
的引數無法靜態分析時,bun build
會將其保持原樣。
const dynamic = (name) => require(name);
console.log(dynamic("some-package"));
如果您將其與 bun build --compile
一起使用並以這種方式載入 commonjs 檔案,則轉譯器將產生具有語法錯誤的程式碼。此問題已得到修正。
感謝 25 位貢獻者!
我們總是很高興歡迎新的貢獻者加入 Bun。在此版本中,有 12 位新的貢獻者做出了他們的首次貢獻。
- @adrienbrault 在 #7350 中做出了他們的首次貢獻
- @brianknight10 在 #7368 中做出了他們的首次貢獻
- @DontBreakAlex 在 #7316 中做出了他們的首次貢獻
- @james-elicx 在 #7277 中做出了他們的首次貢獻
- @joeyw 在 #7364 中做出了他們的首次貢獻
- @lqqyt2423 在 #7089 中做出了他們的首次貢獻
- @mimikun 在 #7378 中做出了他們的首次貢獻
- @NReilingh 在 #7372 中做出了他們的首次貢獻
- @rhyzx 在 #7294 中做出了他們的首次貢獻
- @RiskyMH 在 #7306 中做出了他們的首次貢獻
- @stav 在 #7327 中做出了他們的首次貢獻
- @SukkaW 在 #7348 中做出了他們的首次貢獻
- @yharaskrik 在 #7409 中做出了他們的首次貢獻
感謝 25 位讓此版本成為可能的貢獻者