Tips & Tricks (Aktualisiert: 2.6.2026)

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.

Ein npm-Paket mit Claude Code erstellen und veröffentlichen

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.

BereichEntscheidung im BeispielWas Claude Code prüfen soll
Name@acme/string-kitob ein scoped public Paket --access public braucht
NutzerNode.js und TypeScriptob ESM import und CJS require funktionieren
Buildtsup erzeugt ESM, CJS und Typenob dist die Dateien aus exports enthält
Inhaltnur dist, README.md, LICENSEob npm pack --dry-run unerwartete Dateien zeigt
ReleaseGitHub Actions + npm Trusted Publishingob 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.

#Claude Code #npm #繝代ャ繧ア繝シ繧ク蜈ャ髢・ #TypeScript #OSS
Kostenlos

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.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.