Bun

モチベーション
- Bunをざっくり知る
- Bunをざっくり使う
- Bunの内部を知る
- そもそもNode.jsの仕様と歴史を追ってみる( https://zenn.dev/highgrenade/scraps/15d9f44cd91c24 )
- Bun + Honoを使ってみる( https://zenn.dev/highgrenade/scraps/6e5fb1f51644aa )
- Bun + Next.jsなどのフロントエンドフレームワークを使ってみる
- Hono + htmx + Cloudflare
参考
この人の順番よさげ
Zig気になる
タイムリーで気になる

Bunをざっくり知る
公式とその他資料を読んだ
特徴
- Node.js の代替として設計された「速くて All in One な Javascript ランタイム」
- Zig で開発されており、内部のJSエンジンで JavaScriptCore を利用
- 起動時間とメモリ使用量が大幅に削減
現在、最も一般的なJSエンジンは、V8(Google製)とJavaScriptCore(Apple製)
JavaScriptCoreはV8より速い傾向があるよう
Bunコマンドラインツールについて
下記が実装されている
- スクリプトランナー
- Node.js 互換のパッケージ マネージャー
- テスト ランナー
ほとんど変更を必要なく、既存の Node.js プロジェクトで使用可能。
既存ツールよりも大幅に高速。
コマンド一覧
bun run start # run the `start` script
bun install <pkg> # install a package
bun build ./index.tsx # bundle a project for browsers
bun test # run tests
bunx cowsay "Hello, world!" # execute a package

Bunをざっくり触る
Bun本体のインストールについて
# バージョンを指定しないならこちらでok
curl -fsSL https://bun.sh/install | bash
# バージョンを指定する場合
curl -fsSL https://bun.sh/install | bash -s "bun-v1.0.0"
source $HOME/.zshrc
インストールok
bun -v
1.0.4
Hello World
index.ts
console.log('Hello Bun!')
bun run index.ts
※ bun run js/ts ファイル名で 実行ができる
※ ts はコンパイルしなくてもデフォルトで動作する
Hello Bun!
パッケージマネージャについて
bunもpackage.jsonを利用する
scriptsも同じで、下記に記述することで bun run ◯◯ が利用可能
startやdevなどの予約されているワードに関しては、bun start、bun devで実行可能。
"scripts": {
"a": "bun run index.ts",
"start": "bun run index.ts",
"dev": "bun run index.ts"
},
パッケージ追加
bun add ◯◯
bun add -D ◯◯
Webサーバ用の環境作成
ディレクトリ作成 → bun init
mkdir bun_quickstart
cd bun_quickstart
bun init
初回ディレクトリこんな感じ
簡易Webサーバ(Hello Bun)
const server = Bun.serve({
port: 3000,
fetch(req) {
return new Response('Hello Bun!')
},
})
console.log(`Listening on http://localhost:${server.port} ...`)
bun start でブラウザ表示ok
パッケージ追加
figlet → 引数の文字をアスキーアートにするもの
bun add figlet
bun add -d @types/figlet # TypeScript users only
index.ts
import figlet from 'figlet'
const server = Bun.serve({
port: 3000,
fetch() {
const body = figlet.textSync('Bun!')
return new Response(body)
},
})
console.log(`Listening on http://localhost:${server.port} ...`)
再度 bun start

Bunの中身を知る
Bunの設計について
Bun は、今日の JavaScript エコシステムを念頭に置いてゼロから設計されている
- スピードについて、Bun プロセスは現在 Node.js よりも 4 倍高速
- TypeScript と JSX をデフォルトサポート
- .jsx、.ts、ファイルを直接実行可能
- Bunトランスパイラは、実行前にts/tsxを標準のjsに変換
- ESM と CommonJS の互換性
- Bun は ES モジュールを推奨
- CommonJS もサポート
- npm 上の何百万ものパッケージは依然として CommonJS を必要とするため
- Web標準API
- fetch、WebSocket、ReadableStreamなどの標準 Web API で実装されている
- Apple製のJavaScriptCoreエンジンを利用の為、一部の API はSafariの様なURL直接使用の形をとる
- Node.js との互換性
- Node.js 組み込みモジュール(process、path、fs、httpなど)との完全な互換性を目指している
- これは進行中のステータスで、まだ完了してない
- 現在のステータスについては、互換性ページを参照
Bun は単なるランタイムではない。
長期的な目標は、パッケージマネージャー、トランスパイラー、バンドラー、スクリプトランナー、テスト ランナーなどを含む、JavaScript/TypeScript製アプリ構築の為の統合されたインフラストラクチャ ツールキットになること。
インストーラが高速な理由
npm installからbun installに切り替えると、インストールが最大 25 倍高速になります。
Global cache
レジストリからダウンロードされたパッケージは、 ~/.bun/install/cacheのグローバル キャッシュに保存されます。
これらは
再ダウンロードを最小限に抑える
パッケージインストール時に、package.jsonで指定された範囲内のバージョンがすでに含まれている場合、
Bunはキャッシュされたパッケージを使用します。
高速コピー
パッケージがキャッシュにダウンロードされた後、それらのファイルをnode_modulesにコピーする必要があります。
Bun は、このタスクを実行するために利用可能な最速の syscall を使用します。
Linux ではハードリンクを使用します。
macOS では、clonefileを使用します。
ディスク容量の節約
Bun はハードリンクを使用してモジュールを Linux 上のプロジェクトnode_modulesディレクトリに「コピー」するため、パッケージの内容はディスク上の 1 つの場所にのみ存在し、node_modulesのディスク容量が大幅に削減されます。
この利点は、パフォーマンス上の理由からclonefileを使用する macOS には適用されません。
Lockfile
bun installを実行するとbun.lockbというロックファイルが作成される。
この中身は、package-lock.jsonやyarn.lockとは違い、バイナリになっている。
なぜバイナリなのか?
パフォーマンスのため。
バイナリになることで、保存とロードが高速に処理が出来る。
ロックファイルを精査するには?
bun install -y を実行すると yarn.lock が生成される。
なぜ速いのか
バイナリ化する際に1次元の配列に最適化したり、文字列重複の排除などを行う為
バンドラーが高速な理由
esbuildの1.75倍、Parcel2の150倍、Rollup + Terserの180倍、Webpackの220倍の速度
Bun.build
Bunは、WebpackやViteなどのサードパーティツールに頼らずともデフォルトでbuildが可能。
また、TypeScriptのトランスパイルもNode.jsの場合はtypescriptパッケージを利用するが、Bunはそれを必要とせず、デフォルトでトランスパイルが可能。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './build',
});
ローダー
デフォルトでローダーも用意されている。
高速なバンドラーのesbuildから着想を得ている
参考記事