mcpField
B
bun-macros

bun-macros

github.com/secondsky开发240391 次安装5 周前更新
代码仓库

关于 bun-macros

bun-macros 是一份 Bun 宏技能指南,介绍如何在打包时执行 JavaScript 并内联结果,涵盖环境值、文件嵌入、代码生成、异步宏和调试。

主要功能

  1. 01在打包时执行函数
  2. 02内联环境变量和构建值
  3. 03嵌入文件内容
  4. 04生成类型或 API 代码
  5. 05使用异步及带参数的宏
  6. 06调试宏求值过程

适用场景

  1. 01将构建时常量嵌入输出
  2. 02在 Bundle 中包含文件数据
  3. 03根据 Schema 生成代码
  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 evaluated缺少 with { type: "macro" }添加导入属性

何时加载参考资料

在以下情况加载 references/advanced-patterns.md:

  • 复杂的代码生成
  • 插件集成
  • 构建流水线 检索并展示自定义宏实现模式、与构建系统集成的示例,以及高级打包器插件工作流。

在以下情况加载 references/debugging.md:

  • 宏未执行
  • 输出不符合预期
  • 性能问题 检索调试技巧,提供分步诊断,并针对用户的具体问题给出优化策略。

评论

支持 Markdown