Bun 1.0 正式發(fā)布,爆火的前端運(yùn)行時(shí),速度遙遙領(lǐng)先!
9 月 8 日,前端運(yùn)行時(shí) Bun 1.0 正式發(fā)布,如今,Bun 已經(jīng)穩(wěn)定并且適用于生產(chǎn)環(huán)境。Bun 不僅是一個(gè)專注性能與開發(fā)者體驗(yàn)的全新 JavaScript 運(yùn)行時(shí),還是一個(gè)快速的、全能的工具包,可用于運(yùn)行、構(gòu)建、測(cè)試和調(diào)試JavaScript和TypeScript代碼,無論是單個(gè)文件還是完整的全棧應(yīng)用。
2022 年 7 月,Bun 發(fā)布,隨即爆火,成為年度最火的前端項(xiàng)目:
Bun 的流行程度伴隨著在去年夏天發(fā)布的第一個(gè) Beta 版而爆炸性增長(zhǎng):僅一個(gè)月內(nèi),就在 GitHub 上獲得了超過兩萬顆 Star。
Bun 不僅僅是一個(gè)運(yùn)行時(shí)。它也是:
- 一個(gè)包管理器 (類似 Yarn、 NPM、 PNPM)
- 一個(gè)構(gòu)建工具 (類似 Webpack、 ESBuild、 Parcel)
- 一個(gè)測(cè)試運(yùn)行器
- ...
所以 Bun 可以通過讀取 package.json 來安裝依賴項(xiàng)。Bun 還可以運(yùn)行腳本。不管它做什么都比其他工具更快。Bun 在 JavaScript 生態(tài)系統(tǒng)的許多方面都有新的嘗試,其中的重點(diǎn)是性能。它優(yōu)先支持標(biāo)準(zhǔn)的 Web API,如 Fetch。它也支持許多 Node.js APIs,使其能與大多數(shù) NPM 包兼容。
安裝 Bun:
// npm
npm install -g bun
// brew
brew tap oven-sh/bun
brew install bun
// curl
curl -fsSL https://bun.sh/install | bash
// docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun
更新 Bun:
bun upgrade
下面就來看看 Bun 是什么,1.0 版本帶來了哪些更新!
Bun:全能的工具包
JavaScript 成熟、發(fā)展迅速,并且有著充滿活力和激情的開發(fā)者社區(qū)。然而,自14年前Node.js發(fā)布以來,JavaScript 的工具鏈變得越來越龐大和復(fù)雜。這是因?yàn)樵诎l(fā)展過程中,各種工具被逐漸添加進(jìn)來,但沒有一個(gè)統(tǒng)一的集中規(guī)劃,導(dǎo)致工具鏈缺乏整體性和效率,變得運(yùn)行緩慢和復(fù)雜。
Bun 為什么會(huì)出現(xiàn)?
Bun的目標(biāo)很簡(jiǎn)單,就是要消除JavaScript工具鏈的緩慢和復(fù)雜性,但同時(shí)保留JavaScript本身的優(yōu)點(diǎn)。Bun希望讓開發(fā)者繼續(xù)使用喜歡的庫和框架,并且無需放棄已經(jīng)熟悉的規(guī)范和約定。
為了實(shí)現(xiàn)這個(gè)目標(biāo),可能需要放棄一些在使用Bun之后變得不再必要的工具:
- Node.js:Bun 的一個(gè)可以直接替代的工具,因此不再需要以下工具:
- node
- npx:Bun 的 bunx 命令比 npx 快5倍。
- nodemon:Bun 內(nèi)置了監(jiān)聽模式,無需使用 nodemon。
- dotenv、cross-env:Bun 默認(rèn)支持讀取.env文件的配置。
轉(zhuǎn)譯器:Bun 可以運(yùn)行.js、.ts、``.cjs、.mjs、.jsx和.tsx文件,因此不再需要以下工具:
- tsc:仍然可以保留它用于類型檢查!
- babel、.babelrc、@babel/preset-*:不再需要使用 Babel 進(jìn)行轉(zhuǎn)譯。
- ts-node、ts-node-esm:Bun 可以直接運(yùn)行 TypeScript 文件。
- tsx:Bun可以直接運(yùn)行 TypeScript 的 JSX 文件。
- 構(gòu)建工具:Bun 具有一流的性能和與esbuild兼容的插件API,因此不再需要以下工具:
- esbuild
- webpack
- parcel, .parcelrc
- rollup, rollup.config.js
- 包管理器:Bun 是一個(gè)與 npm 兼容的包管理器,可以使用熟悉的命令。它可以讀取 package.json文件并將依賴寫入node_modules目錄,與其他包管理器的行為類似,因此可以替換以下工具:
- npm, .npmrc, package-lock.json
- yarn,yarn.lock
- pnpm, pnpm.lock, pnpm-workspace.yaml
- lern
- 測(cè)試庫:Bun是一個(gè)支持Jest的測(cè)試運(yùn)行器,具有快照測(cè)試、模擬和代碼覆蓋率等功能,因此不再需要以下測(cè)試相關(guān)的工具:
- jest, jest.config.js
- ts-jest, @swc/jest, babel-jest
- jest-extended
- vitest, vitest.config.ts
盡管這些工具都有自己的優(yōu)點(diǎn),但使用它們時(shí)往往需要將它們?nèi)考稍谝黄穑@會(huì)導(dǎo)致開發(fā)過程變得緩慢和復(fù)雜。而Bun通過成為一個(gè)單一的工具包,提供了最佳的開發(fā)者體驗(yàn),從性能到API設(shè)計(jì)都力求做到最好。
Bun:JavaScript 運(yùn)行時(shí)
Bun是一個(gè)快速的JavaScript運(yùn)行時(shí)。旨在提供出色的性能和開發(fā)體驗(yàn)。它的設(shè)計(jì)旨在解決開發(fā)過程中的各種痛點(diǎn),使開發(fā)者的工作更加輕松和愉快。
與Node.js兼容
Bun 是可以直接替代 Node.js 的。這意味著現(xiàn)有的 Node.js 應(yīng)用和 npm 包可以在 Bun 中正常工作。Bun 內(nèi)置了對(duì) Node.js API 的支持,包括:
- 內(nèi)置模塊,如fs、path和net
- 全局對(duì)象,如__dirname和process
- Node.js 模塊解析算法(例如node_modules)
盡管與 Node.js 完全兼容是不可能的,特別是一些依賴于v8版本的特性,但 Bun 幾乎可以運(yùn)行任何現(xiàn)有的 Node.js 應(yīng)用。
Bun經(jīng)過了與最受歡迎的Node.js包的兼容性測(cè)試,支持與Express、Koa、Hapi等服務(wù)端框架以及其他流行的全??蚣艿臒o縫集成。開發(fā)者可以放心地在Bun中使用這些庫和框架,并享受到更好的開發(fā)體驗(yàn)。
使用Next.js、Remix、Nuxt、Astro、SvelteKit、Nest、SolidStart和Vite構(gòu)建的全棧應(yīng)用可以在Bun中運(yùn)行。
速度
Bun的速度非???,啟動(dòng)速度比 Node.js 快 4 倍。當(dāng)運(yùn)行TypeScript文件時(shí),這種差異會(huì)更加明顯,因?yàn)樵贜ode.js中運(yùn)行TypeScript文件需要先進(jìn)行轉(zhuǎn)譯才能運(yùn)行。
Bun在運(yùn)行一個(gè)簡(jiǎn)單的"Hello World" TypeScript文件時(shí),比在Node.js中使用esbuild運(yùn)行速度快5倍。
Bun使用的是Apple的WebKit引擎,而不是像Node.js和其他運(yùn)行時(shí)一樣使用Google的V8引擎。WebKit引擎是Safari瀏覽器的核心引擎,每天被數(shù)十億的設(shè)備使用。它經(jīng)過了長(zhǎng)時(shí)間的實(shí)際應(yīng)用和測(cè)試,具備快速和高效的特性。
TypeScript 和 JSX 支持
Bun內(nèi)置了JavaScript轉(zhuǎn)譯器,因此可以運(yùn)行JavaScript、TypeScript甚至JSX/TSX文件,無需任何依賴。
// 運(yùn)行 TS 文件
bun index.ts
// 運(yùn)行 JSX/TSX 文件
bun index.tsx
ESM 和 CommonJS 兼容
從CommonJS到ES模塊的過渡一直是緩慢而充滿挑戰(zhàn)的。在引入ESM之后,Node.js花了5年時(shí)間才在沒有--experimental-modules標(biāo)志的情況下支持它。盡管如此,生態(tài)系統(tǒng)仍然充斥著CommonJS。
Bun 同時(shí)支持這兩種模塊系統(tǒng)。無論是使用CommonJS的.js擴(kuò)展名、.cjs擴(kuò)展名,還是使用ES模塊的.mjs擴(kuò)展名,Bun都會(huì)進(jìn)行正確的解析和執(zhí)行,而無需額外的配置。
甚至可以在同一個(gè)文件中同時(shí)使用import和require():
import lodash from "lodash";
const _ = require("underscore");
Web API
Bun 內(nèi)置支持瀏覽器中可用的Web標(biāo)準(zhǔn)API,如fetch、Request、Response、WebSocket和ReadableStream等。
const response = await fetch("https://example.com/");
const text = await response.text();
開發(fā)者不再需要安裝像node-fetch和ws這樣的包。Bun內(nèi)置的 Web API 是使用原生代碼實(shí)現(xiàn)的,比第三方替代方案更快速和可靠。
熱重載
Bun提供了熱重載功能,可以在開發(fā)過程中實(shí)現(xiàn)文件的自動(dòng)重新加載。只需在運(yùn)行Bun時(shí)加上--hot
參數(shù),當(dāng)文件發(fā)生變化時(shí),Bun 就會(huì)自動(dòng)重新加載你的應(yīng)用,從而提高開發(fā)效率。
bun --hot server.ts
與像nodemon這樣完全重新啟動(dòng)整個(gè)進(jìn)程的工具不同,Bun 在重新加載代碼時(shí)不會(huì)終止舊進(jìn)程。這意味著HTTP和WebSocket連接不會(huì)斷開,并且狀態(tài)不會(huì)丟失。
插件
Bun 被設(shè)計(jì)為高度可定制的。 可以定義插件來攔截導(dǎo)入操作并執(zhí)行自定義的加載邏輯。插件可以添加對(duì)其他文件類型的支持,比如.yaml或.png。插件API的設(shè)計(jì)靈感來自于esbuild,這意味著大多數(shù)esbuild插件在 sBun 中也可以正常工作。
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內(nèi)部提供了針對(duì)開發(fā)者最常用需求的標(biāo)準(zhǔn)庫API,并對(duì)其進(jìn)行了高度優(yōu)化。與Node.js的API不同,Node.js的API存在著向后兼容的考慮,而Bun的原生API則專注于提供更快速和更易于使用的功能。
Bun.file()
使用Bun.file()可以懶加載位于特定路徑的文件。
const file = Bun.file("package.json");
const contents = await file.text();
它返回一個(gè)擴(kuò)展了 Web 標(biāo)準(zhǔn)File的BunFile對(duì)象。文件內(nèi)容可以以多種格式進(jìn)行懶加載。
Bun.serve({
port: 3000,
fetch(request) {
return new Response("Hello from Bun!");
},
});
Bun每秒可以處理的請(qǐng)求比 Node.js 多 4 倍。
也可以使用tls選項(xiàng)來配置TLS(傳輸層安全協(xié)議)。
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"),
}
});
Bun內(nèi)置了對(duì)WebSocket的支持,只需要在websocket中定義一個(gè)事件處理程序來實(shí)現(xiàn)同時(shí)支持HTTP和WebSocket。而Node.js沒有提供內(nèi)置的WebSocket API,所以需要使用第三方依賴庫(例如ws)來實(shí)現(xiàn)WebSocket的支持。因此,使用Bun可以更加方便和簡(jiǎn)單地實(shí)現(xiàn)WebSocket功能。
Bun.serve({
fetch() { ... },
websocket: {
open(ws) { ... },
message(ws, data) { ... },
close(ws, code, reason) { ... },
},
});
Bun 每秒可以處理的消息比在 Node.js 上使用 ws 庫多 5 倍。
bun:sqlite
Bun內(nèi)置了對(duì) SQLite 的支持。它提供了一個(gè)受到better-sqlite3啟發(fā)的API,但是使用本地代碼編寫,以達(dá)到更快的執(zhí)行速度。
import { Database } from "bun:sqlite";
const db = new Database(":memory:");
const query = db.query("select 'Bun' as runtime;");
query.get(); // => { runtime: "Bun" }
在 Node.js 上,Bun 執(zhí)行 SQLite 查詢操作的速度比better-sqlite3快 4 倍。
Bun.password
Bun 還支持一些常見但復(fù)雜的API,不用自己去實(shí)現(xiàn)它們。
例如,可以使用Bun.password來使用bcrypt或argon2算法進(jìn)行密碼哈希和驗(yàn)證,無需外部依賴。
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是一個(gè)包管理器。即使不使用Bun作為運(yùn)行時(shí)環(huán)境,它內(nèi)置的包管理器也可以加速開發(fā)流程。以前在安裝依賴項(xiàng)時(shí)需要盯著npm的加載動(dòng)畫,現(xiàn)在可以通過Bun的包管理器更高效地進(jìn)行依賴項(xiàng)的安裝。
Bun可能看起來像你熟悉的包管理器:
bun install
bun add <package> [--dev|--production|--peer]
bun remove <package>
bun update <package>
安裝速度
Bun的安裝速度比 npm、yarn 和 pnpm 快好幾個(gè)數(shù)量級(jí)。它利用全局模塊緩存來避免從npm注冊(cè)表中重復(fù)下載,并使用每個(gè)操作系統(tǒng)上最快速的系統(tǒng)調(diào)用。
運(yùn)行腳本
很可能你已經(jīng)有一段時(shí)間沒有直接使用 Node 來運(yùn)行腳本了。相反,通常使用包管理器(如npm、yarn等)與框架和命令行界面(CLI)進(jìn)行交互,以構(gòu)建應(yīng)用。
npm run dev
可以用bun run來替換npm run,每次運(yùn)行命令都能節(jié)省 150 毫秒的時(shí)間。
這些數(shù)字可能看起來很小,但在運(yùn)行命令行界面(CLI)時(shí),感知上的差異是巨大的。使用"npm run"會(huì)明顯感到延遲:
而使用bun run則感覺幾乎瞬間完成:
并不只是針對(duì)npm進(jìn)行比較。實(shí)際上,bun run <command>的速度比yarn和pnpm中相應(yīng)的命令更快。
腳本運(yùn)行 | 平均時(shí)間 |
npm run | 176ms |
yarn run | 131ms |
pnpm run | 259ms |
bun run | 7ms ?? |
Bun:測(cè)試運(yùn)行器
如果你以前在 JavaScript 中寫過測(cè)試,可能了解 Jest,它開創(chuàng)了“expect”風(fēng)格的API。
Bun有一個(gè)內(nèi)置的測(cè)試模塊bun:test,它與Jest完全兼容。
import { test, expect } from "bun:test";
test("2 + 2", () => {
expect(2 + 2).toBe(4);
});
可以使用bun test命令來運(yùn)行測(cè)試:
bun test
還將獲得 Bun 運(yùn)行時(shí)的所有優(yōu)勢(shì),包括TypeScript和JSX支持。
從Jest或Vite遷移很簡(jiǎn)單。@jest/globals或vitest的任何導(dǎo)入將在內(nèi)部重新映射到bun:test,因此即使不進(jìn)行任何代碼更改,一切也將正常運(yùn)行。
import { test } from "@jest/globals";
describe("test suite", () => {
// ...
});
在與 zod 的測(cè)試套件進(jìn)行基準(zhǔn)測(cè)試中,Bun比Jest快13倍,比Vite快8倍。
Bun的匹配器由快速的原生代碼實(shí)現(xiàn),Bun中的expect().toEqual()比Jest快100倍,比Vite快10倍。
可以使用bun test命令來加快 CI 構(gòu)建速度,如果在Github Actions中,可以使用官方的oven-sh/setup-bun操作來設(shè)置Bun。
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會(huì)自動(dòng)為測(cè)試失敗的部分添加注釋,以便在持續(xù)集成(CI)日志中更容易理解。這樣,當(dāng)出現(xiàn)測(cè)試失敗時(shí),可以直接從日志中讀取Bun提供的注釋,而不需要深入分析代碼和測(cè)試結(jié)果,從而更方便地檢查問題所在。
Bun:構(gòu)建工具
Bun是一個(gè)JavaScript和TypeScript的構(gòu)建工具和代碼壓縮工具,可用于將代碼打包成適用于瀏覽器、Node.js和其他平臺(tái)的形式。
bun build ./index.tsx --outdir ./build
Bun 受到了 esbuild 的啟發(fā),并提供了兼容的插件API。
import mdx from "@mdx-js/esbuild";
Bun.build({
entrypoints: ["index.tsx"],
outdir: "build",
plugins: [mdx()],
});
Bun 的插件 API 是通用的,這意味著它適用于打包工具和運(yùn)行時(shí)。所以前面提到的.yaml插件可以在這里使用,以支持在打包過程中導(dǎo)入.yaml文件。
根據(jù)esbuild的基準(zhǔn)測(cè)試,Bun比esbuild快1.75倍,比Parcel 2快150倍,比Rollup + Terser快180倍,比Webpack快220倍。
由于Bun的運(yùn)行時(shí)和打包工具是集成在一起的,這意味著Bun可以做其他打包工具無法做到的事情。
Bun引入了JavaScript宏機(jī)制,可以在打包時(shí)運(yùn)行JavaScript函數(shù)。這些函數(shù)返回的值會(huì)直接內(nèi)聯(lián)到打包文件中。
// 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;
}
// index.ts
import { getRelease } from "./release.ts" with { type: "macro" };
// release的值是在打包時(shí)進(jìn)行評(píng)估的,并且內(nèi)聯(lián)到打包文件中,而不是在運(yùn)行時(shí)執(zhí)行。
const release = await getRelease();
bun build index.ts
// index.ts
var release = await "bun-v1.0.0";
Bun:可以做更多事
Bun 在 macOS 和 Linux 上提供了原生構(gòu)建支持,但 Windows 一直是一個(gè)明顯的缺失。以前,在 Windows 上運(yùn)行 Bun 需要安裝 Windows 子系統(tǒng)來運(yùn)行Linux系統(tǒng),但現(xiàn)在不再需要。
Bun 首次發(fā)布了一個(gè)實(shí)驗(yàn)性的、專為Windows平臺(tái)的本地版本的 Bun。這意味著Windows用戶現(xiàn)在可以直接在其操作系統(tǒng)上使用 Bun,而無需額外的配置。
盡管Bun的macOS和Linux版本已經(jīng)可以用于生產(chǎn)環(huán)境,但Windows版本目前仍然處于高度實(shí)驗(yàn)階段。目前只支持JavaScript運(yùn)行時(shí),而包管理器、測(cè)試運(yùn)行器和打包工具在穩(wěn)定性更高之前都將被禁用。性能方面也還未進(jìn)行優(yōu)化。
Bun:面向未來
Bun 1.0 只是一個(gè)開始。Bun 團(tuán)隊(duì)正在開發(fā)一種全新的部署JavaScript和TypeScript到生產(chǎn)環(huán)境的方式,期待 Bun 未來更好的表現(xiàn)!