Bun v1.1.22 版本在此!此版本修正了 79 個錯誤(解決了 93 個 👍)。Express 在 Bun 中現在快了 3 倍,ES 模組在 Windows 上載入更快,Bun.serve()
在 POST 請求中快了 10%,以及 bun build --compile
中的原始碼地圖。減少了 --hot
、Bun.serve() 和 imports 的記憶體使用量。Uint8Array.toBase64()
、Uint8Array.toHex()
,以及大量的 Node.js 相容性改進和錯誤修正。
我們正在舊金山招聘系統工程師,以建構 JavaScript 的未來!
安裝 Bun
curl -fsSL https://bun.dev.org.tw/install | bash
npm install -g bun
powershell -c "irm bun.sh/install.ps1|iex"
scoop install 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
Express 在 Bun 中現在快了 3 倍
在此版本中,我們對 Bun 的 node:http
實作進行了效能和相容性改進。這使得 express
請求吞吐量比 Bun v1.1.21 提高了 50%,這表示在 Bun 中執行相同程式碼比 Node.js 快了 3 倍。
ES 模組在 Windows 上載入速度最高快 4 倍
為了讓 TypeScript、JSX、ES 模組和 CommonJS 都能在 Bun 中正常運作,我們在執行時即時編譯每個檔案。這本身就帶有效能成本。
此版本為 Bundows 帶來了並行轉譯支援,這使得載入 ES 模組更快。
async function benchmark(name) {
console.time(name);
await import(name);
console.timeEnd(name);
}
await benchmark("lodash-es");
在此基準測試中,我們執行了上述程式碼,並測量了匯入熱門套件(如 lodash-es
)所需的時間。
執行階段 | 時間 (毫秒) |
---|---|
Bun v1.1.22 | 39 |
Bun v1.1.21 | 82 |
Node.js v22.4.1 | 186 |
此最佳化先前僅在 Linux 和 macOS 的 Bun 上支援,但現在也支援 Windows。
Bun.serve()
中 POST 請求的吞吐量提高 10%
如果您的程式碼不讀取傳入 Request
的主體,則效能比 Bun 的上一個版本提高了 10%。
在 Bun 的下一個版本中
— Bun (@bunjavascript) 2024 年 7 月 31 日
Bun.serve() 在忽略主體的 POST 請求中獲得高 10% 的 req/s。 pic.twitter.com/OxkIGwYaWn
減少記憶體使用量
bun --hot
使用更少的記憶體
在此版本中,當您使用 bun --hot
重新載入程式碼時,Bun 使用的記憶體減少了 2 倍。
在 Bun 的下一個版本中
— Jarred Sumner (@jarredsumner) 2024 年 8 月 1 日
bun --hot 在多次執行後使用更少的記憶體
左:Bun v1.1.22(新)
右:Bun v1.1.21(舊) pic.twitter.com/eDl5iqZsme
先前,我們並非總是發布舊版模組的原始碼。如果您的程式碼或相依性修改了 require.cache
(這是重新載入程式碼的常見模式),情況也是如此。
匯入被垃圾回收的模組使用更少的記憶體
我們修正了一個錯誤,其中匯入或請求被垃圾回收的模組會保留對該模組原始碼的引用。
當模組拋出錯誤時也會發生這種情況,這會保留對模組原始碼的引用。
在 Bun 的下一個版本中
— Jarred Sumner (@jarredsumner) 2024 年 8 月 1 日
請求 (require)'ing 或匯入 (import)'ing 拋出錯誤的大型模組使用更少的記憶體 pic.twitter.com/ruMqFNDzqM
記憶體減少
我們還修復了各種記憶體洩漏,包括在以下情況:
- 請求 CommonJS 模組
- 計算原始碼地圖中的行偏移
- 並行轉譯超過 64 個檔案
- 建立大量
setTimeout()
或setInterval()
計時器
更佳的堆疊追蹤
我們修正了 Bun 中 error.stack
追蹤的呈現方式中的錯誤。有時,呼叫站點的原始碼 URL 會是空的,這會導致堆疊追蹤與大多數工具預期接收到的略有不同。現在,Next.js 可以正確呈現堆疊追蹤。
單一檔案可執行檔中的原始碼地圖
bun build --compile
讓您產生單一檔案可執行檔,將您的原始碼、相依性和 Bun 捆綁到單一檔案中,您可以將其部署到生產環境,而無需其他相依性。
在此 Bun 版本中,單一檔案可執行檔現在已正確支援 --sourcemap
。這為您提供更佳的堆疊追蹤以進行偵錯。
bun build cli.ts --compile --sourcemap
之前
/tmp
❯ bun-1.1.21 build --compile --sourcemap errory.ts
[3ms] bundle 1 modules
[110ms] compile errory
/tmp
❯ ./errory
2 | // @bun
3 | // errory.ts
4 | throw new Error("hey " + n);
^
error: hey 42
at hey (/$bunfs/root/errory:4:9)
at /$bunfs/root/errory:6:4
Bun v1.1.21 (macOS arm64)
之後
❯ bun build --compile --sourcemap errory.ts
[1ms] bundle 1 modules
[101ms] compile errory
/tmp
❯ ./errory
1 | function hey(n: number) {
2 | throw new Error("hey " + n);
^
error: hey 42
at hey (errory.ts:2:9)
at errory.ts:4:1
Bun v1.1.22-canary.104+c527058f1 (macOS arm64)
為了減少原始碼地圖的記憶體和檔案大小成本,我們使用 zstd
壓縮輸入原始碼,並序列化為自訂二進位格式。
Node.js 相容性
util.getSystemErrorName()
Bun 現在支援 node:util
模組中的 util.getSystemErrorName()
函數。這可讓您傳回錯誤物件的錯誤碼名稱。
import { readFileSync } from "node:fs";
import { getSystemErrorName } from "node:util";
try {
readFileSync("/does/not/exist");
} catch (error) {
console.log(getSystemErrorName(error)); // "ENOENT"
}
感謝 @nektro 實作此功能!
util.aborted()
Bun 現在支援 node:util
模組中的 util.aborted()
函數。這可讓您監聽 AbortSignal
並接收在訊號中止時解析的 Promise。
import { aborted } from "node:util";
const controller = new AbortController();
const promise = aborted(controller.signal);
promise.then(() => {
console.log("Aborted!");
});
events.getEventListeners()
Bun 現在也支援 node:events
模組中 EventTarget
物件的 events.getEventListeners()
函數。這可讓您取得給定發射器上給定事件名稱的所有監聽器。
import { getEventListeners } from "node:events";
const emitter = new EventTarget();
emitter.addEventListener("foo", function foo() {});
console.log(getEventListeners(emitter, "foo"));
// [ [Function: foo] ]
先前,這僅支援 node:events
模組中的 EventEmitter
物件。
NODE_EXTRA_CA_CERTS
Bun 現在支援 NODE_EXTRA_CA_CERTS
環境變數,這可讓您指定一個包含一個或多個 CA 憑證的檔案,以便在驗證 TLS 憑證時使用。這適用於執行階段、bun install
以及 Bun 中所有發出 HTTPS 請求的其他部分。
NODE_EXTRA_CA_CERTS=ca.pem bun install
NODE_EXTRA_CA_CERTS=another.pem bun run script.ts
已修正:在 fs.promises.writeFile()
中支援非同步迭代器
Node.js 在 fs.promises.writeFile()
中具有未記載的非同步迭代器支援。各種套件都依賴此支援,我們決定在 Bun 中支援它。
import { writeFile } from "node:fs/promises";
const iterator = async function* () {
yield "Hello";
yield "World";
};
await writeFile("hello.txt", iterator);
已修正:如果 process.on("exit")
拋出錯誤,Bun 現在會以 1
結束
我們修正了一個錯誤,其中如果 exit
或 beforeExit
事件監聽器拋出錯誤,Bun 將不會傳播正確的結束代碼。
process.on("exit", () => {
throw new Error("Oh no!");
});
感謝 @nektro 修正了此問題!
已修正:Worker
建構函式會誤解 eval
屬性
存在一個錯誤,其中 Worker
建構函式會誤解明確定義的 eval
屬性。這是 Bun v1.1.13 中引入的迴歸錯誤,現已修正。
const worker = new Worker("console.log('hello!')", { eval: false });
// Before: hello!
// After: BuildMessage: ModuleNotFound
感謝 @billywhizz 修正了此錯誤!
已修正:os.freemem()
現在可在 macOS 上運作
此功能先前已在 Linux 和 Windows 上實作,因此此 API 現在可在所有平台上運作。
感謝 @nektro 修正了此問題!
Web API
Uint8Array.toBase64()
Bun 現在支援 Uint8Array
上的 base64 編碼和解碼方法。這是實作於 WebKit 中的,WebKit 遵循 TC39 stage 3 提案以新增這些功能。
Uint8Array.prototype.toBase64()
將Uint8Array
轉換為 base64 字串Uint8Array.prototype.fromBase64()
將 base64 字串轉換為Uint8Array
new Uint8Array([1, 2, 3, 4, 5]).toBase64(); // "AQIDBA=="
Unit8Array.fromBase64("AQIDBA=="); // [1, 2, 3, 4, 5]
這些是 Web 標準替代方案,可取代 Node.js 中普遍存在的 Buffer.prototype.toString("base64")
和 Buffer.from(string, "base64")
模式。
Uint8Array.toHex()
也新增了這些方法,用於在 Uint8Array
與十六進位字串之間進行轉換。
Uint8Array.prototype.toHex()
將Uint8Array
轉換為十六進位字串Uint8Array.prototype.fromHex()
將十六進位字串轉換為Uint8Array
new Uint8Array([1, 2, 3, 4, 5]).toHex(); // "0102030405"
Unit8Array.fromHex("0102030405"); // [1, 2, 3, 4, 5]
感謝 @dcrousso 和 @constellation 在 WebKit 中實作這些功能!
bun build
將 require.main === module
轉換為 import.meta.main
先前,使用 require.main === module
會將模組標記為 CommonJS(因為它使用 module
)。現在,Bun 會將其重寫為 import.meta.main
,這表示您可以將此模式與 import 語句一起使用。
import * as fs from "fs";
if (typeof require !== "undefined" && require.main === module) {
console.log("main!", fs);
}
1 | import "fs";
^
error: Cannot use import statement with CommonJS-only features
at /index.js:1:8
note: Try require("fs") instead
note: This file is CommonJS because 'module' was used
這也修正了在使用 CommonJS 模組和 bun build --compile
的單一檔案可執行檔中對 require.main === module
的支援。
感謝 @paperclover 實作這些功能!
--ignore-dce-annotations
某些 JavaScript 工具支援特殊註解,這些註解可能會在無用程式碼消除期間產生影響。例如,@__PURE__
註解會告知捆綁器函數呼叫是純函數(無論它是否真的是),並且如果未使用該呼叫,則可以將其移除。
let button = /* @__PURE__ */ React.createElement(Button, null);
捆綁或執行上述程式碼將產生一個空檔案,因為未使用 button
變數。
有時,程式庫可能包含不正確的註解,這可能會導致 Bun 移除所需的效果。為了解決這些問題,您可以在執行 bun build
時使用 --ignore-dce-annotations
標誌來忽略所有註解。僅當無用程式碼消除破壞捆綁時才應使用此選項,並且應優先修正註解,而不是保持此標誌開啟。
感謝 @paperclover 實作此功能!
已修正:捆綁中對 module.exports
的賦值
在捆綁 CommonJS 模組時,Bun 會嘗試在可能的情況下將 module.exports
轉換為 exports
。這有助於最小化,但對 module.exports
或 exports
的賦值都必須撤銷最佳化。對於在賦值之前以文字形式出現的 module.exports
實例(這對於函數很重要),這並未發生。
function main() {
console.log(module.exports);
}
module.exports = 123;
main();
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
// input.ts
var require_input = __commonJS((exports, module) => {
function main() {
- console.log(exports);
+ console.log(module.exports);
}
module.exports = 123;
main();
});
export default require_input();
感謝 @paperclover 修正了此問題!
已修正:最小化 await import("react-dom/server")
已修正當在動態匯入 react-dom
的套件上使用 --minify-identifier
時導致以下錯誤的錯誤
SyntaxError: Cannot declare an imported binding name twice
對於某些套件(如 React),Bun 會套用額外的最佳化以將 CommonJS 轉換為 ESM。在此轉換中,產生的 import 語句具有錯誤的範圍分配,導致最小化器將兩個 import 語句使用相同的最小化變數名稱。
已修正錯誤
我們花費大量時間修正 Bun 中的錯誤。這是因為我們的首要任務是在生產環境中支援 Bun。
我們在 7 月修正了 180 個錯誤 pic.twitter.com/KwXyZy9sTG
— Bun (@bunjavascript) 2024 年 8 月 2 日
如果您遇到我們尚未修正的錯誤,請在 GitHub 上提交問題或為現有問題投票,以便我們可以優先處理它。如果您能夠提供最小的可重現範例,則會有所幫助。
Bun.serve()
中未捕獲錯誤時遺失預覽
當您將 development: true
傳遞給 Bun.serve()
時,我們會啟用內建錯誤處理常式,該處理常式會在處理常式中拋出未捕獲的例外時顯示錯誤預覽。
我們修正了一個錯誤,其中如果 Bun.serve()
中拋出未捕獲的例外,則不會顯示錯誤預覽。這是 Bun v1.1.9 中引入的迴歸錯誤,現已修正。
TextDecoder
無法正確解碼 192 或 193
我們修正了一個錯誤,其中 TextDecoder
無法正確解碼以 192
或 193
開頭的 UTF-8 序列。
const decoder = new TextDecoder();
const bytes = new Uint8Array([192, 191]);
console.log(decoder.decode(bytes));
// Before: "?"
// After: "\uFFFD\uFFFD"
帶有加法運算子的非 ASCII 範本字串
我們修正了一個轉譯器錯誤,其中在某些情況下,帶有加法運算子和非 ASCII 輸入的範本字串無法正確轉譯。這是 Bun v1.1.17 中引入的迴歸錯誤。
console.log(`${123}➖` + "123456 456");
// Before: 123➖
// After: 123➖123456 456
感謝 @paperclover 修正了此錯誤!
Bun.serve()
可靠性改進
我們對 Bun.serve()
進行了多項可靠性改進。這包括
- 當 HTTP 請求失敗或中止時,不再建立不必要的
DOMException
物件 - 修正了透過非同步迭代器取用
ReadableStream
時拋出錯誤可能會導致拋出無法捕獲的全域錯誤的錯誤 - 不必要的突然 TLS 關閉導致用戶端在某些情況下無法接收 WebSocket 關閉幀
- 在某些情況下,提供
Bun.file()
會從回應主體中省略尾隨換行符 - 修正了在仍有開啟的 HTTP 請求時突然停止 Bun.serve() 伺服器時可能發生的崩潰
WebSocket 伺服器在關閉後發布
修正了一個錯誤,其中在已關閉的 ServerWebSocket
上呼叫 .publish()
會錯誤地嘗試發布訊息,而不是傳回 0
。在極少數情況下,這可能會導致崩潰。
WebSocket 用戶端接收到偽造的 1006 關閉代碼
我們修正了 WebSocket
用戶端中的一個錯誤,其中即使在向伺服器傳送具有不同代碼的關閉幀後,它也會收到偽造的 1006
關閉代碼。這是因為 Bun 正在執行快速關閉,這表示關閉幀有時未正確傳送。
感謝 @cirospaciari 修正了此錯誤!
傳送 Bun.file()
作為回應時遺失 Date
標頭
我們修正了一個錯誤,其中在 Bun.serve()
中將 File
作為回應傳送時,未傳送 Date
標頭。這是因為 Bun 使用 sendfile()
系統呼叫來傳送檔案,並且該程式碼路徑未設定 Date
標頭。
const server = Bun.serve({
async fetch(req) {
const file = Bun.file("hello.txt");
return new Response(file);
},
});
const response = await fetch(server.url);
console.log(response.headers.get("Date"));
// Before: undefined
// After: "Wed, 06 Aug 2024 19:46:05 GMT"
感謝 @cirospaciari 修正了此錯誤!
複製的 File
會使用錯誤的檔案名稱
存在一個錯誤,其中從另一個檔案複製 File
,同時定義新名稱,會使用錯誤的名稱。現已修正此問題。
const original = Bun.file("original.txt");
const clone = new File([original], "clone.txt");
console.log(clone.name);
// Before: "original.txt"
// After: "clone.txt"
在 Windows 上,當主目錄中有空格時,bun upgrade
會失敗
我們修正了一個錯誤,其中如果您的主目錄包含空格,bun upgrade
將在 Windows 上失敗。
bun upgrade
Bun v1.1.22 is out! You're on v1.1.21
Expand-Archive : A positional parameter cannot be found that accepts argument 'PC\AppData\Local\Temp\1.1.22'.
At line:1 char:47
+ ... lyContinue';Expand-Archive -Path bun.zip C:\Users\My PC\AppDat ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Expand-Archive], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Expand-Archive
error: Failed to verify Bun (code: FileNotFound))
如果您遇到以下錯誤,則現已修正,但您必須再次執行 PowerShell 安裝程式才能接收修正後的組建
powershell -c "irm bun.sh/install.ps1 | iex"
感謝 @paperclover 修正了此問題!
UDP socket 在 macOS 13 上掛起
Bun 使用未記載的 sendmsg_x()
系統呼叫作為 macOS 上的快速路徑,以便一次傳送多個 UDP 封包,類似於 Linux 上的 sendmmsg()
系統呼叫。我們對 API 的使用在 macOS 13 上造成問題,這會導致 UDP 封包無法傳送。現已修正此問題。