mcpField
B
bun-expert

bun-expert

github.com/lammesen開発103 回インストール
リポジトリ

bun-expert について

bun-expert は、Bun を使う開発者向けのスキルです。ランタイム、パッケージ管理、テスト、バンドルに加え、Node.js からの移行や互換性の違いも案内します。

主な機能

  1. 01Bun ランタイム API の解説
  2. 02パッケージ管理とワークスペース
  3. 03bun:test のテストとモック
  4. 04ビルドとバンドラー設定
  5. 05Node.js からの移行案内

活用シーン

  1. 01Bun の HTTP サーバー開発
  2. 02依存関係とワークスペースの管理
  3. 03テストの作成とデバッグ
  4. 04Node.js プロジェクトの Bun 移行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/lammesen/skills --skill bun-expert

インストール後、Claude Code で/bun-expertを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

reference/
api-reference.md
bundler-guide.md
migration-guide.md
testing-guide.md
scripts/
lint-check.sh
test-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 API
  • Bun.connect() / Bun.listen() - TCP/UDP ソケット API
  • Bun.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 API
  • Bun.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 API
  • BroadcastChannel - スレッド間の Pub/Sub メッセージング
  • Bun.Transpiler - JavaScript/TypeScript トランスパイル API
  • Bun.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 からの移行ガイド

移行手順(概要)
  1. Bun をインストールします: curl -fsSL https://bun.sh/install | bash
  2. パッケージマネージャーを置き換えます:
# Delete node_modules and lockfile
rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml
bun install
  1. package.json のスクリプトを更新します:
{
  "scripts": {
    "dev": "bun run --watch src/index.ts",
    "test": "bun test",
    "build": "bun build src/index.ts --outdir dist"
  }
}
  1. TypeScript の型を更新します:
bun add -d @types/bun
# Or in tsconfig.json: "types": ["bun-types"]
API の互換性

完全に互換:

  • node:assert、node:buffer、node:events、node:path、node:url
  • node:fs(92%)、node:http、node:https、node:stream、node:zlib
  • node: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
移行時によくある注意点
  1. ネイティブモジュール: node-gyp を使用するパッケージ(bcrypt、sharp)は失敗する場合があります
    • 解決策:純粋な JS の代替パッケージを使用します(bcrypt の代わりに bcryptjs)
  2. ライフサイクルスクリプト: Bun はセキュリティ上の理由から、デフォルトで postinstall をブロックします
    • 解決策:bun pm trust <package> を実行するか、trustedDependencies に追加します
  3. モジュールシステム: Node.js の内部機能に依存する一部のパッケージは失敗する場合があります
    • Module._nodeModulePaths は Bun には存在しません
  4. ファイルシステムの違い: 大量のファイルを同時に読み込むと、メモリの問題が発生する場合があります
    • 解決策:graceful-fs ラッパーを使用します
  5. 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);
});
セキュリティのベストプラクティス
  1. ライフサイクルスクリプト: trustedDependencies は最小限に保ちます
  2. 環境変数: シークレットには .env.local を使用します(コミットしないでください)
  3. 入力の検証: すべてのユーザー入力をサニタイズします
  4. 依存関係: bun audit を定期的に実行します
  5. 本番環境: --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 バンドラーを設定する場合

コメント