Bun

Bun v0.6.10


Ashcon Partovi · 2023 年 6 月 26 日

我們正在招募 C/C++ 和 Zig 工程師,一同打造 JavaScript 的未來! 加入我們的團隊 →

我們最近發布了許多 Bun 的變更,這裡為您整理摘要,以防您錯過任何資訊

  • v0.6.0 - 推出 bun build,Bun 的全新 JavaScript 打包器。
  • v0.6.2 - 效能提升:JSON.parse 速度提升 20%,Proxyarguments 速度提升高達 2 倍。
  • v0.6.3 - 實作 node:vm,並對 node:httpnode:tls 進行了許多修正。
  • v0.6.4 - 實作 require.cacheprocess.env.TZ,以及 bun test 速度提升 80%。
  • v0.6.5 - 原生支援 CommonJS 模組 (先前,Bun 會將 CJS 轉譯為 ESM),
  • v0.6.6 - bun test 改進,包括 Github Actions 支援、test.only()test.if()describe.skip(),以及 15 個以上的 expect() 匹配器;也支援使用 fetch() 串流檔案上傳。
  • v0.6.7 - Node.js 相容性改進,以解除對 Discord.js、Prisma 和 Puppeteer 的封鎖
  • v0.6.8 - 推出 Bun.passwordbun test 中的模擬功能,以及 toMatchObject()
  • v0.6.9 - 減少記憶體用量並支援非 ASCII 檔案名稱

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

改進的 CommonJS 支援

現在在 Bun 中載入 npm 套件更加可靠。這是因為我們(再次)重寫了 CommonJS 模組載入。我們修正了許多與載入 CommonJS 模組相關的崩潰問題,並改進了 CommonJS 模組載入器,使其更相容於 Node.js。

webpack 現在可在 Bun 中運作

require.main 現在受到支援

require.main 是 Node.js CLI 常用的方法,用於檢查目前執行的腳本是否啟動了進程

if (require.main === module.id) {
  // do something
}

Bun 現在支援 require.main,這解鎖了多個 Node.js CLI。

我們也新增了 process.mainModule,它是 require.main 的別名。

console.log(require.main === process.mainModule); // true

__esModule 註解現在受到支援

Bun 現在具有執行階段支援,可支援 bundler 和 TypeScript 使用的 __esModule 註解,以指示當將 CommonJS 模組作為 ES 模組匯入時,default 匯出應指向的內容。

__esModule 是一種註解,用於保留轉換為 CommonJS 並隨後重新匯入回 ESM 的 ESM 的 export default <value>

import a from 'b' 應參照 module.exports 還是 module.exports.default

這個問題是讓 JavaScript 生態系統的 CommonJS -> ES 模組轉換變得困難的原因之一。

__esModule 是一種保留 default 匯入的方法,該匯入由 Webpack、Babel、esbuild 產生,並在 npm 上的許多套件中使用。Bun 現在具有對此的執行階段支援。

這表示以下的輸入 ES 模組

export default 42;

通常會由建置工具轉換為發布到 npm 的 CommonJS,如下所示

exports.default = 42;
exports.__esModule = true;

當重新匯入回 ESM 時,__esModule 註解會保留 default

import foo from "./foo.js";
console.log(foo); // 42

請注意,在 Node.js 中,default 匯出不會保留

import foo from "./foo.js";

// This is already the "default" export
// so why should you have to do .default to get the original value?
console.log(foo.default); // 42

為了繼續與 Node.js 相容,當沒有 __esModule 註解或封閉的 package.json 將 "type" 設定為 "module" 時,此行為會停用(表示這用於 Node.js 通常無論如何都不支援 ESM 的情況)。

WebSocket 客戶端編碼修正

我們修正了 Bun 的 WebSocket 客戶端實作中的一個編碼錯誤,該錯誤可能導致 Latin1 編碼的文字框架被截斷。

由於這些變更,Bun 中 puppeteer 的支援已獲得改進。

import puppeteer from "puppeteer";

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("https://example.com/");
await page.click("a");
await browser.close();

bun:test 的改進

現在使用 bun test 時,Bun 支援更多匹配器

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

test("new matchers", () => {
  expect(fetch("http://example.com")).resolves.toBeInstanceOf(Response);
  expect(fetch("invalid")).rejects.toBeInstanceOf(Error);
  expect([]).toBeArray();
  expect([1, 2, 3]).toBeArrayOfSize(3);
  expect("").toBeTypeOf("string");
});

spyOn() 的模擬支援也得到了改進。

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

test("spyOn()", () => {
  const service = {
    hasPermission: () => false,
  };

  let hasPermission = false;
  const spy = spyOn(service, "hasPermission").mockImplementation(
    () => hasPermission,
  );
  hasPermission = true;

  expect(service.hasPermission()).toBe(true);
  expect(spy).toHaveBeenCalled();
});

有了所有這些變更,將您現有的專案遷移到使用 bun test 應該比以往任何時候都更快更容易。以下是一個熱門 npm 套件(例如 zod)遷移到 bun test 時的情況。

.env 支援的錯誤修正

Bun 內建支援將 .env 檔案載入到 process.env 中,讓您無需在啟動時執行 require("dotenv").config(),並允許您在測試和 package.json "scripts" 中使用 .env 檔案。

此功能存在一些錯誤,@alexlamsl 已將其修正

Node.js 相容性改進

在 Bun 中監看檔案

fs.watch() 現在已實作!

import { watch } from "node:fs";

// file path
watch(".", (eventType, filename) => {
  console.log(`event type = ${eventType}`);
  if (filename) {
    console.log(`filename = ${filename}`);
  }
});
  • Bun.argv 現在與 process.argv 相符。
import { deepEquals } from "bun";

console.log(deepEquals(Bun.argv, process.argv)); // true
function getStack() {
  const cause = new Error();
  const prevPrepareStackTrace = Error.prepareStackTrace;
  Error.prepareStackTrace = (_, stack) => {
    console.log(stack[0].getFunctionName()); // "getStack"
    console.log(typeof stack[0].getLineNumber()); // "number"
    console.log(typeof stack[0].getColumnNumber()); // "number"
  };
  Error.captureStackTrace(cause);
  Error.prepareStackTrace = prevPrepareStackTrace;
}
import { openSync, writevSync } from "node:fs";

const fd = openSync("path/to/file");
const buffers = [new Uint8Array(3), new Uint8Array(3), new Uint8Array(3)];
console.log(writevSync(fd, buffers)); // 9
  • 現在支援 Module._nodeModulePaths。此函數會傳回 Bun 將在其中搜尋模組的路徑陣列。
import { _nodeModulePaths } from "node:module";

console.log(_nodeModulePaths(".")); // ["/path/to/node_modules", "/path/node_modules", "/node_modules"]
  • 現在支援 crypto.randomInt(),感謝 @lenovouser
  • util.deprecate 現在支援 "code" 引數
  • fs.createWriteStream 現在可以正確傳遞 flags,感謝 @Hanaasagi

bun install 的改進

我們也對 bun install 進行了一些新增功能。

--exact <package>

bun install --exact 提供與 npm install --save-exactyarn add --exact 相同的行為。它會將您正在安裝的套件版本固定為您指定的確切版本。

bun install --exact elysia@0.5.20

--frozen-lockfile

在此模式下,如果 bun.lock 檔案與 package.json 不同步,Bun 將會拋出錯誤。這對於 CI 環境很有用,您可以在 CI 環境中確保 bun.lock 是最新的。

bun install --frozen-lockfile

trustedDependencies

現在您可以設定允許執行生命週期腳本(例如 postinstall)的依賴項允許清單。預設情況下,這些腳本不會執行,以使 Bun 在預設情況下更安全。

package.json
{
  "trustedDependencies": [
    "puppeteer"
  ]
}

我們計劃在不久的將來新增一個預設清單,以便預設情況下,安裝依賴 postinstall 的套件能夠如預期般運作。

更多錯誤修正

  • 已修正使用 Bun.write 寫入檔案時可能發生的崩潰
  • node:tls 模組缺少一些 ES 匯出
  • bun:sqlite 套件缺少 Database 類別的 default 匯出
  • mkdirSync(path, {recursive: true}) 有時會在不應該的情況下傳回空字串
  • 例外狀況記錄中的檔案名稱有時會損毀,此問題已修正
  • 修正了檔案:URL 的模組解析中的錯誤,其中包含空格字元的 URL 會以 % 編碼而不是解碼
  • 修正了當 readdir 傳回大型目錄且某些元素為 UTF-16 時發生的崩潰
  • 修正了當 node:fs 函數中的布林值引數作為非布林值引數傳遞時可能發生的崩潰

更多新功能

  • 現在支援 HTMLRewriter 的 TextChunk 中的 lastInTextNode 屬性,它可以告訴您目前的文字區塊是否為最後一個。感謝 @bru02

更新日誌

#3310Bun.argv 變更為與 process.argv 相同,由 @Jarred-Sumner 執行
7f535a2修正了指派 module.require 時的問題,由 @Jarred-Sumner 執行
#3314改進了 Bun.serve 選項的驗證,由 @cirospaciari 執行
#3320修正了 CommonJS 匯入的錯誤,由 @Jarred-Sumner 執行
#3337修正了 const 宣告可能在使用前被 tree-shaked 的錯誤,由 @dylan-conway 執行
8ad9e57新增了 ucs2 編碼的遺失別名,由 @Jarred-Sumner 執行
b951c1f全面改進了記憶體用量,由 @Jarred-Sumner 執行
#3362改進了檔案沒有匯出時對 ESM 和 CommonJS 的偵測,由 @Jarred-Sumner 執行
#3316bun:test 實作了 toBeArraytoBeArrayOfSizetoBeTypeOf,由 @TiranexDev 執行
#3359實作了更多 V8 的堆疊追蹤 API,由 @kvakil 執行
#3363修正了 fs.utimesSync() 的溢位問題,由 @Jarred-Sumner 執行
83d7ec7修正了 node:crypto.digest().copy() 的錯誤,由 @Jarred-Sumner 執行
#3367toEqualtoStrictEqualtoHaveProperty 實作了非對稱匹配器支援,由 @dylan-conway 執行
#3360修正了經典模式中 JSX 的錯誤,由 @dylan-conway 執行
#3368改進了循環依賴的錯誤訊息,由 @Jarred-Sumner 執行
#3369修正了 .env 檔案的崩潰問題,由 @Jarred-Sumner 執行
#3304bun:test 中實作了更多 mock() 支援,由 @paperclover 執行
#3378修正了 CommonJS 檔案中 bun:test 的使用問題,由 @Jarred-Sumner 執行
#3347修正了 .env 檔案剖析的各種錯誤,由 @alexlamsl 執行
#3318expect() 實作了 resolvesrejects,由 @Electroid 執行
#3377修正了 node-fetch 匯入的錯誤,由 @paperclover 執行
#3376bun:test 中實作了 spyOn(),由 @paperclover 執行
#3249實作了 fs.watch(),由 @cirospaciari 執行
#3379重寫了 CommonJS 的支援,由 @Jarred-Sumner 執行
#3394修正了 WebSocket 中 Latin1 字串的錯誤,由 @Jarred-Sumner 執行
#3400修正了 bun install --production 可能發生的崩潰,由 @Jarred-Sumner 執行
5bd94b8實作了 process.mainModule,由 @Jarred-Sumner 執行
#3402修正了 WriteStream 建構函式的錯誤,由 @Hanaasagi 執行
#3405實作了將檔案嵌入已編譯可執行檔的支援,由 @Jarred-Sumner 執行
#3365實作了 bun install --frozen-lockfile,由 @tiagotex 執行
#3356更新 lol-html,由 @bru02 執行
#3401修正了 lol-html 的崩潰問題,由 @Jarred-Sumner 執行
#3411實作了 _nodeModulePathsrequire.main.paths,由 @dylan-conway 執行
#3288package.json 中實作了 trustedDependencies,由 @alexlamsl 執行
#3419實作了 writevreadv,由 @Jarred-Sumner 執行
#3393實作了 __esModule 註解,由 @Jarred-Sumner 執行

完整更新日誌