我們很高興地宣布 Bun v0.7.0 版本,這是在 Node.js 相容性方面的一大躍進。
我們正在招募 C/C++ 和 Zig 工程師,一同打造 JavaScript 的未來! 加入我們的團隊 →
Bun 是一個極其快速的 JavaScript 執行環境、打包器、轉譯器和套件管理器 — 功能All-in-one。在過去幾個月中,我們發布了許多 Bun 的變更,這裡為您整理了重點回顧,以防您錯過。
v0.6.10
-fs.watch()
、bun install
錯誤修正、bun test
功能,以及改進的 CommonJS 支援v0.6.11
- 解決了v0.6.10
的發布版本問題。v0.6.12
-Error.stack
中的 Sourcemap 支援、Bun.file().exists()
,以及 Node.js 錯誤修正。v0.6.13
- 實作了模擬Date
、更快的 base64 編碼,以及WebSocket
和node:tls
的修正。v0.6.14
-process.memoryUsage()
、process.cpuUsage()
、process.on('beforeExit', cb)
、process.on('exit', cb)
和崩潰修正
安裝 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
Vite 支援
此支援仍處於實驗階段且未經最佳化。 即使使用 Bun 執行,Vite 也不會使用 Bun 的打包器、模組解析器或轉譯器。
隨著近期在 Node.js API 相容性方面取得的進展,現在 Bun 可以執行 vite dev
了,感謝 @paperclover!這是 Bun 最受歡迎的問題之一。
若要使用 Vite 的其中一個入門專案嘗試此功能,請使用 bunx
bunx create-vite myapp
cd myapp
bun install
然後啟動開發伺服器。
bun --bun vite dev
為什麼使用 --bun
? --bun
標記會告知 Bun 覆寫 vite
CLI 中的 #! /usr/bin/env node
Shebang,並使用 Bun 而非 Node.js 執行檔案。在未來的版本中,這將會是預設行為。

這是使用 Bun 的 API 在伺服器端開發前端程式碼,以建構前端應用程式的好方法。
注意:如果您在沒有 -b
或 --bun
的情況下執行 bun vite dev
,它仍然會在 Node.js 中執行,因為 vite
的 CLI 在頂部指定了 #!/usr/bin/env node
,這會告知 Bun(以及您電腦上的其他軟體)在 Node.js 中執行它。
使用 Worker
實現並行
Bun 現在支援 Worker
,讓您可以在獨立的執行緒中執行另一個 JavaScript 實例。在 Bun 中,worker 支援 ES Modules、CommonJS、TypeScript、JSX 以及 Bun 的其他功能,無需額外設定。
如同在瀏覽器中,Worker
是一個全域類別。若要從主執行緒建立 worker
const worker = new Worker("./worker.ts");
worker.addEventListener("message", (event: MessageEvent) => {
console.log("Message from worker:", event.data);
});
worker.postMessage("Hello from main thread!");
在 worker 執行緒中
addEventListener("message", (event: MessageEvent) => {
console.log("Message from main thread:", event.data);
postMessage("Hello from worker thread!");
});
此版本不包含對 node:worker_threads
模組的支援,但這解除了我們在 Bun 中實作它的必要障礙。
以下全域變數已新增至 Bun
postMessage
addEventListener
removeEventListener
onmessage
(getter/setter)
請參閱 文件 > API > Workers 以瞭解更多關於在 Bun 中使用 Worker
的資訊。
搭配 Bun 使用 comlink
熱門的 comlink
套件可在 Bun 中運作,無需任何變更。這個函式庫讓在主執行緒和 worker 執行緒之間共享函式和狀態變得更容易。
Comlink 使用範例
structuredClone()
支援
如同在瀏覽器中,postMessage
使用結構化複製演算法序列化訊息。Bun 現在透過 Web 標準的structuredClone()
函式公開此功能,該函式提供了一種深度複製物件的機制。它類似於 JSON.parse(JSON.stringify(obj))
,但支援更多類型。
const obj = { a: 1, b: 2 };
const clone = structuredClone(obj);
AsyncLocalStorage
支援
Bun 現在實作了來自 node:async_hooks
模組的 AsyncLocalStorage
。這提供了一種機制,用於透過非同步程式碼鏈傳遞上下文資料。這是朝向支援 Next.js 和其他依賴此模組的框架邁出的一大步。
import { AsyncLocalStorage } from "node:async_hooks";
const requestId = new AsyncLocalStorage();
let lastId = 0;
Bun.serve({
fetch(request) {
lastId++;
// Run the callback with 'requestId' set. async_hooks will preserve
// this value through any chain of asynchronous code.
return requestId.run(lastId, async () => {
console.log(`Request ID: ${requestId.getStore()}`);
await Bun.sleep(500);
// Even if new requests mutate 'lastId', 'requestId' is still preserved.
return new Response(`Request ID: ${requestId.getStore()}`);
});
},
});
使用 bun --smol
減少記憶體用量
bun --smol
是一個新的 CLI 標記,它將 JavaScriptCore 堆積大小配置為更小且成長更慢,但會犧牲執行時期效能。這對於在記憶體受限的環境中執行 Bun 非常有用。
下一個版本的 bun 將加入 「--smol」 標記,這會在稍微犧牲效能的情況下減少記憶體用量 pic.twitter.com/9cw9vylrur
— Jarred Sumner (@jarredsumner) 2023年7月17日
為了避免手動設定標記,您可以將其設定為 bunfig.toml
中的預設值。
smol = true
[test]
# set it only for tests, if you want
smol = true
--bail
in bun test
使用 --bail=1
執行 bun test
將在第一次測試失敗後退出。
bun test --bail 1
bun test v0.7.0
✓ test1 [0.02ms]
test2.test.js:
1 | import {test, expect} from 'bun:test';
2 |
3 | test('test2', () => {
4 | expect(2).toEqual(3);
^
error: expect(received).toEqual(expected)
Expected: 3
Received: 2
at /Users/colinmcd94/Documents/bun/fun/test/test2.test.js:13:8
✗ test2 [0.18ms]
Ran 2 tests across 2 files. [8.00ms]
Bailed out after 1 failures
這對於 CI 環境或當您想要在第一次失敗後停止執行測試時非常有用。感謝 @TiranexDev 完成此項改進!
Bun.readableStreamToFormData()
Bun 現在公開了一個輔助函式,用於將 ReadableStream
轉換為 FormData
。
它支援 multipart form data。
import { readableStreamToFormData } from "bun";
// without dashes
const boundary = "WebKitFormBoundary" + Math.random().toString(16).slice(2);
const myStream = getStreamFromSomewhere(); // ...
const formData = await Bun.readableStreamToFormData(stream, boundary);
formData.get("foo"); // "bar"
它也支援 URL 編碼的 form data
import { readableStreamToFormData } from "bun";
const stream = new Response("hello=123").body;
const formData = await readableStreamToFormData(stream);
formData.get("hello"); // "123"
我們新增此功能是為了協助修正一個錯誤,該錯誤會導致當 body 是來自 JavaScript 的 ReadableStream
時,request.formData()
和 response.formData()
掛起。
serialize
和 deserialize
in bun:jsc
bun:jsc
模組現在導出 serialize()
和 deserialize()
,它們將 JavaScript 物件轉換為 ArrayBuffer
並返回。
import { serialize, deserialize } from "bun:jsc";
import { deepEquals } from "bun";
const obj = { a: 1, b: 2 };
const buffer = serialize(obj);
const clone = deserialize(buffer);
if (deepEquals(obj, clone)) {
console.log("They are equal!");
}
node:v8
模組導出相同的函式,以便與現有的函式庫相容,這些函式庫在進程之間序列化/反序列化資料。
WebSocket
改進
您現在可以手動發送和接收 WebSocket ping
和 pong
框架。
const ws = new WebSocket("wss://echo.websocket.org");
ws.addEventListener("pong", () => {
console.log("Received pong");
});
ws.ping();
這適用於 ServerWebSocket
和 WebSocket
。
nodebuffer
現在是預設的 binaryType
預設情況下,Bun 中 WebSocket
和 ServerWebSocket
的 binaryType
現在是 nodebuffer
。這表示 WebSocket
中的二進位資料框架將會是 Buffer
實例,而不是 ArrayBuffer
(如同之前)。這是為了符合 ws
套件的行為。
const ws = new WebSocket("wss://echo.websocket.org");
ws.addEventListener("message", (event: MessageEvent) => {
console.log(event.data instanceof Buffer); // true
});
若要將其改回 ArrayBuffer
,請設定 ws.binaryType = "arraybuffer"
。
const ws = new WebSocket("wss://echo.websocket.org");
ws.binaryType = "arraybuffer";
ws.addEventListener("message", (event: MessageEvent) => {
event.data; // ArrayBuffer
});
(請注意,在瀏覽器中,預設值為 Blob
。)
關閉原因現在能正確傳播
修正了一個錯誤,該錯誤會導致 WebSocket
無法正確傳播來自第三方伺服器的關閉原因。感謝 @Electroid 完成這些改進!
Node.js 相容性改進
此版本針對 Node.js 相容性新增了幾項額外的改進。
node:tls
中 TLSSocket
的改進
以下方法已在 TLSSocket
類別中實作。感謝 @cirospaciari 在 #3596
中完成這些改進。
.getPeerFinished()
.getFinished()
.getProtocol()
.getSharedSigalgs()
.isSessionReused()
.exportKeyingMaterial()
.setMaxSendFragment()
.getPeerCertificate()
.getCertificate()
.enableTrace()
.disableRenegotiation()
.getCipher()
.getEphemeralKeyInfo()
.getTLSTicket()
.getSession()
.setSession()
base64url
雜湊不再是 data:
urls
先前,Bun 會將 data:base64,
前置到 crypto.createHash("sha256").digest("base64url")
的輸出。這不是 Node.js 的行為,並且導致了函式庫的問題,這些函式庫預期輸出與 Node.js 的字串相同。
crypto.createHash("sha256").update("abc").digest("base64url");
// Node.js: "ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0"
// Bun v0.7.0: "ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0"
// <= Bun v0.6.14: "data:base64,ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0="
使用 process.stdout.columns
和 process.stdout.rows
取得終端機尺寸
process.stdout
和 process.stderr
現在支援讀取終端機視窗的尺寸。
const { columns, rows } = process.stdout;
const [columns, rows] = process.stdout.getWindowSize();
const { columns, rows } = process.stderr;
const [columns, rows] = process.stderr.getWindowSize();
如果您想要一次取得兩個尺寸,也可以使用 process.stdout.getWindowSize()
。
錯誤修正
#3656
已修正 await new Response(latin1String).arrayBuffer()
和 await Response.json(obj).json()
中的記憶體洩漏。
修正後
cpu: Apple M1 Max
runtime: bun 0.7.0 (arm64-darwin)
benchmark time (avg) (min … max) p75 p99 p995
--------------------------------------------------------------------------------------------------- -----------------------------
new Response().arrayBuffer() (new string each call, latin1) 12.9 µs/iter (625 ns … 4.18 ms) 1 µs 567.17 µs 711.79 µs
new Response().arrayBuffer() (new string each call, utf16) 12.85 µs/iter (1.67 µs … 1.56 ms) 2.17 µs 462.75 µs 621.13 µs
new Response().arrayBuffer() (existing string, latin1) 6.53 µs/iter (6.21 µs … 7.07 µs) 6.64 µs 7.07 µs 7.07 µs
Peak memory usage: 49 MB
修正前
cpu: Apple M1 Max
runtime: bun 0.7.0 (arm64-darwin)
benchmark time (avg) (min … max) p75 p99 p995
--------------------------------------------------------------------------------------------------- -----------------------------
new Response().arrayBuffer() (new string each call, latin1) 13.51 µs/iter (541 ns … 3.2 ms) 1.92 µs 553.42 µs 709.92 µs
new Response().arrayBuffer() (new string each call, utf16) 13.07 µs/iter (1.71 µs … 3.43 ms) 2.13 µs 451.21 µs 651.67 µs
new Response().arrayBuffer() (existing string, latin1) 6.25 µs/iter (5.79 µs … 6.81 µs) 6.4 µs 6.81 µs 6.81 µs
Peak memory usage: 292 MB
#3659
已修正一個模組解析錯誤,該錯誤導致 graphql
套件匯入相同模組的 CommonJS 和 ESM 版本。此問題已透過將 package.json main 欄位順序調整為更接近 Node.js 的方式來修正。
error: Cannot use GraphQLScalarType "String" from another module or realm.
Ensure that there is only one instance of "graphql" in the node_modules
directory. If different versions of "graphql" are the dependencies of other
relied on modules, use "resolutions" to ensure only one version is installed.
https://yarn.dev.org.tw/en/docs/selective-version-resolutions
Duplicate "graphql" modules cannot be used at the same time since different
versions may have different capabilities and behavior. The data from one
version used in the function from another could produce confusing and
spurious results.
#3663
已修正 bun:test 生命周期鉤子中的一個錯誤,該錯誤導致當範圍中未定義任何測試時,beforeAll
和 afterAll
無法執行。此問題已修正。
#3670
已修正一個 .env 指向目錄時導致 Bun 崩潰的錯誤。此問題已修正。
#3682
已修正一個與帶有展開運算子的三元運算符相關的 TypeScript 解析器錯誤
更新日誌
#3253 | feat(bun/test):由 @TiranexDev 實作 「bail」 選項,用於 「bun test」 |
#3608 | 由 @paperclover 改進我們的內部 typedefs |
#3257 | 由 @Electroid 改進 WebSocket 和 ServerWebSocket |
#3630 | $npm_lifecycle_event 應具有上次呼叫的值,由 @TiranexDev 完成 |
#3631 | 更新 process 的 docs/types,由 @colinhacks 完成 |
#3637 | structured clone,由 @dylan-conway 完成 |
#3650 | docs:在 typescript.md 中新增遺失的一行,由 @capaj 完成 |
#3643 | 修正 #3641,由 @Jarred-Sumner 完成 |
#3614 | 在建構子中支援 napi_wrap ,由 @Jarred-Sumner 完成 |
#3645 | 實作 Workers,由 @Jarred-Sumner 完成 |
#3654 | 修正 crypto 的 base64url 編碼,由 @Jarred-Sumner 完成 |
#3655 | 針對物件,structuredClone / postMessage 的 deserialize 速度提升 20%,由 @Jarred-Sumner 完成 |
#3626 | workaround readable-stream 相容性,由 @alexlamsl 完成 |
#3662 | [install] 優雅地處理重複的工作區宣告,由 @alexlamsl 完成 |
#3664 | package json main 欄位擴展順序,由 @dylan-conway 完成 |
#3596 | [tls] 一般相容性改進,由 @cirospaciari 完成 |
#3667 | zig 升級,由 @dylan-conway 完成 |
#3671 | fix(tls) 修補 checkServerIdentity,由 @cirospaciari 完成 |
#3672 | feature(constants) 新增 constants/node:constants 模組和測試 (prisma),使用 prima 5.0.0 + 針對 postgres 使用相同連線,新增 prisma mssql(目前已停用),由 @cirospaciari 完成 |
#3678 | 由 @Jarred-Sumner 針對找不到 workspace 依賴項提供更佳的錯誤訊息 |
#3683 | 將 constants 模組移至 cpp,由 @cirospaciari 完成 |
#3687 | fix #3682,由 @dylan-conway 完成 |
#3680 | 修正 createDecipheriv,由 @cirospaciari 完成 |
#3688 | 更新根憑證並新增 tls.rootCertificates,由 @cirospaciari 完成 |
#3089 | 實作 AsyncLocalStorage ,由 @paperclover 完成 |
#3693 | 修正瀏覽器綁定的 string_decoder,由 @paperclover 完成 |
#3694 | 修正 vite,由 @paperclover 完成 |
#3698 | 修正 #3670,由 @Jarred-Sumner 完成 |
#3697 | 支援 response.formData() & request.formData 中的 streams,引入 Bun.readableStreamToFormData(),由 @Jarred-Sumner 完成 |
#3706 | 改進 FFI 數字類型的類型,由 @colinhacks 完成 |
#3707 | 修正 Worker 的啟動延遲,由 @cirospaciari 完成 |
#3709 | 將 _preload_modules 設定為空陣列,由 @dylan-conway 完成 |
#3708 | fix 3702,由 @dylan-conway 完成 |
#3692 | 將建構子引數傳遞給 TextDecoder,由 @Parzival-3141 完成 |
#3711 | 修正內建 generator $lazy ,由 @paperclover 完成 |
#3710 | 透過 workaround 修正目錄快取,由 @paperclover 完成 |
#3713 | 再次修正內建,由 @paperclover 完成 |
#3714 | 修正 process.exit 狀態碼處理,由 @paperclover 完成 |
#3715 | fix isFIFO ,由 @dylan-conway 完成 |
#3717 | 字串跳脫邊緣案例,由 @dylan-conway 完成 |