Bun

Bun 1.0


Jarred Sumner, Ashcon Partovi, Colin McDonnell · 2023 年 9 月 8 日

Bun 1.0 終於正式發布。

Bun 是一個快速、多合一的工具組,用於執行、建置、測試和偵錯 JavaScript 和 TypeScript,從單一檔案到完整堆疊的應用程式。今天,Bun 已穩定且可供生產環境使用。

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

Bun 是一個多合一的工具組

我們熱愛 JavaScript。它成熟、發展快速,且其開發者社群充滿活力和熱情。它非常棒。

然而,自從 Node.js 在 14 年前首次亮相以來,工具層層疊疊地累積在彼此之上。而且就像任何在沒有集中規劃的情況下成長和演進的系統一樣,JavaScript 工具已變得緩慢且複雜。

Bun 存在的原因

Bun 的目標很簡單:消除緩慢和複雜性,同時不丟棄 JavaScript 的所有優點。您最喜歡的程式庫和框架應該仍然可以運作,而且您不應該需要忘記您熟悉的慣例。

但是,您需要忘記 Bun 使其變得不必要的許多工具

Node.js — Bun 是 Node.js 的直接替換品,因此您不需要

  • node
  • npxbunx 快 5 倍
  • dotenvcross-env — Bun 預設讀取 .env 檔案
  • nodemonpm2 — 內建監看模式
  • ws — 內建 WebSocket 伺服器
  • node-fetchisomorphic-fetch — 內建 fetch

轉譯器 — Bun 可以執行 .js.ts.cjs.mjs.jsx.tsx 檔案,這可以取代

  • tsc — (但您可以保留它以進行類型檢查!)
  • babel.babelrc@babel/preset-*
  • ts-nodets-node-esm
  • tsx

打包器 — Bun 是一個 JavaScript 打包器,具有同類最佳的效能和與 esbuild 相容的外掛程式 API,因此您不需要

  • esbuild
  • webpack
  • parcel.parcelrc
  • rolluprollup.config.js

套件管理器 — Bun 是一個與 npm 相容的套件管理器,具有熟悉的命令。它讀取您的 package.json 並寫入 node_modules,就像其他套件管理器一樣,因此您可以取代

  • npm.npmrcpackage-lock.json
  • yarnyarn.lock
  • pnpmpnpm.lockpnpm-workspace.yaml
  • lerna

測試程式庫 — Bun 是一個與 Jest 相容的測試執行器,支援快照測試、模擬和程式碼覆蓋率,因此您不再需要

  • jestjest.config.js
  • ts-jest@swc/jestbabel-jest
  • jest-extended
  • vitestvitest.config.ts

雖然這些工具各自都很好 (大部分情況下),但將它們全部一起使用不可避免地會造成脆弱性和緩慢的開發者體驗。它們執行了許多多餘的工作;當您執行 jest 時,您的程式碼將被各種工具解析 3 次以上!而且將所有內容縫合在一起所需的膠帶、外掛程式和轉接器最終總會磨損。

Bun 是一個單一的整合工具組,可避免這些整合問題。此工具組中的每個工具都提供同類最佳的開發者體驗,從效能到 API 設計。

Bun 是一個 JavaScript 執行環境

Bun 是一個快速的 JavaScript 執行環境。其目標是使軟體建置體驗更快、更少挫敗感且更有趣。

Node.js 相容性

Bun 是 Node.js 的直接替換品。這表示現有的 Node.js 應用程式和 npm 套件在 Bun 中可以直接運作。Bun 內建支援 Node API,包括

  • 內建模組,例如 fspathnet
  • 全域變數,例如 __dirnameprocess
  • 以及 Node.js 模組解析演算法。(例如 node_modules)

雖然與 Node.js 的完美相容性是不可能的 — 看看你 node:v8 — Bun 幾乎可以執行任何公開發布的 Node.js 應用程式。

Bun 針對 npm 上最流行的 Node.js 套件的測試套件進行了測試。伺服器框架 (例如 Express、Koa 和 Hono) 可以直接運作。使用最流行的完整堆疊框架建置的應用程式也是如此。總體而言,這些程式庫和框架觸及了 Node.js API 表面中每個重要的部分。

使用 Next.js、Remix、Nuxt、Astro、SvelteKit、Nest、SolidStart 和 Vite 建置的完整堆疊應用程式可以在 Bun 中運作。

注意 — 如需 Node.js 相容性的詳細分類,請查看:bun.sh/nodejs

速度

Bun 速度很快,啟動速度比 Node.js 快達 4 倍 更快。當執行 TypeScript 檔案時,這種差異會更加明顯,因為 TypeScript 檔案需要先經過轉譯才能由 Node.js 執行。

Bun 執行 "hello world" TypeScript 檔案的速度比搭配 Node.js 的 esbuild 快 5 倍。

與使用 Google 的 V8 引擎建置的 Node.js 和其他執行環境不同,Bun 是使用 Apple 的 WebKit 引擎建置的。WebKit 是 Safari 的引擎,每天被數十億個裝置使用。它快速、高效,並且經過數十年的實戰考驗。

TypeScript 和 JSX 支援

Bun 具有內建於執行環境中的 JavaScript 轉譯器。這表示您可以執行 JavaScript、TypeScript 甚至 JSX/TSX 檔案,無需任何依賴項。

bun index.ts
bun index.jsx
bun index.tsx

ESM 和 CommonJS 相容性

從 CommonJS 到 ES 模組的過渡一直很緩慢且充滿恐懼。在引入 ESM 之後,Node.js 花了 5 年時間才在沒有 --experimental-modules 標誌的情況下支援它。儘管如此,生態系統仍然充滿 CommonJS。

Bun 始終支援這兩種模組系統。無需擔心檔案副檔名、.js.cjs.mjs,或在您的 package.json 中包含 "type": "module"

您甚至可以在同一個檔案中使用 importrequire()。它可以直接運作。

import lodash from "lodash";
const _ = require("underscore");

Web API

Bun 內建支援瀏覽器中可用的 Web 標準 API,例如 fetchRequestResponseWebSocketReadableStream

const response = await fetch("https://example.com/");
const text = await response.text();

您不再需要安裝 node-fetchws 等套件。Bun 的內建 Web API 是以原生程式碼實作的,比第三方替代方案更快且更可靠。

熱重載

Bun 使您作為開發者更容易提高生產力。您可以執行具有 --hot 的 Bun 以啟用熱重載,這會在檔案變更時重新載入您的應用程式。

bun --hot server.ts

與硬重新啟動整個程序 (例如 nodemon) 的工具不同,Bun 會重新載入您的程式碼,而不會終止舊程序。這表示 HTTP 和 WebSocket 連線不會中斷連線,並且狀態不會遺失。

外掛程式

Bun 設計為高度可自訂。

您可以定義外掛程式來攔截匯入並執行自訂載入邏輯。外掛程式可以新增對其他檔案類型 (例如 .yaml.png) 的支援。外掛程式 API 的靈感來自 esbuild,這表示大多數 esbuild 外掛程式都可以在 Bun 中運作。

import { plugin } from "bun";

plugin({
  name: "YAML",
  async setup(build) {
    const { load } = await import("js-yaml");
    const { readFileSync } = await import("fs");
    build.onLoad({ filter: /\.(yaml|yml)$/ }, (args) => {
      const text = readFileSync(args.path, "utf8");
      const exports = load(text) as Record<string, any>;
      return { exports, loader: "object" };
    });
  },
});

Bun API

Bun 隨附高度最佳化的標準程式庫 API,用於開發者最需要的功能。

與 Node.js API (為了向後相容性而存在) 相反,這些Bun 原生 API 設計為快速且易於使用。

Bun.file()

使用 Bun.file() 以延遲載入特定路徑的 File

const file = Bun.file("package.json");
const contents = await file.text();

它會傳回一個 BunFile,它擴展了 Web 標準 File。檔案內容可以延遲載入各種格式。

const file = Bun.file("package.json");

await file.text(); // string
await file.arrayBuffer(); // ArrayBuffer
await file.blob(); // Blob
await file.json(); // {...}

Bun 讀取檔案的速度比 Node.js 快達 10 倍 更快

Bun.write()

使用 Bun.write() 是一個單一、彈性的 API,用於將幾乎任何內容寫入磁碟 — 字串、二進位資料、Blobs,甚至是 Response 物件。

await Bun.write("index.html", "<html/>");
await Bun.write("index.html", Buffer.from("<html/>"));
await Bun.write("index.html", Bun.file("home.html"));
await Bun.write("index.html", await fetch("https://example.com/"));

Bun 寫入檔案的速度比 Node.js 快達 3 倍 更快

Bun.serve()

使用 Bun.serve() 來啟動 HTTP 伺服器、WebSocket 伺服器或兩者。它基於熟悉的 Web 標準 API,例如 RequestResponse

Bun.serve({
  port: 3000,
  fetch(request) {
    return new Response("Hello from Bun!");
  },
});

Bun 每秒可以處理的請求比 Node.js 多 4 倍 更多

您也可以使用 tls 選項設定 TLS。

Bun.serve({
  port: 3000,
  fetch(request) {
    return new Response("Hello from Bun!");
  },
  tls: {
    key: Bun.file("/path/to/key.pem"),
    cert: Bun.file("/path/to/cert.pem"),
  }
});

為了支援 HTTP 旁的 WebSocket,只需在 websocket 內定義事件處理常式。將此與 Node.js 進行比較,Node.js 不提供內建的 WebSocket API,並且需要像 ws 這樣的第三方依賴項。

Bun.serve({
  fetch() { ... },
  websocket: {
    open(ws) { ... },
    message(ws, data) { ... },
    close(ws, code, reason) { ... },
  },
});

Bun 每秒可以處理的訊息比 Node.js 上的 ws 多 5 倍 更多

bun:sqlite

Bun 內建支援 SQLite。它具有受 better-sqlite3 啟發的 API,但以原生程式碼撰寫,以求更快。

import { Database } from "bun:sqlite";

const db = new Database(":memory:");
const query = db.query("select 'Bun' as runtime;");
query.get(); // => { runtime: "Bun" }

Bun 查詢 SQLite 的速度比 Node.js 上的 better-sqlite3 快達 4 倍 更快

Bun.password

Bun 也支援用於常見但複雜的事物的 API,您不想自己實作這些事物。

您可以使用 Bun.password 使用 bcrypt 或 argon2 雜湊和驗證密碼,無需外部依賴項。

const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password);
// => $argon2id$v=19$m=65536,t=2,p=1$tFq+9AVr1bfPxQdh...

const isMatch = await Bun.password.verify(password, hash);
// => true

Bun 是一個套件管理器

即使您不將 Bun 用作執行環境,Bun 的內建套件管理器也可以加速您的開發工作流程。盯著 npm 旋轉圖示看著您的依賴項安裝的日子已經過去了。

Bun 可能看起來像您習慣使用的套件管理器 —

bun install
bun add <package> [--dev|--production|--peer]
bun remove <package>
bun update <package>

— 但它感覺不像它們。

安裝速度

Bun 比 npmyarnpnpm 快幾個數量級。它使用全域模組快取來避免從 npm 登錄檔重複下載,並使用每個作業系統上可用的最快系統呼叫。

從快取安裝啟動器 Remix 專案的依賴項。

執行指令碼

您可能有一段時間沒有直接使用 node 執行指令碼了。相反,我們經常使用我們的套件管理器來與框架和 CLI 介面以建置我們的應用程式。

npm run dev

您可以用 bun run 取代 npm run每次執行命令時節省 150 毫秒。

這些數字可能看起來都很小,但當執行 CLI 時,感知上的差異是巨大的。執行 npm run 明顯有延遲—

—而 bun run 感覺是瞬間完成的。

而且我們不只是挑剔 npm。事實上,bun run <command>yarnpnpm 中的等效命令 更快

指令碼執行器平均時間
npm run176 毫秒
yarn run131 毫秒
pnpm run259 毫秒
bun run7 毫秒 🚀

Bun 是一個測試執行器

如果您之前在 JavaScript 中編寫過測試,您可能很熟悉 Jest,它開創了 "expect" 風格的 API。

Bun 有一個內建的測試模組 bun:test,它與 Jest 完全相容。

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

test("2 + 2", () => {
  expect(2 + 2).toBe(4);
});

您可以使用 bun test 命令執行您的測試。

bun test

您還可以獲得 Bun 執行環境的所有優點,包括 TypeScript 和 JSX 支援。

從 Jest 或 Vitest 遷移很容易。從 @jest/globalsvitest 的任何匯入都將在內部重新對應到 bun:test,因此一切都可以運作,即使沒有程式碼變更。

index.test.ts
import { test } from "@jest/globals";

describe("test suite", () => {
  // ...
});

在針對 zod 的測試套件的基準測試中,Bun 比 Jest 快 13 倍,比 Vitest 快 8 倍。

執行 Zod 的測試套件

Bun 的匹配器是以快速原生程式碼實作的 — Bun 中的 expect().toEqual() 比 Jest 快 100 倍 更快,比 Vitest 快 10 倍。

若要開始使用,您可以使用 bun test 加速您的 CI。在 Github Actions 中,使用官方的 oven-sh/setup-bun 動作。

.github/workflows/ci.yml
name: CI
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: oven-sh/setup-bun@v1
      - run: bun test

為了讓事情變得更好,Bun 會自動將註解新增到您的測試失敗中,因此您的 CI 日誌易於閱讀。

Bun 是一個打包器

Bun 是一個 JavaScript 和 TypeScript 打包器和最小化器,可用於為瀏覽器、Node.js 和其他平台打包程式碼。

CLI
bun build ./index.tsx --outdir ./build

它深受 esbuild 的啟發,並提供相容的外掛程式 API。

import mdx from "@mdx-js/esbuild";

Bun.build({
  entrypoints: ["index.tsx"],
  outdir: "build",
  plugins: [mdx()],
});

Bun 的外掛程式 API 是通用的,這表示它適用於打包器執行環境。因此,先前的 .yaml 外掛程式可以在此處用於支援打包期間的 .yaml 匯入。

使用 esbuild 自己的基準測試,Bun 比 esbuild 快 1.75 倍,比 Parcel 2 快 150 倍,比 Rollup + Terser 快 180 倍,比 Webpack 快 220 倍。

從頭開始打包 10 個 three.js 副本,具有來源地圖和最小化。

由於 Bun 的執行環境和打包器是整合的,這表示 Bun 可以做其他打包器無法做到的事情。

Bun 引入了 JavaScript 巨集,這是一種在打包時執行 JavaScript 函數的機制。從這些函數傳回的值會直接內嵌到您的捆綁包中。

index.ts
release.ts
index.ts
import { getRelease } from "./release.ts" with { type: "macro" };

// The value of `release` is evaluated at bundle-time,
// and inlined into the bundle, not run-time.
const release = await getRelease();
release.ts
export async function getRelease(): Promise<string> {
  const response = await fetch(
    "https://api.github.com/repos/oven-sh/bun/releases/latest"
  );
  const { tag_name } = await response.json();
  return tag_name;
}

CLI
bun build index.ts
// index.ts
var release = await "bun-v1.0.0";

這是打包 JavaScript 的新範例,我們很高興看到您使用它建置什麼。

Bun 還有更多...

Bun 為 macOS 和 Linux 提供原生建置版本,但有一個顯著的缺席:Windows。先前,若要在 Windows 上執行 Bun,您需要安裝 Windows Subsystem for Linux... 但現在不再需要了。

我們很高興首次發布適用於 Windows 的 Bun 實驗性原生建置版本。

雖然 macOS 和 Linux 建置版本的 Bun 已可供生產環境使用,但 Windows 建置版本仍處於高度實驗階段。目前,僅支援 JavaScript 執行環境;套件管理器、測試執行器和打包器已被停用,直到它們更穩定為止。效能也尚未最佳化 — 尚未。

我們將在未來幾週內快速改進對 Windows 的支援。如果您對適用於 Windows 的 Bun 感到興奮,我們鼓勵您加入我們 Discord 上的 #windows 頻道以獲取更新。

感謝您

如果沒有 Bun 傑出的工程師團隊和不斷成長的貢獻者社群,Bun 的 1.0 之旅是不可能實現的。

我們要感謝那些幫助我們走到這裡的人。

  • Node.js 及其貢獻者:軟體是站在巨人的肩膀上建構的。
  • WebKit 及其貢獻者,尤其是 Constellation:感謝您讓 WebKit 變得更快,您們太棒了。
  • 在過去兩年中幫助建置 Bun 的 近 300 位貢獻者

接下來是什麼?

Bun 1.0 僅僅是個開始。

我們正在開發一種將 JavaScript 和 TypeScript 部署到生產環境的新方法。而且如果您想幫助我們建構 JavaScript 的未來,我們正在徵才底層系統工程師。

您也可以

  • 加入我們的 Discord 伺服器以收聽有關 Bun 的最新消息。
  • 追蹤我們的 X/Twitter 以獲取 JavaScript 迷因和來自 Jarred 和團隊的每日更新。
  • 在 Github 上給我們加星號 — 它可以支付帳單!(/s)

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

自 v0.8 以來的變更記錄

如果您在 1.0 之前使用 Bun,則自 Bun 0.8 以來有一些變更。

  • 現在支援 Next.js、Astro 和 Nest.js 了!
  • 已移除已棄用的 bun dev 命令。現在執行 bun dev 將執行您 package.json 中的 "dev" 指令碼。

Bun 現在支援以下 Node.js API

熱重載現在支援 Bun.serve()。先前,只有在伺服器定義為 default export 時才有可能。

server.ts
Bun.serve({
  fetch(request) {
    return new Response("Reload!");
  },
})

CLI
bun --hot server.ts