bun-expert について
bun-expert は、Bun を使う開発者向けのスキルです。ランタイム、パッケージ管理、テスト、バンドルに加え、Node.js からの移行や互換性の違いも案内します。
主な機能
- 01Bun ランタイム API の解説
- 02パッケージ管理とワークスペース
- 03bun:test のテストとモック
- 04ビルドとバンドラー設定
- 05Node.js からの移行案内
活用シーン
- 01Bun の HTTP サーバー開発
- 02依存関係とワークスペースの管理
- 03テストの作成とデバッグ
- 04Node.js プロジェクトの Bun 移行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lammesen/ skills --skill bun-expertインストール後、Claude Code で/bun-expertを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
reference/api-reference.mdbundler-guide.mdmigration-guide.mdtesting-guide.mdscripts/lint-check.shtest-runner.sh詳細
Bun エキスパートスキル
Bun ランタイム、パッケージマネージャー、テストランナー、バンドラーに関する深い知識を持つ、Bun のエキスパート開発者です。Bun のネイティブ API を使った高性能な JavaScript/TypeScript アプリケーションの構築を支援し、Node.js からの移行を案内します。
主な専門分野
1. Bun ランタイム API
HTTP サーバーとネットワーキング:
Bun.serve(options)- 高性能な HTTP/WebSocket サーバー(Node.js より 2.5 倍高速)Bun.fetch(url)- 拡張された Web Fetch APIBun.connect()/Bun.listen()- TCP/UDP ソケット APIBun.dns- DNS 解決ユーティリティ
ファイルシステム操作:
Bun.file(path)- 遅延読み込みでゼロコピーのファイル操作を行う BunFile(Blob を拡張)Bun.write(path, data)- 最適化されたファイル書き込みBun.stdin/Bun.stdout/Bun.stderr- 標準 I/O ストリーム
プロセスとシェル:
Bun.spawn(cmd)/Bun.spawnSync(cmd)- 子プロセスの起動Bun.$\command`` - テンプレートリテラルを使ったクロスプラットフォームのシェルスクリプト- 組み込みコマンド:
ls、cd、rm、cat、echo、pwd、mkdir、touch、which、mv
データとストレージ:
bun:sqlite- 組み込み SQLite3 ドライバー(better-sqlite3 より 3~6 倍高速)Bun.sql- PostgreSQL、MySQL、SQLite 向けの統合 SQL APIBun.S3Client/Bun.s3- ネイティブの S3 互換ストレージ(AWS SDK より 5 倍高速)Bun.redis- 組み込み Redis クライアント
ユーティリティ:
Bun.password.hash()/Bun.password.verify()- Argon2 パスワードハッシュ化Bun.hash(data)- 高速ハッシュ化(xxhash、murmur)Bun.Glob- ネイティブの glob パターンマッチングBun.semver- Semver 比較ユーティリティBun.sleep(ms)/Bun.sleepSync(ms)- スリープ関数Bun.deepEquals(a, b)- ディープ比較Bun.escapeHTML()- HTML サニタイズBun.YAML.parse()/Bun.YAML.stringify()- ネイティブの YAML サポートHTMLRewriter- HTML ストリーミング変換
高度な機能:
bun:ffi- 外部関数インターフェース(Node.js の FFI より 2~6 倍高速)Worker- マルチスレッド向け Web Workers APIBroadcastChannel- スレッド間の Pub/Sub メッセージングBun.Transpiler- JavaScript/TypeScript トランスパイル APIBun.build()- コンパイルに対応したバンドラー API
2. パッケージマネージャーのコマンド
基本コマンド:
bun install # Install all dependencies
bun install --frozen-lockfile # CI/CD lockfile validation
bun add <pkg> # Add dependency
bun add -d <pkg> # Add devDependency
bun remove <pkg> # Remove dependency
bun update # Update outdated packages
bun ci # CI-optimized install (--frozen-lockfile)
bunx <pkg> # Execute package without installing (100x faster than npx)
ワークスペースのサポート:
{
"workspaces": ["packages/*", "apps/*"],
"dependencies": {
"shared-pkg": "workspace:*"
}
}
パッケージ管理:
bun pm trust <pkg> # Allow lifecycle scripts
bun pm untrusted # View blocked scripts
bun why <pkg> # Explain why package installed
bun outdated # Show outdated packages
bun audit # Security vulnerability check
bun patch <pkg> # Prepare package for patching
bun link # Link local packages
ロックファイル: Bun は bun.lock(テキストベースの JSONC 形式)を使用します。人間が読みやすく、Git の差分を確認できます。package-lock.json、yarn.lock、pnpm-lock.yaml から自動的に移行します。
3. テストランナー(bun:test)
テスト構文:
import { describe, test, expect, beforeAll, afterEach, mock, spyOn } from "bun:test";
describe("feature", () => {
beforeAll(() => { /* setup */ });
afterEach(() => { mock.restore(); });
test("basic assertion", () => {
expect(2 + 2).toBe(4);
});
test("async operation", async () => {
const result = await fetchData();
expect(result).toMatchObject({ status: "ok" });
});
test.each([[1, 2, 3], [2, 3, 5]])("adds %i + %i = %i", (a, b, expected) => {
expect(a + b).toBe(expected);
});
});
テスト修飾子:
test.skip()- テストをスキップtest.only()- このテストだけを実行(--onlyフラグを使用)test.todo()- TODO としてマークtest.if(condition)/test.skipIf(condition)- 条件付き実行test.failing()- 失敗が想定されるテストtest.concurrent- 並行実行test.retry(n)- 失敗したテストを再試行
主なマッチャー:
.toBe()、.toEqual()、.toStrictEqual()- 等価性.toContain()、.toHaveLength()、.toMatch()- 文字列/配列.toHaveProperty()、.toMatchObject()- オブジェクト.toThrow()、.rejects.toThrow()- エラー.toMatchSnapshot()、.toMatchInlineSnapshot()- スナップショット.toHaveBeenCalled()、.toHaveBeenCalledWith()- モック
モック:
import { mock, spyOn } from "bun:test";
const mockFn = mock(() => 42);
mockFn.mockImplementation(() => 100);
mockFn.mockReturnValue(200);
const spy = spyOn(object, "method");
spy.mockResolvedValue({ data: "test" });
// Module mocking
mock.module("./api", () => ({
fetchUser: mock(() => ({ id: 1, name: "Test" }))
}));
CLI コマンド:
bun test # Run all tests
bun test --watch # Watch mode
bun test --coverage # Enable coverage
bun test -t "pattern" # Filter by test name
bun test --timeout=5000 # Set timeout
bun test --bail # Stop on first failure
bun test --update-snapshots # Update snapshots
4. バンドラーの設定
JavaScript API:
const result = await Bun.build({
entrypoints: ["./src/index.tsx"],
outdir: "./dist",
target: "browser", // "browser" | "bun" | "node"
format: "esm", // "esm" | "cjs" | "iife"
minify: true,
sourcemap: "external",
splitting: true, // Code splitting
external: ["react", "react-dom"],
define: {
"process.env.NODE_ENV": '"production"'
},
loader: {
".png": "dataurl",
".svg": "text"
},
plugins: [myPlugin],
naming: {
entry: "[dir]/[name].[ext]",
chunk: "[name]-[hash].[ext]"
}
});
if (!result.success) {
console.error(result.logs);
}
CLI:
bun build ./src/index.tsx --outdir ./dist --minify --sourcemap=external
bun build ./src/index.ts --compile --outfile myapp # Single executable
プラグインシステム:
const myPlugin: BunPlugin = {
name: "yaml-loader",
setup(build) {
build.onLoad({ filter: /\.yaml$/ }, async (args) => {
const text = await Bun.file(args.path).text();
return {
contents: `export default ${JSON.stringify(YAML.parse(text))}`,
loader: "js"
};
});
}
};
5. TypeScript との統合
Bun はトランスパイルの設定なしで TypeScript をネイティブに実行します:
bun run index.ts # Just works
bun run index.tsx # JSX supported
推奨する tsconfig.json:
{
"compilerOptions": {
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"types": ["bun-types"]
}
}
型チェック(別の手順):
bunx tsc --noEmit
6. 設定(bunfig.toml)
# Runtime
preload = ["./setup.ts"]
smol = true # Reduced memory mode
# JSX
[jsx]
runtime = "automatic"
importSource = "react"
# Package installation
[install]
optional = false
lockfile.save = true
[install.scopes]
"@myorg" = { url = "https://npm.myorg.com", token = "$NPM_TOKEN" }
# Test runner
[test]
preload = ["./test-setup.ts"]
coverage = true
coverageThreshold = { lines = 0.8, functions = 0.8 }
7. CLI フラグのリファレンス
実行:
--watch- ファイルの変更時に自動で再起動します--hot- ホットモジュールリプレースメント--smol- メモリ使用量を削減するモード--inspect/--inspect-brk- デバッガー
モジュール解決:
--preload/-r- モジュールを事前に読み込みます--install=auto|fallback|force- 自動インストールの動作
トランスパイル:
--define/-d- コンパイル時定数--drop=console- 関数呼び出しを削除します--loader- カスタムファイルローダー
環境:
--env-file- 指定した .env ファイルを読み込みます--cwd- 作業ディレクトリを設定します--bun/-b- Bun ランタイムを強制的に使用します
Node.js からの移行ガイド
移行手順(概要)
- Bun をインストールします:
curl -fsSL https://bun.sh/install | bash - パッケージマネージャーを置き換えます:
# Delete node_modules and lockfile
rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml
bun install
- package.json のスクリプトを更新します:
{
"scripts": {
"dev": "bun run --watch src/index.ts",
"test": "bun test",
"build": "bun build src/index.ts --outdir dist"
}
}
- TypeScript の型を更新します:
bun add -d @types/bun
# Or in tsconfig.json: "types": ["bun-types"]
API の互換性
完全に互換:
node:assert、node:buffer、node:events、node:path、node:urlnode:fs(92%)、node:http、node:https、node:stream、node:zlibnode:crypto、node:net、node:dns、node:os
一部互換:
node:child_process-proc.gid、proc.uidは未対応です。IPC は JSON に限定されますnode:cluster- 負荷分散用の SO_REUSEPORT は Linux のみ対応していますnode:http2- 95% 互換です。pushStreamは未対応ですnode:worker_threads-stdin、stdout、stderrオプションは未対応ですnode:async_hooks- AsyncLocalStorage は動作しますが、v8 の Promise フックは未対応です
未実装:
node:inspector、node:repl、node:trace_events
移行時によくある注意点
- ネイティブモジュール: node-gyp を使用するパッケージ(bcrypt、sharp)は失敗する場合があります
- 解決策:純粋な JS の代替パッケージを使用します(
bcryptの代わりにbcryptjs)
- 解決策:純粋な JS の代替パッケージを使用します(
- ライフサイクルスクリプト: Bun はセキュリティ上の理由から、デフォルトで postinstall をブロックします
- 解決策:
bun pm trust <package>を実行するか、trustedDependenciesに追加します
- 解決策:
- モジュールシステム: Node.js の内部機能に依存する一部のパッケージは失敗する場合があります
Module._nodeModulePathsは Bun には存在しません
- ファイルシステムの違い: 大量のファイルを同時に読み込むと、メモリの問題が発生する場合があります
- 解決策:
graceful-fsラッパーを使用します
- 解決策:
- TypeScript のエントリーポイント: Bun 用に
"main"フィールドを更新します:
{
"main": "src/index.ts" // Not "build/index.js"
}
段階的な移行戦略
フェーズ 1: パッケージマネージャーのみ(bun install)
フェーズ 2: 開発ツール(bun run、bun test)
フェーズ 3: ランタイムを選択的に移行(シャドーデプロイ)
フェーズ 4: 本番環境を全面的に移行
ベストプラクティス
パフォーマンスの最適化
// Use Bun's native APIs for I/O
const file = Bun.file("large.txt"); // Zero-copy
const content = await file.text();
await Bun.write("output.txt", processedData);
// Use Promise.all for concurrent operations
const [users, posts] = await Promise.all([
db.query("SELECT * FROM users"),
db.query("SELECT * FROM posts")
]);
// Use Bun.serve() static routes
Bun.serve({
static: {
"/": homepage,
"/about": aboutPage
},
fetch(req) { /* dynamic routes */ }
});
// Use bun:sqlite for local data
import { Database } from "bun:sqlite";
const db = new Database(":memory:");
const stmt = db.prepare("SELECT * FROM users WHERE id = ?");
エラー処理
// HTTP server error handling
Bun.serve({
fetch(req) {
try {
return handleRequest(req);
} catch (error) {
console.error(error);
return new Response("Internal Error", { status: 500 });
}
},
error(error) {
return new Response(`Error: ${error.message}`, { status: 500 });
}
});
// Process-level error handling
process.on("uncaughtException", (error) => {
console.error("Uncaught:", error);
process.exit(1);
});
セキュリティのベストプラクティス
- ライフサイクルスクリプト:
trustedDependenciesは最小限に保ちます - 環境変数: シークレットには
.env.localを使用します(コミットしないでください) - 入力の検証: すべてのユーザー入力をサニタイズします
- 依存関係:
bun auditを定期的に実行します - 本番環境:
--productionフラグを使用して devDependencies をスキップします
プロジェクト構成
my-bun-project/
├── src/
│ ├── index.ts # Entry point
│ ├── server.ts # HTTP server
│ └── lib/ # Utilities
├── test/
│ └── *.test.ts # Test files
├── bunfig.toml # Bun configuration
├── tsconfig.json # TypeScript config
├── package.json
└── .env.local # Local secrets (gitignored)
デバッグ
Web デバッガー:
bun --inspect server.ts # Start debugger
bun --inspect-brk server.ts # Break at first line
bun --inspect-wait server.ts # Wait for connection
https://debug.bun.sh を開くか、VSCode の Bun 拡張機能を使用します。
詳細な Fetch ログ:
BUN_CONFIG_VERBOSE_FETCH=curl bun run server.ts
例
WebSocket を使用する HTTP サーバー
Bun.serve({
port: 3000,
fetch(req, server) {
if (server.upgrade(req)) return;
return new Response("Hello Bun!");
},
websocket: {
open(ws) { console.log("Connected"); },
message(ws, message) { ws.send(`Echo: ${message}`); },
close(ws) { console.log("Disconnected"); }
}
});
ファイルサーバー
Bun.serve({
async fetch(req) {
const path = new URL(req.url).pathname;
const file = Bun.file(`./public${path}`);
if (await file.exists()) {
return new Response(file);
}
return new Response("Not Found", { status: 404 });
}
});
SQLite を使用するデータベース
import { Database } from "bun:sqlite";
const db = new Database("app.db");
db.run(`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE
)`);
const insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
const getAll = db.prepare("SELECT * FROM users");
insert.run("Alice", "[email protected]");
const users = getAll.all();
このスキルが有効になる条件
次の場合に、このスキルは自動的に有効になります:
- Bun プロジェクトで
.ts、.tsx、.js、.jsxファイルを操作する場合 bunfig.tomlまたはbun.lockを作成または変更する場合bun:test、bun:sqlite、bun:ffiのインポートを使用する場合- Bun API(Bun.serve、Bun.file、Bun.build)について話し合う場合
- Node.js から Bun に移行する場合
- Bun のテストを記述またはデバッグする場合
- Bun バンドラーを設定する場合