3.3 KiB
Prompt 15: Production Bundle & Packaging
Context
You are working in /workspaces/claude-code. By now you should have a working development runner (Prompt 14) and build system (Prompt 03). This prompt focuses on creating a production-quality bundle.
Task
Part A: Optimize the esbuild configuration
Update scripts/build-bundle.ts for production:
-
Tree shaking — esbuild does this by default, but verify:
- Feature-gated code with
if (feature('X'))where X isfalseshould be eliminated process.env.USER_TYPE === 'ant'branches should be eliminated (setdefineto replace withfalse)
- Feature-gated code with
-
Define replacements — Inline constants at build time:
define: { 'process.env.USER_TYPE': '"external"', // Not 'ant' (Anthropic internal) 'process.env.NODE_ENV': '"production"', } -
Minification — Enable for production (
--minifyflag) -
Source maps — External source maps for production debugging
-
Target — Ensure compatibility with both Bun 1.1+ and Node.js 20+
Part B: Handle chunking/splitting
The full bundle will be large (~2-5 MB minified). Consider:
- Single file — Simplest, works everywhere (recommended for CLI tools)
- Code splitting — Multiple chunks, only useful if we want lazy loading
Go with single file unless it causes issues.
Part C: Create the executable
After bundling to dist/cli.mjs:
- Add shebang —
#!/usr/bin/env node(already in banner) - Make executable —
chmod +x dist/cli.mjs - Test it runs —
./dist/cli.mjs --version
Part D: Platform packaging
Create packaging scripts for distribution:
npm package (scripts/package-npm.ts):
// Generate a publishable npm package in dist/npm/
// - package.json with bin, main, version
// - The bundled CLI file
// - README.md
Standalone binary (optional, via Bun):
bun build --compile src/entrypoints/cli.tsx --outfile dist/claude
This creates a single binary with Bun runtime embedded. Not all features will work, but it's worth testing.
Part E: Docker build
Update the existing Dockerfile to produce a runnable container:
FROM oven/bun:1-alpine AS builder
WORKDIR /app
COPY package.json bun.lockb* ./
RUN bun install --frozen-lockfile || bun install
COPY . .
RUN bun run build:prod
FROM oven/bun:1-alpine
WORKDIR /app
COPY --from=builder /app/dist/cli.mjs /app/
RUN apk add --no-cache git ripgrep
ENTRYPOINT ["bun", "/app/cli.mjs"]
Part F: Verify production build
bun run build:prodsucceedsls -lh dist/cli.mjs— check file sizenode dist/cli.mjs --version— works with Node.jsbun dist/cli.mjs --version— works with BunANTHROPIC_API_KEY=... node dist/cli.mjs -p "hello"— end-to-end works
Part G: CI build script
Create scripts/ci-build.sh:
#!/bin/bash
set -euo pipefail
echo "=== Installing dependencies ==="
bun install
echo "=== Type checking ==="
bun run typecheck
echo "=== Linting ==="
bun run lint
echo "=== Building ==="
bun run build:prod
echo "=== Verifying build ==="
node dist/cli.mjs --version
echo "=== Done ==="
Verification
bun run build:prodproducesdist/cli.mjs- The bundle is < 10 MB (ideally < 5 MB)
node dist/cli.mjs --versionworksdocker build .succeeds (if Docker is available)- CI script runs end-to-end without errors