Bun-js 入門簡介
Bun 是 Node.js 和 Deno 的競爭對手,是一個新的 JavaScript 運行時。在本文中,我們將介紹 Bun 1.0,以及它可能讓你嘗試去使用的理由。
歷史:Bun 在 Node 和 Deno 中的位置
Ryan Dahl 於 2009 年發佈了 Node.js。雖然它不是第一個服務器端 JavaScript 運行時,但 Node.js 迅速嶄露頭角。2023 年發佈了第 20 版,Node.js 擁有最大的開發生態系統,擁有 320 萬個模塊,每週下載量接近 5000 億次。
2020 年,Ryan Dahl 發佈了 Deno,它是 “noDe” 的一種混合體,旨在現代化 JavaScript 開發並解決 Node.js 安全性、API 兼容性、工具和模塊管理方面的傳統問題。雖然 Deno 受到了積極的評價,但尚未挑戰 Node 的主導地位。
2022 年,Jarred Sumner 發佈了 Bun,因爲他在開發 Next.js 項目時對 Node.js 的速度感到不滿。
Bun 使用 JavaScriptCore 引擎,該引擎驅動 WebKit 瀏覽器,如 Safari,而不是 Node.js、Deno 和 Chrome 中使用的 V8 引擎。
Bun 運行時側重於性能和開發人員體驗。其目標是消除速度慢和複雜性,而不是放棄 JavaScript 的所有優點。
Bun 可以比 Node.js 更快地發展,後者必須與現有的 JavaScript 和 npm 生態系統保持(基本)向後兼容。
與 Deno 一樣,Bun 對 JavaScript 和 TypeScript 本地支持,無需第三方轉譯器或配置。
Bun 正在成爲 Node.js、Deno、無服務器運行時、構建和測試工具的即插即用替代品。它可以替代 npm、npx、yarn、TypeScript 編譯器、dotenv、nodemon、pm2、Webpack、Babel 和 Jest,爲在單一平臺上開發應用程序提供了一個完整的多合一工具箱。
最初的運行時是穩定的,但多虧了近 300 名開發人員的貢獻,Bun 版本 1.0 發佈於 2023 年 9 月發佈。這將不可避免地誘使更多的開發人員遷移到 Bun,他們可以享受下文描述的好處。
“Bun” 這個名字有什麼
來歷?“Bun” 這個名字的起源不清楚,標誌也沒有幫助!它可能與食物、蓬鬆的兔子、“bundle” 或者可能是一個簡短、容易記住的名字有關,而且 bun.sh 域名也可用。
美味的 Bun 好處
Node.js 和 Deno 使用 Chrome 的 V8 JavaScript 引擎。Bun 選擇了 JavaScriptCore 引擎,該引擎驅動 WebKit 瀏覽器,如 Safari。Bun 本身是用 Zig 編寫的,這是一種具有手動內存管理和本機線程處理能力的低級編程語言。其結果是一個輕量級運行時,具有更小的內存佔用、更快的啓動時間,以及在某些(基準測試)條件下性能可以比 Node.js 和 Deno 快四倍。
與 Deno 一樣,Bun 對 JavaScript 和 TypeScript 都有本機支持,無需第三方轉譯器或配置。它還支持. jsx 和. tsx 文件,以將類似 HTML 的標記轉換爲本機 JavaScript。還提供了運行 WebAssembly 編譯的. wasm 文件的實驗性支持。
在內部 Bun 使用 ES 模塊,支持頂級await
,翻譯 CommonJS,並實現了 Node 的node_modules
解析算法。Bun 將模塊緩存到~/.bun/install/cache/
中,並使用硬鏈接將它們 “複製” 到項目的node_modules
目錄中。因此,您系統上的所有項目都將引用同一庫的單個實例,這減少了磁盤空間需求並提高了安裝性能。(請注意,macOS 安裝保留本地版本以提高速度。)
Bun 支持 Node 的package.json
,與npm
等效命令,以及 bunx,這是一個類似npx
的選項,可以在單個命令中自動安裝和運行包。例如:
bunx cowsay "Hello, world!"
bun init
與npm init
相同,用於創建空項目,但您還可以使用bun create <template> <destination>
來模板化新項目,其中<template>
是一個官方包、GitHub 存儲庫或本地包。例如,要創建一個新的 Next.js 項目:
bun create next ./myapp
Bun 包含一個 bundler,用於將所有依賴項導入單個文件,並且可以針對 Bun、Node.js 和客戶端 JavaScript。這減少了使用 esbuild 或 Rollup 等工具的需求:
bun build ./index.ts —outdir ./out
大多數命令行界面選項都可以通過 JavaScript API 使用,因此可以創建複雜的構建腳本,而無需專門的任務運行器。以下是與上述命令相同的構建:
await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out',
})
Bun 具有標準的測試運行器,類似於 Deno 和 Node.js 20。運行bun test
會執行如下命名的腳本:
*.test.{js|jsx|ts|tsx}
*_test.{js|jsx|ts|tsx}
*.spec.{js|jsx|ts|tsx}
*_spec.{js|jsx|ts|tsx}
無需 nodemon 等工具,因爲bun
具有--watch
標誌,可在修改依賴文件時重新啓動腳本或測試。重新啓動速度如此之快,以至於可以在每次按鍵時進行實時重新加載。(是否實用而不會分散注意力是另一回事!)
實時重新加載不太美觀!(警告:內容閃爍!) 查看原始動畫 GIF。
類似的—hot
模式也可用,Bun 會監視更改並重新加載模塊。所有文件都將重新評估,但全局狀態保持不變。
項目.env
文件中包含的環境變量會自動加載和解析,使它們在 Bun 應用程序中可用,因此無需使用 dotenv 等包。
除了自己的 Bun APIs,用於網絡、文件訪問、子進程等方面,Bun 還支持:
- Web API
,例如fetch
、URL
、blob
、WebSocket
、JSON
、setTimeout
和事件。
- Node.js 兼容性 API,例如
console
、assert
、dns
、http
、path
、stream
和util
,以及全局變量,包括__dirname
和__filename
*。Bun 聲稱已經完全實現了最常用 API 的 90%,儘管您應該仔細檢查與項目特定的 API。
最後,Bun 具有本機的 SQLite3 客戶端——bun:sqlite,這可以減少某些項目中所需的依賴項數量。
安裝 Bun
Bun 可以作爲一個單一的二進制文件安裝在 Linux、macOS 和 Windows WSL 上,使用 curl:
curl -fsSL <https://bun.sh/install> | bash
它也可以通過 Node 包管理器安裝:
npm install -g bun
或者通過 macOS 上的 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,只需刪除 ~/.bun
二進制文件和緩存目錄:
rm -rf ~/.bun
然後更新您的 shell 配置文件(.bashrc
、.zshrc
或類似文件),以從 $PATH
變量中刪除 ~/.bun/bin
的引用。
使用 Bun
如果您從項目的開始使用 Bun,它是可靠的。速度比 Node.js 更快,儘管除非您的應用程序執行特定的密集任務,如大量的 SQLite 處理或 WebSocket 消息傳遞,否則不太可能看到顯著的性能提升。
對於較小、較簡單的項目,Node.js 的兼容性很好,我成功地使用 bun start
啓動了一些腳本,而沒有進行任何更改。但對於更復雜的應用程序,可能會失敗,並生成在 node_modules
層次結構深處生成的晦澀錯誤消息。
Bun vs Deno vs Node.js
Deno 解決了 Node 的許多缺點,但開發人員並不一定感到有必要切換:
-
Deno 不支持 Node 的第三方模塊。
-
從 Node.js 遷移到 Deno 需要學習新的技術。
-
雖然 Deno 提供了更好的開發體驗,但 Node.js 已經足夠好用。
現在,Deno 已經添加了 Node.js 兼容選項。這是讓開發人員轉向 Deno 的最簡單方法,但與此同時,Node.js 也採用了 Deno 的一些功能,包括 ES 模塊、本地測試運行程序和--watch
模式。
Bun 採取了不同的方法,旨在成爲一個快速、與 Node 兼容的引擎,具有 Deno 的先進功能。跡象是令人鼓舞的,但還沒有完全達到目標:
-
性能很好,但很少有開發人員抱怨 Node.js 的速度。
-
兼容性很好,但在不同的 JavaScript 引擎中支持所有 Node.js 模塊將是一項挑戰。JavaScriptCore 是否能夠跟上 V8 的發展,而投入遠遠少於 V8?
-
Bun 有潛力替代您的工具套件,但尚未提供與 Deno 中找到的完整範圍相匹配的功能。
Bun 與 Node.js 的兼容性
對於較小、較簡單的項目,與 Node.js 的兼容性通常很好。您可能可以啓動一些腳本,而不需要進行任何更改,只需使用bun start
代替npm start
。
Bun 支持:
-
內置 Node.js 模塊和 API,如
fs
、path
、http
、console
、assert
等 -
全局變量和對象,如
__dirname
和process
-
Node.js 模塊解析算法,以在
node_modules
中查找文件
Bun 1.0 聲稱可以運行 “幾乎任何野外的 Node.js 應用程序”。我尚未完全相信;複雜的應用程序可能會由於在第三方模塊中生成的晦澀錯誤消息而失敗。
ES 模塊和 CommonJS 兼容性
Bun 支持 ESM 和 CommonJS 兩種模塊系統,還支持頂級await
。ESM 在 Node.js 中花了幾年時間才推出,生態系統仍然以 CommonJS 爲主導。使用 Bun,無需特定的文件擴展名(.js
、.cjs
、.mjs
)或在package.json
中的"type": "module"
。您可以在任何文件中交替使用import
或require()
!
在內部,Bun 將所有模塊都轉換爲 CommonJS,並實現了 Node 的node_modules
解析算法。是否如預期地工作是另一回事:
-
ES6 模塊會在執行代碼之前預先解析,以解析更多導入。動態導入是可能的,但應該只被視爲最後的選擇。
-
CommonJS 模塊在執行代碼時按需加載依賴項。動態導入問題較少。
在某些應用程序中,執行順序可能至關重要,這也是 Node.js 限制您在單個文件中使用 EMS 或 CommonJS 的原因。
Web API
Bun 具有內置對瀏覽器中可用的 Web 標準 API 的支持,例如fetch
、Request
、Response
、URL
、blob
、WebSocket
、JSON
、setTimeout
和ReadableStream
。Deno 將這些 API 引入其服務器運行時,使 Web 編碼更加一致。Node.js 正在趕上,但像fetch
這樣的功能最近纔在 18 版中加入。
Bun API
Bun 附帶了高度優化的用於常見操作的標準 API,例如文件讀取、文件寫入、HTTP 服務、SQLite 查詢和密碼哈希。
WebSockets 支持 HTTP,無需第三方模塊,例如ws
:
Bun.s
erve({
port: 8000,
fetch(request) {
return new Response('Hello from the Bun server!');
},
websocket: {
open(ws) { ... },
message(ws, data) { ... },
close(ws, code, reason) { ... },
}
});
TypeScript 和 JSX 支持
與 Deno 一樣,Bun 在運行時內置了 JavaScript 轉譯器。您可以在不需要第三方依賴項的情況下運行 JavaScript、TypeScript、JSX 或 TSX 文件。例如:
bun index.ts
bun index.jsx
bun index.tsx
包管理
您可以直接在任何 Node.js 項目中使用 Bun 作爲npm
的替代品。例如:
bun install
bun add <package> [--dev|--production|--peer]
bun remove <package>
bun update <package>
Bun 將模塊緩存到~/.bun/install/cache/
,並使用硬鏈接將它們複製到項目的node_modules
目錄中。因此,您系統上的所有項目都引用相同庫的單個實例。這可以減少磁盤空間使用,並將安裝性能提高多達 30 倍。
實時重載
無需像 nodemon 這樣的工具,因爲bun
可執行文件具有-watch
標誌,可以在修改文件時重新啓動腳本或測試。
還提供了類似的--hot
模式,其中 Bun 會監視更改並進行軟重載模塊。所有文件都將重新評估,但全局狀態保持不變。
測試
Bun 提供了與 Jest 兼容的bun:test
測試運行器,支持快照測試、模擬和代碼覆蓋。例如:
import { test, expect } from "bun:test";
test('2 + 2', () => {
expect(2 + 2).toBe(4);
});
從 Jest 或 Vitest 遷移非常簡單,因爲來自@jest/globals
或vitest
的導入會在內部重新映射到bun:test
。不應該需要進行代碼更改。
運行bun test
會執行以下命名的腳本:
*.test.{js|jsx|ts|tsx}
*_test.{js|jsx|ts|tsx}
*.spec.{js|jsx|ts|tsx}
*_spec.{js|jsx|ts|tsx}
腳本捆綁
Bun 是一個 JavaScript 和 TypeScript 捆綁器和代碼縮小工具,可以針對瀏覽器、Node.js 和其他平臺的代碼進行目標定位。它受到 esbuild 的啓發,並提供了一個兼容的插件 API:
// 簡單的構建
Bun.build({
entrypoints: ['index.js'],
outdir: 'build'
});
基準測試顯示,與 Go 編譯的 esbuild 相比,Bun 的性能可以快兩倍,而且節省的縮小程度相似。
與 esbuild 不同,Bun 不支持 CSS 捆綁,但考慮到有一個通用的插件 API,這很可能會到來...
通用插件 API
Bun 的插件 API 是通用的:它適用於捆綁器和運行時。您可以定義插件以攔截導入並執行自定義加載邏輯。以下示例實現了對.yaml
文件的導入:
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' };
});
},
});
啓動和執行速度
與npm run <script>
相比,使用bun run <script>
通常會快 150 毫秒啓動應用程序。這可能是一個小的改進,但是比 Node.js 快 4 倍,當您運行許多命令和構建腳本時會非常明顯。當使用 TypeScript 時,性能改進將更爲顯著,因爲沒有編譯步驟。
Bun 還提供以下關於 Node.js 性能的聲稱:
-
比
npx
快 5 倍 -
文件讀取速度快 10 倍(使用
Bun.read()
) -
文件寫入速度快 3 倍(使用
Bun.write()
) -
提供 HTTP 請求時,速度快 4 倍(使用
Bun.serve()
) -
SQLite 查詢速度快 4 倍(使用
bun:sqlite
) -
在測試時比 Jest 快 13 倍
-
在測試時比 Vitest 快 8 倍
對於捆綁,Bun 是:
-
幾乎比 esbuild 快兩倍
-
比 Parcel 2 快 150 倍
-
比使用 Terser 的 Rollup 快 180 倍
-
比 Webpack 快 220 倍
您不太可能在每個項目中都看到這樣的提升,但 Bun 應該能夠改善您的開發體驗
實驗性 Windows 版本
Bun 的本機構建將很快提供給 Windows 用戶。這是一個高度實驗性的版本,僅支持 JavaScript 運行時,沒有性能優化。像包管理器、測試運行器和捆綁器等功能都已禁用,直到它們變得穩定爲止。
目前,Windows 用戶可以在 Windows 子系統 Linux(WSL) 上安裝 Bun,這仍然是進行任何重型 JavaScript 工作的最佳選擇。
總結:您應該嘗試使用 Bun 嗎?
Bun 是一個成熟的 JavaScript 運行時,但對於關鍵任務或傳統應用程序,Node.js 仍然是首選。您可以嘗試使用 bun start
運行您的應用程序,但是代碼庫越大,執行而無需修改的機會就越小。
對於新項目來說,Deno 可能比 Bun 更好,因爲它更加成熟且功能更完整。
Bun 很棒,而且正在積極開發,但它是新的。運行時是穩定的,但在這個階段,很少有人會押注它的長期未來。儘管如此,Bun 提出了一些有趣的想法,我希望 Node.js 和 Deno 團隊都會考慮採納(CLI API 和自動加載的 .env
請注意!)
另外,我喜歡 Bun 的名稱,但在搜索資源時可能會有些困難。ChatGPT 大膽地聲明:“沒有一個被廣泛知曉的名爲'Bun' 的 JavaScript 運行時。據我所知,JavaScript 生態系統中沒有這樣的技術。” 這可能是因爲後續數據有限,儘管某些問題會返回 Bun 的響應並對錯誤表示道歉!
我懷疑我們正走向一個同構的服務器端 JavaScript 時代,在這個時代,模塊開發人員試圖編寫與所有運行時兼容的代碼:Node.js、Deno、Bun、無服務器、邊緣、嵌入式等等。我們最終可能會達到一個 JavaScript 運行時基本上可以互換使用的程度,就像今天的瀏覽器一樣。
Bun 版本 1.0 里程碑在技術上可能沒有太多意義,鑑於與 0.8 版本相比的微小更改。但心理上的差異更大:Bun 感覺上 更完整、更可用。更多開發人員將考慮將其用於自己的項目的運行時和工具集。
Deno 最初走了自己(不錯的)方向,但不得不後退。對於許多 Node.js 開發人員來說,它過於激進和不兼容。在項目中從 Node.js 切換到 Deno 仍然不是一件您應該考慮而不接受後果的事情。
Bun 從一開始就提供了兼容性和速度,這在使用不同的 JavaScript 引擎的情況下是一項重大成就。它是否能夠實現接近 100% 的 Node.js 兼容性還有待觀察,但您可以考慮將其用於傳統項目中工具集的一部分。
Bun 的性能聲稱令人印象深刻,但很少有人抱怨原始 Node.js 的性能,特別是當它在每個版本中都有所提高時。一些框架可能較慢,但這通常是由於膨脹而不是運行時的固有故障。
目前,Node.js 仍然是無可爭議的 JavaScript 冠軍。選擇 Node.js 的人很少會因此而被解僱,但 Bun 避免了一些 Deno 的錯誤,並迅速成爲一個吸引人的選擇。
作者:@Craig Buckler
翻譯原文:https://www.sitepoint.com/bun-javascript-runtime-introduction
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/KYN85kqVnyusE3c7wlhSAA