Skip to content

Implement bunjs-dev: Bun.js development conventions #9

@vredchenko

Description

@vredchenko

Summary

The bunjs-dev plugin enforces Bun-first development: prefer bun over node/npm, use Bun-native APIs (Bun.serve, Bun.file, Bun.write), use biome over eslint/prettier, and leverage Bun's built-in test runner. This is valuable because Claude Code defaults to Node.js patterns and npm commands even when a project uses Bun.

Original Intent

Use Bun.js instead of Node.js and bun install instead of npm install. Use Bun.js features and functionality extensively.

Commands

/bunjs:init

Purpose: Initialize a new Bun.js project with TypeScript and modern tooling.

Behavior:

  1. Ask user for:
    • Project name (default: current directory name)
    • Project type: library, CLI app, web server, fullstack app
  2. Run bun init if no package.json exists
  3. Ensure package.json has:
    {
      "type": "module",
      "scripts": {
        "dev": "bun run --watch src/index.ts",
        "build": "bun build src/index.ts --outdir dist --target bun",
        "test": "bun test",
        "check": "bunx biome check .",
        "check:fix": "bunx biome check --fix ."
      }
    }
  4. Create tsconfig.json optimized for Bun:
    {
      "compilerOptions": {
        "target": "ESNext",
        "module": "ESNext",
        "moduleResolution": "bundler",
        "types": ["bun-types"],
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "outDir": "dist"
      },
      "include": ["src/**/*.ts"]
    }
  5. Install dev deps: bun add -d bun-types @biomejs/biome
  6. Create biome.json:
    {
      "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
      "organizeImports": { "enabled": true },
      "linter": {
        "enabled": true,
        "rules": { "recommended": true }
      },
      "formatter": {
        "enabled": true,
        "indentStyle": "tab",
        "lineWidth": 100
      }
    }
  7. Create directory structure:
    • Library: src/index.ts, tests/
    • CLI app: src/index.ts with #!/usr/bin/env bun shebang, src/commands/
    • Web server: src/index.ts with Bun.serve() template
    • Fullstack: src/server.ts, src/client/, public/
  8. Create .gitignore (node_modules/, dist/, *.tsbuildinfo)
  9. Output summary

Edge cases:

  • package-lock.json exists → warn: "This project uses npm. Convert to Bun? This will create bun.lockb and remove package-lock.json."
  • yarn.lock or pnpm-lock.yaml exists → similar warning
  • Existing eslint config → offer migration to biome

/bunjs:test

Purpose: Run tests using Bun's built-in test runner and analyze results.

Behavior:

  1. Run tests:
    bun test --bail
  2. If tests fail:
    • Show failure summary with file:line references
    • Offer to fix first failing test
  3. If all pass:
    • Show pass count and duration
    • Check for untested source files (compare src/**/*.ts with tests/**/*.test.ts)
  4. Special modes:
    • "Just this file" → bun test <file>
    • "Watch mode" → bun test --watch
    • "Coverage" → bun test --coverage

Bun test API reminders (include in command doc for Claude's reference):

import { describe, test, expect, beforeAll, afterAll, mock } from "bun:test";

// Bun-native mocking
const fn = mock(() => 42);

// Snapshot testing
expect(value).toMatchSnapshot();

// Async
test("async", async () => {
  const resp = await fetch("http://localhost:3000");
  expect(resp.status).toBe(200);
});

Edge cases:

  • No test files exist → scaffold tests/<module>.test.ts for each source file
  • Jest config exists → note that Bun's test runner is largely Jest-compatible, suggest removing jest deps
  • vitest config exists → note Bun's built-in runner is preferred, but vitest is also fine

/bunjs:build (new)

Purpose: Build/bundle the project using Bun's bundler.

Behavior:

  1. Detect build targets from project type:
    • Library: bun build src/index.ts --outdir dist --target bun
    • CLI: bun build src/index.ts --compile --outfile dist/<name>
    • Web: bun build src/client/index.ts --outdir dist/public --minify
  2. Show build output:
    ✓ Built in 42ms
      dist/index.js  12.3 KB
      dist/index.js.map  28.1 KB
    
  3. For compilable CLIs:
    • Cross-compilation targets: --target=bun-linux-x64, --target=bun-darwin-arm64
    • Ask user which targets to build for
  4. If package.json has a build script → use that instead

Edge cases:

  • External dependencies that shouldn't be bundled → --external <pkg>
  • Large bundle size → suggest --minify and --splitting

Hooks

PreToolUse: bun_lockb_detector

Trigger: Bash tool, when command matches \bnpm\s+(install|i|ci|run|exec|test)\b or \bnpx\s+ and a bun.lockb file exists in the project

Behavior:

  • BLOCK the operation
  • Output: ⚠ This project uses Bun (bun.lockb detected). Use \bun`/`bunx` instead of `npm`/`npx`. Equivalent: `bun ``
  • Provide the equivalent bun command

PostToolUse: bun_api_hint

Trigger: Write or Edit tool, when written content contains Node.js patterns that have Bun-native alternatives:

  • fs.readFile → suggest Bun.file(path).text()
  • fs.writeFile → suggest Bun.write(path, data)
  • http.createServer / express() → suggest Bun.serve()
  • child_process.exec → suggest Bun.spawn() / Bun.$
  • crypto.randomUUID → suggest Bun.randomUUIDv7()

Behavior:

  • Output: 💡 Bun-native alternative available: \` instead of ```

File Manifest

File Est. Lines Purpose
commands/init.md 100-120 Initialize Bun project
commands/test.md 80-100 Run and analyze tests
commands/build.md 70-90 Build/bundle with Bun
hooks/bun_lockb_detector.md 25-35 Block npm in Bun projects
hooks/bun_api_hint.md 30-40 Suggest Bun-native APIs
README.md 160-200 Full plugin documentation
.claude-plugin/plugin.json 15-20 Plugin manifest

README Outline

  1. Overview — Bun-first development philosophy

  2. Quick Start — Installation + /bunjs:init

  3. Commands — Table with all 3 commands

  4. Hooks — npm detection + Bun API suggestions

  5. Bun vs Node API Cheat Sheet

    Node.js Bun Native Notes
    fs.readFile(path) Bun.file(path).text() Returns Promise directly
    fs.writeFile(path, data) Bun.write(path, data) Accepts Response, Blob, etc.
    http.createServer() Bun.serve() Built-in WebSocket support
    child_process.exec() Bun.spawn() / Bun.$ Shell tagged template
    node:test bun:test Jest-compatible API
    crypto.randomUUID() Bun.randomUUIDv7() UUIDv7 (time-sortable)
  6. Biome Configuration — Explanation of the default biome.json

  7. Project Templates — Layout for library, CLI, web server, fullstack

  8. Migration from Node.js — Moving from npm/eslint/jest to bun/biome/bun:test

Prerequisites

  • bun (v1.0+)
  • No other tools required — Bun replaces node, npm, npx, jest, and bundlers

Quality Checklist

  • Each command .md is 60+ lines with concrete steps
  • README is 100+ lines with examples and reference tables
  • API cheat sheet (Node → Bun) is comprehensive
  • Plugin provides clear value beyond Claude's defaults (npm blocker + API hints are key)
  • Biome config is included and explained

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions