Bun

Bun v1.1.30


Jarred Sumner · 2024 年 10 月 8 日

我們正在舊金山招聘系統工程師,以打造 JavaScript 的未來!

此版本修正了 57 個錯誤(解決了 150 個 👍)。Bun 的 CSS 捆綁器已在此處(且非常實驗性)。bun publishnpm publish 的直接替換品。bun build --bytecode 編譯為位元組碼,啟動時間加快 2 倍。Bun.color() 格式化並標準化顏色。bun pm whoami 印出您的 npm 使用者名稱。bun install 讀取 $HOME/.npmrcbun build --format=cjs 輸出 CommonJS 模組。bun build --target=node 現在支援 Node.js 原生附加元件。crypto.privateEncrypt() & crypto.publicDecrypt() 速度提升 30 倍。bun test 中的殭屍程序終結器。bun build 中的 --banner--footer 選項。Bun.serve().stop() 傳回 Promise。Bun.CryptoHasher 現在支援 HMAC。node:zlib、node:module 和 node:buffer 的錯誤修正。更多錯誤修正和 Node.js 相容性改進

安裝 Bun

curl
npm
powershell
scoop
brew
docker
curl
curl -fsSL https://bun.dev.org.tw/install | bash
npm
npm install -g bun
powershell
powershell -c "irm bun.sh/install.ps1|iex"
scoop
scoop install 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

實驗性功能:CSS 解析與捆綁

在過去兩個月裡,@zackradisic 為 Bun 建構了一個 CSS 解析器和捆綁器。

它基於 @devongovett 出色的 LightningCSS 解析器,從 Rust 重寫為 Zig,以垂直整合到 Bun 的 JavaScript 和 TypeScript 解析器、捆綁器和執行時環境中。

您今天可以透過帶有 --experimental-css 標誌的 bun build (CLI) 或 Bun.build (API) 試用。

CSS 捆綁

Bun 的 CSS 捆綁器將多個 CSS 檔案和透過 url@import@font-face 等引用的任何資產串連成單個 CSS 檔案,您可以將其發送到瀏覽器,從而避免網路請求瀑布流。

index.css
@import "foo.css";
@import "bar.css";

透過 CLI 使用 bun build 試用

shell
bun build --experimental-css ./index.css

這兩個 CSS 檔案變成單個捆綁的 CSS 檔案

dist.css
/** foo.css */
.foo {
  background: red;
}

/** bar.css */
.bar {
  background: blue;
}

在 JavaScript 和 TypeScript 中匯入 .css 檔案

Bun 的 CSS 解析器與我們的 JavaScript 和 TypeScript 解析器與捆綁器整合。

您可以在 JavaScript 和 TypeScript 中匯入 .css 檔案,並且將建立一個額外的 css 入口點,它將組合從 JavaScript/TypeScript 模組圖匯入的所有 css 檔案,以及任何 @import 規則。

index.ts
import "./style.css";
import Component from "./MyComponent.tsx";

// ... rest of your app

然後,如果 MyComponent.tsx 匯入 CSS 檔案,則不會將額外的 .css 檔案新增到捆綁包中,而是將每個入口點匯入的所有 CSS 扁平化為單個 CSS 檔案。

shell
bun build --experimental-css ./index.ts --outdir=dist
  index.js     0.10 KB
  index.css    0.10 KB
[5ms] bundle 4 modules

這會輸出以下 css 檔案,該檔案來自 TypeScript 匯入

style.css
/* style.css */
.hello {
  background: red;
}

/* MyComponent.css */
.MyComponent {
  color: green;
}

使用 Bun.build 捆綁 CSS:

我們也新增了透過 Bun.build API 以程式方式捆綁 CSS 的支援。您可以使用相同的 API 在同一個組建中捆綁 CSS 和 JavaScript。

api.ts
import { build } from "bun";

const results = await build({
  entrypoints: ["./index.css"],
  outdir: "./dist",
  experimentalCss: true,
});

console.log(results);

CSS 解析與捆綁的速度有多快?

一旦它更穩定,我們將發布基準測試,但我認為您會對效能感到滿意。

非常感謝 @zackradisic 建構了這個,並感謝 @devongovett 提供他出色的 LightningCSS 函式庫。

bun publishnpm publish 的直接替換品

您可以使用 bun 透過 bun publish 發布 npm 套件

bun publish

bun publish v1.1.30 (ecad797a)

packed 108B package.json
packed 3B README.md
packed 19B index.js

Total files: 3
Shasum: abd73b91b21057f0b07a58472077f5a3bbfb3e89
Integrity: sha512-aWkWikXiSXyR[...]Ubll4PQcEEoNw==
Unpacked size: 130B
Packed size: 254B
Tag: latest
Access: default
Registry: https://127.0.0.1:4873

+ lodash-2@1.0.0

bun publish 旨在作為 npm publish 的直接替換品,並支援許多相同的功能,例如

  • 讀取 .npmrc 檔案以進行身分驗證
  • 封裝 tarball,考量多個目錄中的 .gitignore.npmignore 檔案
  • OTP / 雙重驗證
  • 處理 package.json 欄位的各種邊緣情況,例如 "bin""files"
  • 仔細處理遺失的 README 檔案

此外,當使用工作區時,bun publish 將自動重新撰寫工作區套件的依賴版本,以指向已發布的版本,以便您可以正確發布在內部使用 workspace: 依賴關係的套件。

感謝 @dylan-conway 實作此功能!

bun pm whoami

新的 bun pm whoami 命令將印出目前使用者的 npm 使用者名稱。

bun pm whoami
bun

感謝 @dylan-conway 實作此功能!

編譯為位元組碼以加快 2 倍啟動時間

bun build 現在支援將 JavaScript 和 TypeScript 捆綁到位元組碼,以加快 2 倍啟動時間。

bun build --bytecode --compile ./index.ts

單一檔案位元組碼可執行檔

位元組碼捆綁包

如果您希望使用個別檔案而不是獨立可執行檔,您也可以在不使用 --compile 的情況下使用此功能。

bun build --bytecode --outdir=./dist ./index.ts

這將輸出與 .js 檔案並排的 .jsc 檔案。這些 .jsc 包含檔案的位元組碼版本。兩者都必須在 Bun 中執行,因為位元組碼編譯目前不編譯 async 函數、產生器、eval 和少數其他邊緣情況。

位元組碼可能比原始碼大 8 倍,因此這可以加快啟動速度,但會增加磁碟空間成本。

CommonJS 捆綁包輸出格式

bun build 現在支援 --format=cjs 以輸出 CommonJS 捆綁包。先前僅支援 --format=esm

這使得在 CommonJS 模組更易於使用的情況下,更輕鬆地使用 bun build 來建構適用於 Node.js 的函式庫和應用程式。

shell.sh
index.js
output.js
shell.sh
bun build --format=cjs index.js
index.js
// index.js
export default "Hello, world!";
output.js
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __moduleCache = /* @__PURE__ */ new WeakMap;
var __toCommonJS = (from) => {
  var entry = __moduleCache.get(from), desc;
  if (entry)
    return entry;
  entry = __defProp({}, "__esModule", { value: true });
  if (from && typeof from === "object" || typeof from === "function")
    __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
      get: () => from[key],
      enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
    }));
  __moduleCache.set(from, entry);
  return entry;
};
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, {
      get: all[name],
      enumerable: true,
      configurable: true,
      set: (newValue) => all[name] = () => newValue
    });
};

// index.js
var exports_site = {};
__export(exports_site, {
  default: () => site_default
});
module.exports = __toCommonJS(exports_site);
var site_default = "Hello, world!";

bun test 中的殭屍程序終結器

在 Linux 和 macOS 上,當一個產生的程序未被等待時,它被稱為「殭屍程序」。

Bun 現在會自動終結 bun test 中因測試逾時而產生的殭屍程序。

當在 bun test 中產生程序(多個)的測試逾時時,如果無法從測試外部存取該程序,那麼如果 bun test 在不久後退出,您最終可能會得到一個可能永遠不會被清除的程序。對於像 Puppeteer 這樣產生瀏覽器實例的工具來說,這尤其明顯。持續存在的 Chromium 程序可能會花費您數百 MB 的 RAM 並導致各種問題。

Bun 現在會在內部追蹤測試內產生的所有程序,如果測試逾時,Bun 將自動終結該程序。

使用 --target=node 捆綁 .node 檔案

您現在可以使用 Bun 捆綁 Node.js 原生模組,並在 Node.js 中執行這些 Node.js 原生模組。

我們修正了一個錯誤,該錯誤阻止 --target=node 正確捆綁 .node 檔案,這些檔案是 Node.js 原生模組。先前,這僅在 --target=bun 中受支援,現在也在 --target=node 中受支援。

您現在可以使用 bun buildBun.build 中的 --banner--footer 選項,在捆綁輸出上方和下方新增橫幅和頁尾。

輸入

shell
api.js
shell
bun build --banner "/* Hello, world! */" --footer "/* Goodbye! */" index.ts
api.js
await Bun.build({
  entrypoints: ["./index.ts"],
  outdir: "./dist",
  banner: "/* Hello, world! */",
  footer: "/* Goodbye! */",
});

輸出

/**
 * Hello, world!
 */
export default "Hello, world!";
/**
 * Goodbye!
 */

非常感謝 @versecafe 實作此功能!

bun install 中的 --registry 標誌

您現在可以在使用 bun install 安裝套件時,從命令列指定自訂登錄檔。您可以單獨使用此標誌,也可以與您想要新增到專案的套件一起使用。

# Install packages from a custom local registry instead of the default npm registry.
bun install --registry=https://127.0.0.1:4873/
# With packages
bun install zod --registry=https://127.0.0.1:4873/

您可以繼續在 .npmrc 檔案、bunfig.toml 或透過 NPM_CONFIG_REGISTRY 環境變數中設定登錄檔。如果您想要從私有登錄檔全域安裝套件,而無需在 .npmrc 檔案中設定登錄檔或使用範圍套件名稱,則此額外的 CLI 標誌非常有用。

Bun.color() 格式化並標準化顏色

Bun.serve() 中的 stop() 傳回 Promise

Bun 的 HTTP 伺服器 API Bun.serve() 現在從 server.stop() 傳回 Promise,當所有連線關閉時,Promise 會解析。

這讓您可以使用 await server.stop() 等待所有連線關閉,而不會突然關閉它們。

const server = Bun.serve({
  port: 3000,
  async fetch(req) {
    return new Response("Hello, world!");
  },
});

await server.stop();

Bun.CryptoHasher 中的 HMAC

Bun.CryptoHasher 現在可用於計算 HMAC 摘要。為此,請將金鑰傳遞給建構函式。

import { CryptoHasher } from "bun";
const hasher = new CryptoHasher("sha1", "secret-key");
const hash = hasher
  .update("message")
  // This creates the HMAC signature
  .digest("hex");

console.log(hash); // 48de2656eac2c9c21b04faeec4f1be9672ef53c1

bun install 現在讀取 $HOME/.npmrc

如果未指定其他登錄檔,bun install 現在會讀取 $HOME/.npmrc 檔案以進行身分驗證。

先前,僅讀取目前目錄中的 .npmrc。現在,如果在目前的 package.json 目錄中找不到 .npmrc,也會讀取 $HOME/.npmrc

感謝 @robertshuford 實作此功能!

捆綁器修正

已修正:bun build 中的頂層 await 錯誤

已修正一個可能導致 bun build 中出現虛假頂層 await 錯誤的錯誤,感謝 @snoglobe

已修正:在 bun build 中匯入帶有 Unicode 字元的 JSON

現在,在 bun build 中正確地處理了匯入帶有 Unicode 字元的 JSON。Bun 先前錯誤地轉換了來自 JSON 的字串編碼,導致 Unicode 字元以錯誤的編碼方式解譯。

// test.json
{
  "测试a": "b"
}
// test.js
import data from "./test.json";
console.log(data["测试" + "a"]); // b

感謝 @snoglobe

Node.js 相容性改進

crypto.privateEncrypt() & crypto.publicDecrypt() 速度提升 30 倍

Bun 中的 crypto.privateEncrypt()crypto.publicDecrypt() 現在由 BoringSSL 提供支援,這使得這些函式的效能比先前的 JavaScript Polyfill 實作提高了 30 倍。

之後

benchmark                                  time (avg)             (min … max)       p75       p99      p999
----------------------------------------------------------------------------- -----------------------------
RSA sign RSA_PKCS1_PADDING round-trip     832 µs/iter       (816 µs … 915 µs)    834 µs    893 µs    915 µs

之前

benchmark                                  time (avg)             (min … max)       p75       p99      p999
----------------------------------------------------------------------------- -----------------------------
RSA sign RSA_PKCS1_PADDING round-trip  26'997 µs/iter (26'657 µs … 27'551 µs) 27'119 µs 27'551 µs 27'551 µs

感謝 @wpaulino 進行修正!

require("cluster") 速度加快 6 毫秒

require("cluster") 所需的時間減少了 6 毫秒,感謝 @nektro

先前

bun-1.1.29 --print 'console.time("require(`cluster`)");require(`cluster`);console.timeEnd("require(`cluster`)");' # Old
[7.62ms] require(`cluster`)

現在

bun --print 'console.time("require(`cluster`)");require(`cluster`);console.timeEnd("require(`cluster`)");' # New
[1.39ms] require(`cluster`)

已修正:Buffer.alloc 的第二個引數錯誤

已修正當 Buffer.alloc 傳遞空字串作為第二個引數時的錯誤。

感謝 @nektro 進行修正!

已修正:多個 node:zlib 問題

Bun 的 node:zlib 實作現在通過了更多 Node.js 測試,感謝 @nektro!這解決了 Sharp/Jimp、Zip.js、一些 GPRC 函式庫、pubnub 等問題。

感謝 @nektro 進行修正!

已修正:Prisma 在退出前未等待 Promise

我們的 NAPI 實作中的一個錯誤可能會導致 Prisma 在 Bun 程序退出之前,未等待查詢中的 Promise。

感謝 @190n 進行修正!

已修正:node:module 中遺失的匯出

已新增 node:module 中少數遺失的匯出

  • _preloadModules 先前未定義。現在它不執行任何操作
  • _debug & _pathCache 先前為 undefined
  • enableCompileCachegetCompileCache 先前未定義
  • __resolveFilename_resolveFilename 先前都已定義,現在僅定義 _resolveFilename

已修正:console.logrequire.cache

先前,console.log(require.cache) 會印出一個空物件。現在它會印出快取。

// Old
{}

// New
{
  "/path/to/module": Module {
    id: "/path/to/module",
    exports: {},
    parent: null,
    filename: "/path/to/module.js",
    loaded: false,
    children: [],
    paths: []
  }
}

已修正:process.cwd() 在 Windows 上針對磁碟機根目錄傳回錯誤的路徑

已修正一個回歸,如果目前工作目錄位於磁碟機的根目錄,則 process.cwd() 會在 Windows 上傳回不正確的路徑。例如,如果目前工作目錄為 C:\,則 process.cwd() 將傳回 C: 而不是 C:\

已修正:Bun.spawn() 中 2 個罕見的崩潰

已修正 Bun.spawn() 中的兩個罕見崩潰。其中一個是 Bun v1.1.25 的回歸。有時在某些情況下,子程序在參考 stdin 之前被垃圾回收時會發生這種情況。

原型污染緩解

為了使 原型污染 更難在 Bun 的 API 中利用,Bun API 現在在從 Bun 原生實作的 API(例如 fetchRequestResponse 等)中的物件和函式讀取值時,會忽略 Object 原型。

先前,以下程式碼會導致 glob.scanSync 追蹤符號連結

import { Glob } from "bun";
const glob = new Glob("*.ts");
Object.defineProperty(Object.prototype, "followSymlinks", {
  value: true,
  writable: true,
  configurable: true,
  enumerable: true,
});
const second = glob.scanSync({
  cwd: path.join(dir, "abc"),
  onlyFiles: true,
});

現在,由於 Object.prototype 被忽略,因此這種攻擊得到了緩解。我們幾乎對所有在 Zig 中實作的 Bun API 都執行了此操作。

這並不能完全防止原型污染攻擊,但確實使它們更難在 Bun API 中利用。感謝 @lirantal 的報告!

已修正:bun add 錯誤地將相對路徑新增到工作區中的 tarball

修正了一個錯誤,該錯誤導致 bun add 無法將本機 tarball 套件新增到工作區。發生這種情況的原因是 bun 使用工作區根目錄作為基礎路徑,而不是 tarball 將被新增到的目前工作區套件。

感謝 17 位貢獻者!