本記事はQiita Advent Calender 2025 わたなべの3日目です!
3日目は、私渡邊が作成します!
3日目はAntigravityで無重力なアプリを作ってみようと思っていましたが、優先度の高いトピックが舞い込んできたので、それは後日に回してBunに関する記事を書いてみます!
という感じで緊急で記事書いてるんですけど、Claude Codeで有名なAnthropicによるBunの買収が発表されました!
Xでも騒がれていたものの、Vibe cordingからClaude Codeを知った方はもしかしてBunを知らないのでは?と思い、簡単にBunを紹介する記事を書いてみます!
- Claude Codeは知ってるけどBunは初めて聞いた
- JavaScriptは知ってるけど、Bunは知らない
という方には是非とも読んでいただきたいです。
ただ、TypeScriptとReact, preactあたりの知識がないと難しい部分はあるかもしれませんので、適宜調べていただければと思います。
最速の肉まん|Bun
Bunと書いてバンと読みます
bun!
Bunを一言で表すと、高速なJavaScriptオールインワンパッケージでしょうか。
自分の記事を見返すと、v0.6の頃から利用していました。当時からスピードにこだわって開発されていた印象です。ライブラリのインストールや実行速度などのベンチマークを積極的に発信していたのが記憶に残っています。
オールインワンなパッケージ
トップページにあるように、Bunはそれひとつで色々できます。
- JavaScript Runtime(Node.js)
- Package Manager(npm)
- Test Runner(Vitest)
- Bundler(Vite)
という感じで、プロジェクトのセットアップから開発時の実行、テストの実行、ビルドまでできると。
すごいですね!
TypeScriptネイティブ
今では割と普通になってきていますが、2~3年前はTypeScriptがそのまま動くというのは非常にありがたかったですね。
豊富なBuilt-in API
- Node.jsにもあるような
fetch,node:fsに相当するfile,ReadableStream -
Bun.serveでHTTP serverやwebsocket -
SQL,S3,Redisのclient
などといった機能があります
オールインワンで高速、依存も低く実装できるということで、プロトタイピングとの相性は抜群ですね!
100% Bun でチャットアプリを作ってみる
という感じの説明を聞いてもふ〜んで終わってしまうので、実際に動くものを作ってみましょう。
依存ゼロでチャットアプリケーションを実装してみます。
今回、デプロイ先はfly.ioを採用して、実際に触れるものをGPTが作ってみます!
1. セットアップ
お好きなフォルダに移動して
mkdir bun-chat
cd bun-chat
bun init
を実行
✓ Select a project template: Blank
+ .gitignore
+ index.ts
+ tsconfig.json (for editor autocomplete)
+ README.md
To get started, run:
bun run index.ts
bun install v1.3.3 (274e01c7)
+ @types/bun@1.3.3
+ typescript@5.9.3
5 packages installed [2.28s]
という感じでセットされるので、
bun index.ts
を実行するとHello via Bun!が表示される、というところからスタートしました。
2. 要件定義とタスクの設定。
GPTと話しながら、次のような感じにして/docs/spec.mdに配置しました。
ということでざっくり概要としては
- サーバーは
Bun.serve- チャットのリアルタイム更新は
ws(bunのwebsocket)- dbは
bun:sqliteを配置(デプロイすると消えるけどプロトタイプなのでまあ)- フロントはbunの
JSXを利用
- ただし、honoのようなJSX complierはないようなので自前実装(あくまでJSXをJSにするだけで、
createElement的なものがないらしい)- もちろんHooksもないので
useState,useEffectも自前実装- 認証など細かいところは実装しない(入室の名前だけ管理)
という感じの仕様で行ってみました。
本当はbun-plugin-tailwindでCSSはtailwindにしたかったのですが、試しに動かしたところうまく動かず、そもそもpluginとはいえtailwindを入れたらbun100%と言えるのか?という疑問を感じたので、普通のCSSにしました。どうせ自分で1から書くことはないし
3. Vibe Cording
❯ codex --version
codex-cli 0.65.0
{
"name": "bun-chat",
"module": "index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5"
},
"scripts": {
"typecheck": "bunx tsc --noEmit",
"build:client": "bun build src/client/index.tsx --outdir static --public-path /static",
"start": "bun run build:client && bun run index.ts"
}
}
# Repository Guidelines
These notes keep contributors aligned on how this Bun-based chat app is structured and built. Keep edits focused, small, and in line with the specs in `docs/spec.md`.
## Project Structure & Module Organization
- `index.ts`: entry point; will host `Bun.serve` HTTP + WebSocket handling and SQLite access.
- `docs/spec.md`: product and architecture requirements; treat as source of truth. `docs/tasks.md` lists setup to-dos. write[x] when finished the task.
- `tsconfig.json`: strict TypeScript configuration using bundler resolution and JSX enabled for Bun’s JSX runtime.
- `bun.lock`, `package.json`: dependency lock and metadata (TypeScript as peer, Bun types as dev dependency).
- Tests and assets are not yet present; co-locate future tests beside code (e.g., `chat.test.ts`).
## Build, Test, and Development Commands
- `bun install` — install dependencies.
- `bun run index.ts` — start the app entry. Add flags or scripts as needed when HTTP/WebSocket routes are implemented.
- `bun test` — run the test suite once tests exist; prefer fast, deterministic unit tests.
## Coding Style & Naming Conventions
- Language: TypeScript ES modules (`type: "module"`, `verbatimModuleSyntax: true`); use explicit file extensions in imports when TypeScript requires it.
- Indentation: 2 spaces; keep lines concise; favor `const` and arrow functions.
- JSX: use Bun’s JSX (no React/Preact). Keep components small and pure; prefer named exports for shared utilities.
- Lint/format: Bun-friendly defaults are acceptable; if adding a formatter, align with existing style before enforcing it.
## Testing Guidelines
- Use `bun test`; name files `*.test.ts`. Keep tests near implementation for clarity.
- Cover WebSocket message flow, SQLite queries (happy path + failure handling), and JSX rendering helpers.
- For integration-style tests, mock network/DB where possible to keep runs quick.
## Commit & Pull Request Guidelines
- Commits: short, imperative subjects (e.g., `Add websocket broadcast handler`, `Fix sqlite retention query`); group related changes.
- PRs: include a brief summary, linked issue (if any), commands run (`bun test`, `bun run index.ts`), and notes on manual steps or UI screenshots when relevant.
- Keep diffs minimal and aligned with `docs/spec.md`; call out deviations explicitly.
## Security & Configuration Tips
- Do not commit secrets or production URLs; prefer environment variables for credentials if added later.
- Sanitize user-provided chat content before rendering; treat WebSocket payloads as untrusted.
- SQLite files should live in a writable data path outside version control (e.g., `./data/app.db` in local dev).***
-
ほとんどデフォルトのまま、package.jsonのtypecheck, start scriptのみ変更。testは当然bun test。Bunですからね!
要件定義書/docs/spec.mdをもとに、/docs/tasks.mdも作成。
やってる人もいるかもしれませんが、
## 0. tasks0
- [ ] task
- [ ] task2
## 1. tasks1
- [ ] task
- [ ] task2
というstep形式と、[ ]のブランクを用意。完了したら[x]をAIエージェントに書かせるという形式で進捗管理しながら抜けもれを防いでいきました。
このtasks.mdはスタート時点では 5.Testingまで記述し、テストの状況と出力されたコードを見ながら、6以降を順次追加していった感じです。
サッと作りたかったのでTDD形式ではなく一気に実装してまとめてTestをする形式で進めました。実装でつまるところは特にありませんでしたね。
4. deploy
今回はfly.ioを選択しました。
Bunのアプリを丸ごとデプロイするので、Dockerでのコンテナ環境が望ましく、websoketを貼るので長時間の接続に向かないCloud Runは除外。
fly.ioRenderRailway
が候補になりましたが、Renderはコールドスタートが結構長く、Railwayは常時稼働すると無料が1ヶ月もたないことを考え、fly.ioに落ち着きました。
FROM oven/bun:1.3
WORKDIR /app
COPY bun.lock* package.json tsconfig.json ./
COPY index.ts ./
COPY src ./src
COPY static ./static
COPY docs ./docs
RUN bun install
RUN bun run build:client
EXPOSE 3000
ENV PORT=3000
CMD ["bun", "run", "index.ts"]
こんな感じでDockerfileは記述しました。GPTが。
6. プロトタイプ
![]()
こちらクリックして試せます
まあ、特にいうこともないチャットルーム1部屋です。
なんの変哲もないチャットといえばそうなのですが、Bunだけでつくって依存ゼロです!
❯ fly ssh console -a bun-chat
Connecting to machine... complete
root@machine:/app# ls
bun.lock docs node_modules src tsconfig.json
data index.ts package.json static
root@machine:/app# cat data/app.db
P++Ytablesqlite_sequencesqlite_sequenceCREATE TABLE sqlite_sequence(name,seq)?#?tablemessagesmessagesCREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
message TEXT NOT NULL,
ts INTEGER NOT NULL
????渡邊やあi2??"渡邊2こんばんは!i2??!1渡邊こんばんは!i2??
fly.ioはflyctlから立てているVMにSSH接続できるので中身を見ていますが、最終行にあるようにログはマシンの中の/data/app.dbのsqliteファイルに直書きしてます。まあ仕様通りという感じですね。
プロジェクト構成・リポジトリ
リポジトリがこちらで、それぞれのファイルの役割は次のような感じです!
-
index.ts
Bun を使ったサーバー処理をまとめたファイル。HTTP ルートの定義や WebSocket の接続処理を担当します -
src/db.ts
SQLite を扱うためのヘルパー関数や、チャットログの保存期間(Retention)に関する処理が入っています -
src/runtime/
独自に実装した軽量 JSX ランタイム。クライアント側・サーバー側で使う UI コンポーネントの基盤となる仕組みです -
src/client/
クライアント側(ブラウザ側)の TSX ファイル群。ホーム画面やチャット画面などの UI を実装しています -
src/server/shell.tsx
HTML 全体の枠(シェル)を生成するコンポーネント。サーバー側レンダリングで利用されます -
static/style.css
プロジェクト全体で共通して使う CSS スタイル -
static/index.js
クライアント用にビルドされたバンドル済み JavaScript。bun run build:clientによって生成されます -
docs/
仕様書やタスク管理、技術メモなどをまとめたドキュメント類
流石にpreactくらいは使った方がいいけど・・・
JSX complierまで自前実装する必要はなかったかもしれませんが、それでも依存関係なしでここまで作れるとすごいですね!
npm installも怖いご時世ですので、Bun使ってみてはいかがでしょうか?
