Ein npm-Paket mit Claude Code erstellen und veröffentlichen
Erstelle mit Claude Code ein npm-Paket mit tsup, exports, Typen, npm pack, README-Generator und CI-Publishing.
Claude Code kann sehr schnell ein npm-Paket anlegen. Ein Paket, das andere Entwickler zuverlässig installieren, braucht aber mehr als ein paar erzeugte Dateien. Wichtig sind ein stimmiges package.json, korrekte exports, generierte Typdefinitionen, ein README mit passenden Beispielen, eine Prüfung mit npm pack und ein CI-Workflow, der nur unter klaren Bedingungen veröffentlicht.
In diesem Artikel bauen wir ein kleines TypeScript-Paket für String-Helfer. Claude Code ist dabei kein Autopilot für die Veröffentlichung, sondern ein Partner zum Generieren, Prüfen und Erklären. Prüfe vor echten Releases immer die offiziellen Quellen: npm package.json, scoped public packages, npm pack, trusted publishing und die Claude Code Dokumentation.
Zuerst den Paketvertrag klären
Der erste Prompt sollte nicht nur “erstelle ein Paket” lauten. Nenne Paketname, Nutzer, Runtime, Modulformate, Prüfkommandos und Veröffentlichungsstrategie. type: "module", main, exports und types hängen zusammen. Wenn Claude Code nur eine Stelle setzt, kann das Paket zwar bauen, aber bei Nutzern scheitern.
| Bereich | Entscheidung im Beispiel | Was Claude Code prüfen soll |
|---|---|---|
| Name | @acme/string-kit | ob ein scoped public Paket --access public braucht |
| Nutzer | Node.js und TypeScript | ob ESM import und CJS require funktionieren |
| Build | tsup erzeugt ESM, CJS und Typen | ob dist die Dateien aus exports enthält |
| Inhalt | nur dist, README.md, LICENSE | ob npm pack --dry-run unerwartete Dateien zeigt |
| Release | GitHub Actions + npm Trusted Publishing | ob keine langen npm Tokens nötig sind |
Der Ablauf wird übersichtlicher, wenn du ihn vor der Bearbeitung visualisierst.
flowchart LR
A["Paket-Brief"] --> B["package.json"]
B --> C["src/index.ts"]
C --> D["Vitest"]
D --> E["tsup build"]
E --> F["npm pack dry-run"]
F --> G["CI publish"]
Wenn dein Paket eine CLI werden soll, lies danach CLI-Tool-Entwicklung mit Claude Code. Für bessere Arbeitsaufträge passt Claude Code Produktivitäts-Tipps dazu.
Ein minimales Projekt erstellen
Starte in einem sauberen Ordner. In einem großen Repository vermischen sich Paketfehler schnell mit Workspace-Konfiguration, alten Abhängigkeiten oder bestehenden Scripts. Das Minimalprojekt zeigt, ob der Paketvertrag selbst funktioniert.
mkdir string-kit
cd string-kit
npm init -y
npm install -D typescript tsup vitest @types/node
mkdir src scripts
Das package.json ist der öffentliche Vertrag. main bedient CJS, module hilft manchen Bundlern, types ist für TypeScript und exports steuert moderne Einstiegspunkte. files ist bewusst eng, damit Tests, Notizen, Sourcemaps und lokale Konfiguration nicht versehentlich veröffentlicht werden.
{
"name": "@acme/string-kit",
"version": "0.1.0",
"description": "Small TypeScript string utilities used as an npm package example.",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"./package.json": "./package.json"
},
"files": ["dist", "README.md", "LICENSE"],
"sideEffects": false,
"scripts": {
"build": "tsup",
"test": "vitest run",
"docs": "node scripts/write-readme.mjs",
"test:pack": "npm pack --dry-run",
"prepublishOnly": "npm run test && npm run build && npm run test:pack"
},
"keywords": ["string", "typescript", "utilities"],
"license": "MIT",
"devDependencies": {
"@types/node": "^22.15.0",
"tsup": "^8.5.0",
"typescript": "^5.8.0",
"vitest": "^3.2.0"
}
}
TypeScript prüft hier nur die Typen. Die Ausgabe übernimmt tsup. Diese Trennung macht es einfacher, Claude Code nach dem Build die Übereinstimmung von dist und exports prüfen zu lassen.
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"declaration": true,
"declarationMap": true,
"skipLibCheck": true,
"noEmit": true
},
"include": ["src", "tsup.config.ts"]
}
Implementierung und Tests
Ein Paketartikel sollte keinen Pseudocode verkaufen. Dieses Beispiel exportiert vier kleine Funktionen: slugify erzeugt ASCII-Slugs, truncate kürzt Text auf eine maximale Länge, interpolate ersetzt einfache Platzhalter und byteLength zählt UTF-8-Bytes.
export function slugify(input: string): string {
return input
.normalize("NFKD")
.replace(/[\u0300-\u036f]/g, "")
.toLowerCase()
.trim()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
export function truncate(input: string, maxLength: number, suffix = "..."): string {
if (!Number.isInteger(maxLength) || maxLength < 1) {
throw new RangeError("maxLength must be a positive integer");
}
if (suffix.length >= maxLength) {
throw new RangeError("suffix must be shorter than maxLength");
}
if (input.length <= maxLength) return input;
return `${input.slice(0, maxLength - suffix.length)}${suffix}`;
}
export function interpolate(template: string, values: Record<string, string | number>): string {
return template.replace(/\{\{\s*([\w.-]+)\s*\}\}/g, (match, key: string) => {
return Object.hasOwn(values, key) ? String(values[key]) : match;
});
}
export function byteLength(input: string): number {
return new TextEncoder().encode(input).length;
}
Die Tests decken Normalfälle, Grenzen, Fehler und Unicode ab. Bitte Claude Code nicht nur um “Tests”, sondern nenne Akzente, unbekannte Platzhalter, ungültige Längen und UTF-8-Bytes ausdrücklich.
import { describe, expect, it } from "vitest";
import { byteLength, interpolate, slugify, truncate } from "./index";
describe("slugify", () => {
it("turns a title into an npm-friendly slug", () => {
expect(slugify("Hello npm Package!")).toBe("hello-npm-package");
});
it("removes accents before replacing separators", () => {
expect(slugify("Crème brûlée utils")).toBe("creme-brulee-utils");
});
});
describe("truncate", () => {
it("keeps short text unchanged", () => {
expect(truncate("short", 10)).toBe("short");
});
it("adds a suffix inside the requested length", () => {
expect(truncate("Claude Code package", 12)).toBe("Claude Co...");
});
it("rejects invalid lengths", () => {
expect(() => truncate("abc", 2)).toThrow(RangeError);
});
});
describe("interpolate", () => {
it("replaces known placeholders and keeps unknown ones", () => {
expect(interpolate("Hi {{ name }}, ship {{pkg}} {{missing}}", {
name: "Masa",
pkg: "@acme/string-kit",
})).toBe("Hi Masa, ship @acme/string-kit {{missing}}");
});
});
describe("byteLength", () => {
it("counts UTF-8 bytes", () => {
expect(byteLength("npm")).toBe(3);
expect(byteLength("日本語")).toBe(9);
});
});
tsup und README-Generator
Die tsup-Konfiguration bleibt klein. outExtension schreibt ESM als .js und CJS als .cjs, passend zu den Einträgen im package.json. sourcemap: false ist hier Absicht, damit keine internen Quellkarten ohne Entscheidung im Paket landen.
import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts"],
format: ["esm", "cjs"],
dts: true,
clean: true,
sourcemap: false,
minify: false,
target: "es2022",
outDir: "dist",
outExtension({ format }) {
return { js: format === "esm" ? ".js" : ".cjs" };
},
});
README-Beispiele veralten schnell. Ein kleiner Generator hält Installation und Nutzung näher an der echten API.
import { writeFile } from "node:fs/promises";
const fence = String.fromCharCode(96).repeat(3);
const readme = `# @acme/string-kit
Small TypeScript string utilities packaged with tsup.
## Install
${fence}bash
npm install @acme/string-kit
${fence}
## Usage
${fence}ts
import { slugify, truncate } from "@acme/string-kit";
console.log(slugify("Hello npm Package!"));
console.log(truncate("Claude Code package", 12));
${fence}
`;
await writeFile(new URL("../README.md", import.meta.url), readme);
Vor dem Release mit npm pack prüfen
npm publish darf nicht der erste echte Test sein. npm pack --dry-run zeigt, was in die Registry gehen würde. Prüfe README, LICENSE, Typen, ESM/CJS-Dateien und ob Tests oder Entwürfe draußen bleiben.
npm run docs
npm test
npm run build
npm pack --dry-run
node -e "import('./dist/index.js').then((m)=>console.log(m.slugify('Hello ESM')))"
node -e "const m=require('./dist/index.cjs'); console.log(m.slugify('Hello CJS'))"
Noch besser ist die Installation des erzeugten .tgz in einem separaten Ordner.
npm pack
mkdir ../string-kit-smoke
cd ../string-kit-smoke
npm init -y
npm install ../string-kit/acme-string-kit-0.1.0.tgz
node -e "import('@acme/string-kit').then((m)=>console.log(m.truncate('Claude Code package', 12)))"
Drei Einsatzfälle sind typisch. Ein Produktteam teilt String-Regeln zwischen Web, Admin und Dokumentation. Ein Content-Team nutzt truncate und interpolate für Beschreibungen, Karten und Release Notes. Ein Designsystem oder eine CLI veröffentlicht kleine Utilities separat, damit Apps sie per SemVer aktualisieren können.
Veröffentlichung per GitHub Actions
CI-Publishing macht den Prozess prüfbar. npm Trusted Publishing kann per OIDC veröffentlichen und reduziert lange npm Tokens. Richte den trusted publisher in npm ein und beschränke die Veröffentlichung auf ein Release-Ereignis.
name: package
on:
push:
branches: [main]
pull_request:
release:
types: [published]
permissions:
contents: read
id-token: write
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org
cache: npm
- run: npm ci
- run: npm run docs
- run: npm test
- run: npm run build
- run: npm pack --dry-run
publish:
if: github.event_name == 'release'
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org
cache: npm
- run: npm ci
- run: npm run docs
- run: npm test
- run: npm run build
- run: npm publish --access public
Für strukturierte Changelogs passt Claude Code und Changesets zu diesem Ablauf.
Häufige Fallen
Die erste Falle ist main ohne exports. Die zweite ist ein zu breites Paket ohne strenges files. Die dritte ist ein veraltetes README. Die vierte ist ein zu starkes Unicode-Versprechen: Dieses truncate nutzt JavaScript-Stringlänge, nicht sichtbare Grapheme. Die fünfte ist, Claude Code über Name, Scope, 2FA, Trusted Publishing und finale Release-Freigabe entscheiden zu lassen.
Prompt für Claude Code
Create a TypeScript npm package.
Goal:
- Package name: @acme/string-kit
- Support both ESM import and CJS require
- Use tsup to emit dist/index.js, dist/index.cjs, and dist/index.d.ts
- Include README generation, Vitest tests, and npm pack verification
Constraints:
- Only touch package.json, tsconfig.json, tsup.config.ts, src, scripts, and .github/workflows
- Do not use pseudocode; the project must run after npm install
- Do not publish source maps or unnecessary test files in the package tarball
Acceptance criteria:
- npm test passes
- npm run build passes
- npm pack --dry-run output is summarized
- ESM import and CJS require smoke tests are shown
- List the human release checks before npm publish
CTA: Release-Qualität als Vorlage speichern
Ein npm-Paket ist nach dem ersten Release nicht fertig. Versionen, README, Node-Versionen in CI, Abhängigkeiten und Registry-Rechte ändern sich. Starte mit dem kostenlosen Claude Code Cheatsheet für sichere Prompts und Prüfkommandos. Wiederverwendbare Vorlagen findest du bei den ClaudeCodeLab Produkten. Für Teams mit CLAUDE.md, CI-Regeln, Rechten und Review-Prozess eignet sich Claude Code Training und Beratung.
Ich habe den Ablauf in einem temporären Windows-Ordner geprüft: npm install, npm test, npm run build, npm pack --dry-run und ESM/CJS-Smoke-Tests mit node -e liefen durch. In Masas Alltag findet die Bitte an Claude Code, die npm pack-Ausgabe vor dem Release zu erklären, oft veraltete README-Beispiele, fehlende Typen und unerwartete Tarball-Dateien.
Zusammenfassung
Claude Code beschleunigt npm-Pakete, aber der Veröffentlichungsvertrag muss klar bleiben. Verbinde package.json, exports, Typen, tsup, Tests, README, npm pack und CI zu einem Ablauf. Prüfe vor dem Release dist, den Tarball und die Einstiegspunkte, die Nutzer wirklich verwenden.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Permission Safety Ladder: Zugriff kontrolliert erweitern
Von read-only zu begrenzten Änderungen, Prüfbefehlen und Deploy-Checks mit klarer Kontrolle.
Claude Code Small PR Proof Pack: kleine Änderungen reviewbar machen
Ein Proof Pack für Claude-Code-PRs: Diff, Checks, öffentliche URL, CTA-Pfad und Rollback.
Claude-Code-Review-Gate vor dem Commit
Vor dem Commit mit Claude Code prüfen: Diff, Build, öffentliche URL, Gumroad-Links, Beratung-CTA, fehlende Tests und fremde Dateien.