Créer et publier un package npm avec Claude Code
Créez un package npm avec Claude Code : tsup, exports, types, npm pack, README généré et publication CI.
Demander à Claude Code de créer un package npm donne vite un résultat. Publier un package fiable demande plus qu’une génération de fichiers. Il faut un package.json cohérent, des exports exacts, des types générés, un README à jour, une vérification npm pack et un workflow CI qui publie seulement quand les conditions sont réunies.
Ce guide utilise un petit package TypeScript d’utilitaires de chaînes. Claude Code sert ici d’assistant de génération et de revue, pas d’autorité qui publie sans contrôle humain. Pour rester aligné avec les règles actuelles, consultez les documents npm sur package.json, scoped public packages, npm pack, trusted publishing et la documentation officielle de Claude Code.
Définir le contrat du package
Le premier prompt doit préciser le nom, les utilisateurs, le runtime, les formats de module, les commandes de vérification et la politique de publication. type: "module", main, exports et types forment un ensemble. Si Claude Code en crée un sans vérifier les autres, le package peut compiler tout en étant difficile à consommer.
| Zone | Décision de l’exemple | Ce que Claude Code doit vérifier |
|---|---|---|
| Nom | @acme/string-kit | si un package scoped public exige --access public |
| Utilisateurs | Node.js et TypeScript | si ESM import et CJS require fonctionnent |
| Build | tsup produit ESM, CJS et déclarations | si dist contient les fichiers référencés par exports |
| Contenu | seulement dist, README.md, LICENSE | si npm pack --dry-run contient une surprise |
| Publication | GitHub Actions + npm Trusted Publishing | si le workflow évite les tokens npm durables |
Un schéma simple rend la revue plus claire.
flowchart LR
A["Brief package"] --> 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"]
Pour un package CLI, lisez aussi développer un outil CLI avec Claude Code. Pour les habitudes de prompt et de vérification, consultez les conseils de productivité Claude Code.
Créer le projet minimal
Commencez dans un dossier propre. Dans un grand dépôt, les erreurs peuvent venir du workspace, d’anciennes dépendances ou de scripts existants. Un package minimal permet de tester le contrat avant l’intégration.
mkdir string-kit
cd string-kit
npm init -y
npm install -D typescript tsup vitest @types/node
mkdir src scripts
Le package.json est le contrat public. main sert les consommateurs CJS, module aide certains bundlers, types sert TypeScript et exports contrôle les points d’entrée modernes. La clé files réduit le risque de publier tests, notes internes, sourcemaps ou configuration locale.
{
"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 vérifie les types; tsup émet les fichiers. Cette séparation rend la vérification plus simple pour Claude Code.
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"declaration": true,
"declarationMap": true,
"skipLibCheck": true,
"noEmit": true
},
"include": ["src", "tsup.config.ts"]
}
Implémentation et tests réels
Un article sur un package public ne doit pas s’arrêter à du pseudo-code. Le module exporte quatre fonctions : slugify, truncate, interpolate et byteLength. Le code est petit, mais il couvre les besoins d’un vrai package : types, tests, build et packaging.
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;
}
Les tests couvrent les cas normaux, les limites, les erreurs et Unicode. Demandez à Claude Code des tests précis : accents, placeholders inconnus, longueurs invalides et octets UTF-8.
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 et README généré
La configuration tsup reste compacte. outExtension produit .js pour ESM et .cjs pour CJS, ce qui correspond aux entrées du package.json. Le sourcemap est désactivé ici afin de ne pas publier des informations internes sans décision explicite.
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" };
},
});
Un README peut vite devenir faux. Un petit générateur garde l’installation et l’exemple d’utilisation alignés avec les exports.
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);
Vérifier avec npm pack
npm publish ne doit pas être la première vérification. npm pack --dry-run montre les fichiers qui seront envoyés. Vérifiez les sorties ESM/CJS, les types, README, LICENSE, et l’absence de tests ou brouillons.
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'))"
Pour un smoke test plus réaliste, installez le .tgz dans un autre dossier.
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)))"
Trois cas d’usage reviennent souvent. Une équipe produit partage les mêmes règles de texte entre web, admin et documentation. Une équipe contenu utilise truncate et interpolate pour descriptions et notes de version. Un design system ou une CLI publie de petits utilitaires pour permettre des mises à jour SemVer ciblées.
Publier avec GitHub Actions
La publication depuis CI rend le processus révisable. npm Trusted Publishing permet de publier via OIDC et réduit le besoin de tokens npm durables. Configurez d’abord le trusted publisher côté npm, puis limitez la publication à un événement release.
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
Pour mieux gérer les notes de version, combinez ce flux avec Claude Code et Changesets.
Pièges fréquents
Le premier piège est de garder seulement main sans exports. Le deuxième est de publier trop de fichiers faute d’un files strict. Le troisième est un README périmé. Le quatrième est de promettre un support Unicode que truncate ne fournit pas, car il utilise la longueur de chaîne JavaScript et non les grappes visibles. Le cinquième est de laisser Claude Code décider du nom final, du scope, de la 2FA, du trusted publisher et de l’approbation release.
Prompt 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 : garder le modèle de publication
Publier un package npm n’est pas une tâche unique. Versions, README, Node en CI, dépendances et permissions évoluent. Commencez par la fiche gratuite Claude Code pour garder prompts sûrs et commandes de vérification. Pour des modèles réutilisables, consultez les produits ClaudeCodeLab. Pour une équipe qui doit structurer CLAUDE.md, CI, permissions et revue, utilisez la page formation et conseil Claude Code.
J’ai testé ce flux dans un dossier temporaire Windows : npm install, npm test, npm run build, npm pack --dry-run et les smoke tests ESM/CJS avec node -e sont passés. Dans le travail de Masa, demander à Claude Code d’expliquer la sortie de npm pack avant release détecte souvent README obsolète, types manquants et fichiers inattendus dans le tarball.
Résumé
Claude Code accélère la création d’un package npm, mais le contrat de publication doit rester explicite. Reliez package.json, exports, types, tsup, tests, README, npm pack et CI. Avant publication, vérifiez dist, le tarball et les mêmes points d’entrée que vos utilisateurs.
PDF gratuit: cheatsheet Claude Code
Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.
Nous protégeons vos données et n'envoyons pas de spam.
À propos de l'auteur
Masa
Ingénieur spécialisé dans les workflows pratiques avec Claude Code.
Articles liés
Échelle de sécurité des permissions Claude Code
Passer du read-only aux éditions limitées, preuves et checks de déploiement sans perdre le contrôle.
Claude Code Small PR Proof Pack : rendre les petits changements reviewables
Un pack de preuve pour PR Claude Code : diff, vérifications, URL publique, CTA et rollback.
Gate de review avant commit avec Claude Code
Review avant commit avec Claude Code : diff, build, URL publique, liens Gumroad, CTA consultation, tests manquants et fichiers hors scope.