Bun v1.1.21 版本發布!此版本修正了 72 個錯誤(解決了 63 個 👍)。fetch() 解壓縮速度提升 30%,新增 --fetch-preconnect 標誌,改進了 Remix 支援,Bun 在 Linux 上縮小了 4 MB,捆綁套件時排除依賴項,許多捆綁器修復和 Node 相容性改進。
我們正在舊金山招聘系統工程師,以構建 JavaScript 的未來!
先前的版本
v1.1.20
&v1.1.19
修正了 54 個錯誤(解決了 248 個 👍)。JavaScript 在 Windows 上速度更快。Raspberry Pi 4 支援。.npmrc 中支援 _auth。bun install
保留 package.json 縮排。aws-cdk-lib
支援。修復了new Response(request)
和fs.readdir
中的記憶體洩漏問題。多項可靠性改進。v1.1.18
修正了 55 個錯誤(解決了 493 個 👍)。支援 npmrc。改進了常數折疊和枚舉內聯。改進了函數的console.log
輸出。修復了工作區中修補依賴項的問題。修復了bun install
在連結二進制檔案時的幾個錯誤。修復了dns.lookup
中的崩潰,並標準化了 DNS 錯誤以更好地匹配 Node。修復了Bun.escapeHTML
中的斷言失敗。升級了 JavaScriptCore。v1.1.0
Bundows。Windows 支援來了!
安裝 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
fetch()
解壓縮速度提升 30%
由於 libdeflate,在 Linux x64 上解壓縮使用 gzip 或 deflate 壓縮的 fetch()
響應正文速度提升了 30%。
在 Bun 的下一個版本中
— Jarred Sumner (@jarredsumner) July 27, 2024fetch()
解壓縮 gzip 數據速度提升 30%,感謝 libdeflate。 pic.twitter.com/obCjWo2fHv
我們還在 websocket 伺服器中啟用了 libdeflate,以加快解壓縮小型訊息的速度。
新增:--fetch-preconnect
提前預熱連線
我們新增了一個新的標誌 --fetch-preconnect=<url> <file>
,它會在執行任何程式碼之前啟動對指定 URL 的 HTTP 請求。
bun --fetch-preconnect='https://example.com' ./index.ts
對於許多生產服務來說,Bun 腳本執行的第一件事是使用 fetch
或 node:http
向伺服器發送 HTTP 請求。許多網路請求中最慢的部分是初始連線設定,這可能涉及 DNS 查找、TCP 連線建立和 TLS 協商。有時這需要 100 毫秒才能發送 HTTP 請求。
這項工作受網路限制。如果可以在執行任何程式碼之前啟動該連線,以便在其餘程式碼運行時,連線已經建立,那會怎麼樣?這就是 --fetch-preconnect
的作用。它很像 HTML 中的 <link rel="preconnect">
,但適用於伺服器端 JavaScript。
在此過程中,我們還新增了一個 JavaScript API 來執行相同的操作
fetch.preconnect(url: string): void;
這對於無伺服器環境和在 fetch
或 node:http
之上運行的資料庫非常有用。
bun --fetch-preconnect=https://example.com ./hey.mjs
[8.37ms] fetch(https://example.com)
❯ bun hey.mjs # Without preconnect
[51.92ms] fetch(https://example.com)
❯ node hey.mjs
fetch(https://example.com): 68.417ms
❯ cat hey.mjs
│ File: hey.mjs
1 │ if (globalThis.Bun) {
2 │ await Bun.sleep(1000);
3 │ } else {
4 │ await new Promise(resolve => setTimeout(resolve, 1000));
5 │ }
6 │
7 │ console.time("fetch(https://example.com)");
8 │ await fetch("https://example.com");
9 │ console.timeEnd("fetch(https://example.com)");
改進了 Remix 支援
我們修復了一個錯誤,即覆蓋像 Request
或 Response
這樣的全局變數可能會導致 node:http
出現問題。在內部,Bun 的 node:http
實現使用 Bun.serve()
,它期望使用者返回原生的 Response
物件。
Remix 和其他框架全局 polyfill Request
和 Response
,而 Bun 的 node:http
之前使用的是全局 Request
和 Response
物件。我們通過始終在 node:http
中使用原生的 Request
和 Response
物件來修復此問題。
我們還在 Bun 的 node-fetch
和 undici
的 polyfill 中修復了類似的問題。
如果您遇到以下錯誤,那麼現在已修復
// error: Expected a Response object, but received 'Response {
// [Symbol(Body internals)]: {
// body: ReadableStream {
// ...
我們還為 Remix 新增了一個整合測試,以便我們將來可以繼續確保相容性。
bun install
在 HTTP 500 錯誤時重試
在此版本中,bun install
現在將在網路錯誤且 HTTP 狀態碼 > 499 時重試。
我們已經看到來自使用者和我們自己的 CI 的報告,指出官方 npm 註冊表返回 HTTP 500 錯誤,這會導致 bun install
失敗。現在,bun install
將在這些錯誤時重試,這應該有助於補償 npm 註冊表的臨時問題(減少虛假的 CI 失敗)。
在 Linux 上縮小 4 MB
在此版本中,我們將 Bun 的 Linux x64 二進制檔案大小縮小了 4 MB,這使其比官方 Node.js v22.5.1 可執行檔小 23%。
二進制檔案大小 | 版本 |
---|---|
92 MB | Bun v1.1.21 |
96 MB | Bun v1.1.20 |
97 MB | Bun v1.1.19 |
97 MB | Bun v1.1.18 |
114 MB | Node.js v22.5.1 |
在 Linux 上速度提升 1 毫秒
我們還將 Bun 在 Linux 上的啟動時間縮短了 1 毫秒。
hyperfine "bun --reivison" "bun-1.1.20 --revision"
Benchmark 1: bun --revision
Time (mean ± σ): 1.4 ms ± 0.2 ms [User: 0.9 ms, System: 0.4 ms]
Range (min … max): 1.2 ms … 2.6 ms 1143 runs
Benchmark 2: bun-1.1.20 --revision
Time (mean ± σ): 2.3 ms ± 0.2 ms [User: 1.1 ms, System: 1.1 ms]
Range (min … max): 2.2 ms … 5.0 ms 1099 runs
這些大小和啟動時間的改進來自連結器標誌、編譯器標誌、連結時間優化和一些小的程式碼更改的組合。
使用 bun build --packages=external
捆綁套件時排除依賴項
您現在可以控制套件依賴項是否包含在您的捆綁包中。如果導入不是以 .
、..
或 /
開頭,則它被視為套件。
bun build ./index.ts --packages external
您也可以在 JavaScript API 中使用它
await Bun.build({
entrypoints: ["./index.ts"],
packages: "external",
});
這在捆綁函式庫時非常有用。它使您可以減少使用者必須下載的檔案數量,同時繼續支援對等或外部依賴項。
感謝 @zpix1 實作此功能!
改進了 bun build
中程式碼分割的雜湊
以前,Bun 會在程式碼分割期間為檔案生成「隔離」雜湊,以便可以並行完成。但是,這意味著如果導入的檔案發生更改,則擁有導入的檔案的雜湊將不會更改。
const other = await import('./second');
export const second = 1;
此問題已修復,並且通過切換到 base32 編碼,雜湊也變得更短,類似於 esbuild
的做法。
感謝 @paperclover 參與此項工作!
已修復:當檔案為 .mts
時,導入解析為 .mjs
我們修復了一個錯誤,即 .mjs
導入不會解析為 .mts
檔案。
import "./foo.mjs";
export const foo = 1;
感謝 @190n,此問題現已修復!
已修復:在 Windows 上使用 Bun.write
時崩潰
我們修復了 Windows 上 Bun.write()
中的一個錯誤,其中 Bun 在為不存在的檔案建立目錄後可能會崩潰。
import { write, file } from "bun";
const txt = file("/does/not/exist/example.txt");
await write(txt, "hello world");
已修復:setSystemTime
無法與數字一起使用
存在一個錯誤,即從 bun:test
模組使用 setSystemTime
無法與數字一起使用,而是需要 Date
物件。
import { test, expect, setSystemTime } from "bun:test";
test("setSystemTime", () => {
const future = Date.now() + 1000;
setSystemTime(future);
expect(Date.now()).toBe(future);
// Before: <test failed>
// After: <test passed>
});
感謝 @cirospaciari 修復此錯誤!
已修復:合併巢狀 TypeScript 命名空間時崩潰
Bun 中存在一個錯誤,即 TypeScript 命名空間可能會導致 Bun 崩潰。這是 Bun 轉譯器中的一個邊緣案例,其中它沒有正確處理函數與類別或命名空間合併時的情況。
namespace X {
export function Y(): void {}
export namespace Y {
export const Z = 1;
}
}
感謝 @paperclover 修復此錯誤!
感謝 @190n,此問題現已修復!
已修復:伺服器關閉後中止請求時崩潰
我們修復了 Bun.serve()
中的一個罕見崩潰,如果伺服器在請求完成發送正文之前關閉後手動中止 Request
,則可能會發生此崩潰。
感謝 @cirospaciari 修復此錯誤!
已修復:CryptoHasher.update()
中使用空值時崩潰
我們修復了 CryptoHasher.update()
中的一個錯誤,其中空值會導致崩潰。
import { CryptoHasher } from "bun";
const hasher = new CryptoHasher("sha1");
hasher.update(); // <crash>
感謝 @cirospaciari 修復此錯誤!
已修復:列印錯誤堆疊時崩潰
在 Bun 中列印堆疊追蹤時可能會發生崩潰。這是由於未正確檢查堆疊幀是來自 JavaScript 函數還是來自原生函數造成的。
感謝 @nektro 修復此錯誤!
已修復:將 expect.any()
與 expect.toThrow()
一起使用
expect.toThrow()
的預期值現在可以使用非對稱匹配器 expect.any()
。以下程式碼將按預期工作
test("toThrow asymmetric matcher", () => {
expect(() => {
throw new Error("error!");
}).toThrow(expect.any(Error)); // passes
});
感謝 @ippsav!
已修復 bun test 中 test.each
的傳回值導致崩潰的問題
bun test
中存在一個錯誤,其中 test.each
的傳回值可能使用空指針,如果該值在 JavaScript 中使用,則會導致崩潰。現在,test.each
將返回 undefined
。
console.log(test.each([1, 2])("test.each %d", () => {})); // Before: <crash>, After: undefined
感謝 @dylan-conway!
已修復:Windows 上的程式碼覆蓋率現在排除 node_modules
我們修復了 bun test --coverage
中的一個錯誤,其中程式碼覆蓋率報告將包含來自 Windows 上 node_modules
的檔案。這是由於僅檢查 /
作為路徑分隔符引起的,而在 Windows 上,路徑分隔符可能是 \
或 /
。
感謝 @dariushalipour 修復此錯誤!
Node.js 相容性改進
已修復:node:http
請求 'data' 回調中的靜默錯誤
已修復導致 node:http
客戶端請求的 data
回調中錯誤靜默的錯誤。
Previously, the following code would not error
const { request } = require("node:http");
const req = request("http://www.google.com", (res) => {
res.on("data", (chunk) => {
throw new Error("oopsie");
});
}).end();
Now, it correctly throws an error
1 | const { request } = require("node:http");
2 | const req = request("http://www.google.com", (res) => {
3 | res.on("data", (chunk) => {
4 | throw new Error("oopsie");
^
error: oopsie
at silent.js:4:15
at emit (node:events:180:48)
at addChunk (node:stream:2029:22)
at readableAddChunk (node:stream:1983:30)
at node:http:136:44
Bun v1.1.21 (macOS arm64)
已修復:Readable.fromWeb
在使用 fetch()
串流時過早停止
我們修復了一個錯誤,即當從 fetch()
傳遞 ReadableStream
時,Readable.fromWeb
在某些情況下會過早停止讀取,如果串流尚未完成下載。
import { Readable } from "node:stream";
const res = await fetch("https://bun.dev.org.tw");
const stream = Readable.fromWeb(res.body);
stream.on("data", (chunk) => {
console.log("Received", chunk.length);
});
新的
❯ bun chunk.js
Received 16384
[... more chunks ...]
Received 3883
先前
❯ bun-1.1.20 chunk.js # Before
此錯誤專門影響 fetch()
的 ReadableStream。
已修復:允許 path.basename()
中使用 undefined
擴展名
我們修復了 path.basename()
中的一個相容性錯誤,其中它不允許將 undefined
作為擴展名。
import path from "path";
path.basename("foo", undefined);
path.posix.basename("bar", undefined);
path.win32.basename("baz", undefined);
如果您遇到以下錯誤,那麼現在已修復
> 2 | path.posix.basename("bar", undefined);
^
TypeError: "ext" property must be of type string, got undefined
code: "ERR_INVALID_ARG_TYPE"
感謝 @190n!
已修復:在連線 socket 之前,node:dgram
中的 Unref
我們修復了 node:dgram
中的一個錯誤,如果在連線 socket 之前完成,則它不會正確地 unref UDP socket。
import dgram from "node:dgram";
const socket = dgram.createSocket("udp4");
socket.unref(); // <would not unref>
感謝 @190n 修復此錯誤!
已修復:napi_threadsafe_function
在完成後會保持進程存活
我們修復了 Node-API 中的一個回歸問題,即在 napi_threadsafe_function
完成後,它將繼續保持進程存活。感謝 @dylan-conway 修復此問題!
...
napi_threadsafe_function tsfn;
...
napi_release_threadsafe_function(tsfn, napi_tsfn_release);
// `tsfn` will allow the process to exit if all threads have released it.
...
已修復:process.exitCode
在呼叫 process.exit()
之前應為 undefined
在 Node.js 中,process.exitCode
在以下任一情況發生之前都是 undefined
- 手動設定
process.exitCode
- 呼叫
process.exit()
我們修復了 Bun 中的一個錯誤,其中 process.exitCode
會在呼叫 process.exit()
之前設定為 0
。
console.log(process.exitCode); // Before: 0, After: undefined
感謝 @nektro 修復此錯誤!
已修復:node:zlib
brotli 解壓縮時崩潰
當長時間同步解壓縮由許多區塊組成的 brotli 串流時,可能會發生崩潰。此問題已修復。崩潰是由於在解壓縮發生時未正確保持來自 JavaScript 的值處於活動狀態而引起的。
感謝 @dylan-conway 修復此錯誤!
捆綁器修復
稍小的捆綁包
在 Bun 的下一個版本中
— clo (@paperclover_dev) July 24, 2024
Bun 的捆綁器在消除死程式碼方面變得稍微更聰明了 pic.twitter.com/nUoNbVgM8J
已修復:使用外部屬性存取進行捆綁時,bun build
中崩潰
我們修復了 bun build
中的一個錯誤,即當模組在導入的外部模組上使用屬性存取時可能會發生崩潰。
感謝 @paperclover,此問題已修復!
已修復:在使用 bun build
時,require()
中的尾部斜線
我們修復了一個錯誤,即在使用 bun build
時,帶有尾部斜線的 require()
呼叫將無法工作。
為了與 Node.js 匹配,如果您嘗試 require process/
,它應該解析為 node_modules/process/...
。以前,Bun 會感到困惑並解析為內建的 node:process
模組。
var process2 = require("process/");
// Error: Cannot find module 'process/'
感謝 @paperclover,此問題現已修復!
已修復:使用繩索字串導入時崩潰
Bun 中存在一個錯誤,即 import()
上 with
選項中的非文字值會導致 Bun 崩潰。這是因為 Bun 的轉譯器未正確訪問 with
選項。
import("./foo", { with: "text" }); // would work
import("./foo", { with: "te" + "xt" }); // would crash
感謝 @paperclover,此問題現已修復!
已修復:類別提升錯誤
A bug causing the following error has been fixed
TypeError: The superclass is not a constructor.
當類別宣告具有副作用時,它不能被提升。我們修復了一個錯誤,即 Bun 的捆綁器會提升具有副作用的類別宣告。
async function hi() {
const { default: MyInherited } = await import('./other.js');
const myInstance = new MyInherited();
console.log(myInstance.greet())
}
hi();
const MyReassignedSuper = class MySuper {
greet() {
return 'Hello, world!';
}
};
class MyInherited extends MyReassignedSuper {};
export default MyInherited;
This produces the correct output now
- class MyInherited extends MyReassignedSuper {
- }
- var MyReassignedSuper, other_default;
- MyReassignedSuper = class MySuper {
- greet() {
- return "Hello, world!";
- }
+ var MyReassignedSuper = class MySuper {
+ greet() {
+ return "Hello, world!";
+ }
+ }, MyInherited, other_default;
+ MyInherited = class MyInherited extends MyReassignedSuper {
+ };
+ other_default = MyInherited;
// ...
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, {
get: all[name],
enumerable: true,
configurable: true,
set: (newValue) => all[name] = () => newValue
});
};
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
// other.js
var exports_other = {};
__export(exports_other, {
default: () => other_default
});
var MyReassignedSuper = class MySuper {
greet() {
return "Hello, world!";
}
}, MyInherited, other_default;
var init_other = __esm(() => {
MyInherited = class MyInherited extends MyReassignedSuper {
};
other_default = MyInherited;
});
// entry.js
async function hi() {
const { default: MyInherited2 } = await Promise.resolve().then(() => (init_other(), exports_other));
const myInstance = new MyInherited2;
console.log(myInstance.greet());
}
hi();
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, {
get: all[name],
enumerable: true,
configurable: true,
set: (newValue) => all[name] = () => newValue
});
};
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
// other.js
var exports_other = {};
__export(exports_other, {
default: () => other_default
});
class MyInherited extends MyReassignedSuper {
}
var MyReassignedSuper, other_default;
var init_other = __esm(() => {
MyReassignedSuper = class MySuper {
greet() {
return "Hello, world!";
}
};
other_default = MyInherited;
});
// entry.js
async function hi() {
const { default: MyInherited2 } = await Promise.resolve().then(() => (init_other(), exports_other));
const myInstance = new MyInherited2;
console.log(myInstance.greet());
}
hi();
內部:macOS 和 Windows 上的 LLVM 18
我們已將 macOS 和 Windows 上的 LLVM 從 16 升級到 18。這使我們可以在 macOS 上添加更多偵錯斷言,這有助於更早地捕獲某些錯誤。