mcpField
B
bun-macros

bun-macros

github.com/secondsky開発240391 回インストール5 週間前に更新
リポジトリ

bun-macros について

bun-macros は、バンドル時に JavaScript を実行し、その結果を出力へ埋め込む Bun マクロのスキルガイドです。環境値、ファイル埋め込み、コード生成、非同期マクロ、デバッグを扱います。

主な機能

  1. 01バンドル時の関数実行
  2. 02環境値とビルド値の埋め込み
  3. 03ファイル内容の埋め込み
  4. 04型や API コードの生成
  5. 05非同期マクロと引数付きマクロ
  6. 06マクロ評価のデバッグ

活用シーン

  1. 01ビルド時定数を出力に埋め込む
  2. 02ファイルデータをバンドルに含める
  3. 03スキーマからコードを生成
  4. 04評価されないマクロの原因調査

インストール

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

$npx skills add https://github.com/secondsky/claude-skills --skill bun-macros

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

詳細

Bun マクロ

Bun マクロはバンドル時に JavaScript を実行し、その結果を出力にインライン化します。

クイックスタート

// src/config.ts (macro file)
export function getVersion() {
  return "1.0.0";
}

export function getBuildTime() {
  return new Date().toISOString();
}

// src/index.ts (consumer)
import { getVersion, getBuildTime } from "./config" with { type: "macro" };

// At bundle time, these become:
const version = "1.0.0";
const buildTime = "2024-01-15T12:00:00.000Z";

マクロの構文

// Import with macro attribute
import { fn } from "./macro-file" with { type: "macro" };

// Call the macro (evaluated at build time)
const result = fn();

よくあるユースケース

環境変数のインライン化
// macros/env.ts
export function env(key: string): string {
  return process.env[key] ?? "";
}

// src/index.ts
import { env } from "./macros/env" with { type: "macro" };

const apiUrl = env("API_URL");
// Becomes: const apiUrl = "https://api.example.com";
Git 情報
// macros/git.ts
export function gitCommit(): string {
  return Bun.spawnSync(["git", "rev-parse", "HEAD"])
    .stdout.toString().trim();
}

export function gitBranch(): string {
  return Bun.spawnSync(["git", "branch", "--show-current"])
    .stdout.toString().trim();
}

// src/index.ts
import { gitCommit, gitBranch } from "./macros/git" with { type: "macro" };

const BUILD_INFO = {
  commit: gitCommit(),
  branch: gitBranch(),
};
// Inlined at build time
ファイルの埋め込み
// macros/embed.ts
export function embedFile(path: string): string {
  return Bun.file(path).text();
}

export function embedJSON(path: string): unknown {
  return Bun.file(path).json();
}

// src/index.ts
import { embedFile, embedJSON } from "./macros/embed" with { type: "macro" };

const license = embedFile("./LICENSE");
const config = embedJSON("./config.json");
ビルド定数
// macros/constants.ts
export function isDev(): boolean {
  return process.env.NODE_ENV !== "production";
}

export function buildDate(): number {
  return Date.now();
}

export function randomId(): string {
  return Math.random().toString(36).slice(2);
}

// src/index.ts
import { isDev, buildDate, randomId } from "./macros/constants" with { type: "macro" };

if (isDev()) {
  console.log("Development mode");
}

const BUILD_ID = randomId();
ディレクトリ一覧
// macros/files.ts
import { readdirSync } from "fs";

export function listRoutes(): string[] {
  return readdirSync("./src/routes")
    .filter(f => f.endsWith(".tsx"))
    .map(f => f.replace(".tsx", ""));
}

// src/router.ts
import { listRoutes } from "./macros/files" with { type: "macro" };

const routes = listRoutes();
// Becomes: const routes = ["home", "about", "users"];
コード生成
// macros/codegen.ts
export function generateTypes(schema: string): string {
  // Parse schema and generate types at build time
  const types = parseSchemaToTypes(schema);
  return types;
}

export function generateAPI(spec: string): string {
  const openapi = JSON.parse(Bun.file(spec).text());
  // Generate API client code
  return generateClientFromOpenAPI(openapi);
}

戻り値の型

マクロは次の値を返せます。

// Primitives
export function getString(): string { return "hello"; }
export function getNumber(): number { return 42; }
export function getBoolean(): boolean { return true; }
export function getNull(): null { return null; }

// Objects (serializable)
export function getObject(): object {
  return { key: "value", nested: { a: 1 } };
}

// Arrays
export function getArray(): string[] {
  return ["a", "b", "c"];
}

// Response (for bundler plugins)
export function getResponse(): Response {
  return new Response("content", {
    headers: { "Content-Type": "text/plain" },
  });
}

非同期マクロ

// macros/fetch.ts
export async function fetchSchema(): Promise<object> {
  const response = await fetch("https://api.example.com/schema.json");
  return response.json();
}

// src/index.ts
import { fetchSchema } from "./macros/fetch" with { type: "macro" };

const schema = await fetchSchema();
// Fetched at build time, inlined as object literal

パラメーター

// macros/parameterized.ts
export function repeat(str: string, count: number): string {
  return str.repeat(count);
}

export function formatDate(format: string): string {
  return new Date().toLocaleDateString("en-US", {
    dateStyle: format as any,
  });
}

// src/index.ts
import { repeat, formatDate } from "./macros/parameterized" with { type: "macro" };

const separator = repeat("-", 20);
const date = formatDate("long");

条件付きコード

// macros/platform.ts
export function platform(): "node" | "bun" | "browser" {
  if (typeof Bun !== "undefined") return "bun";
  if (typeof process !== "undefined") return "node";
  return "browser";
}

// src/index.ts
import { platform } from "./macros/platform" with { type: "macro" };

if (platform() === "bun") {
  // This block is kept or removed at build time
  console.log("Running on Bun");
}

バンドル時のみの実行

マクロはバンドル時にのみ実行されます。

# Macros executed
bun build src/index.ts --outdir=dist

# Macros NOT executed (runtime)
bun run src/index.ts

エラー処理

// macros/safe.ts
export function requireEnv(key: string): string {
  const value = process.env[key];
  if (!value) {
    throw new Error(`Missing required env var: ${key}`);
  }
  return value;
}

// Build fails if env var missing
import { requireEnv } from "./macros/safe" with { type: "macro" };
const secret = requireEnv("API_SECRET");

マクロのデバッグ

// macros/debug.ts
export function debug(label: string, value: unknown): unknown {
  console.log(`[MACRO] ${label}:`, value);
  return value;
}

// See output during build
bun build src/index.ts --outdir=dist
// [MACRO] config: { ... }

ベストプラクティス

  1. マクロを純粋に保つ - 副作用を避けます
  2. シリアライズ可能な値を返す - JSON 互換である必要があります
  3. エラーを処理する - ビルド失敗時に意味のあるエラーをスローします
  4. 依存関係を文書化する - 必要なファイルや環境変数を記載します
  5. 個別にテストする - マクロは通常の関数としてテストできます

よくあるエラー

エラー原因修正方法
Cannot find moduleインポートパスが間違っていますマクロファイルの場所を確認します
Not serializable関数またはクラスが返されましたプレーンなデータを返します
Macro failedマクロ内でランタイムエラーが発生しましたマクロを個別にデバッグします
Not evaluatedwith { type: "macro" } がありませんインポート属性を追加します

参照資料を読み込むタイミング

次の場合は references/advanced-patterns.md を読み込みます。

  • 複雑なコード生成
  • プラグインの統合
  • ビルドパイプライン カスタムマクロ実装のパターン、ビルドシステムとの統合例、高度なバンドラープラグインのワークフローを取得して提示します。

次の場合は references/debugging.md を読み込みます。

  • マクロが評価されない
  • 想定外の出力
  • パフォーマンスの問題 デバッグ手法を取得し、手順に沿った診断を提供して、ユーザー固有の問題に応じた最適化戦略を提案します。

コメント