Tips & Tricks (Atualizado: 02/06/2026)

Criar e publicar um pacote npm com Claude Code

Crie um pacote npm com Claude Code usando tsup, exports, tipos, npm pack, README gerado e publicação via CI.

Criar e publicar um pacote npm com Claude Code

Pedir ao Claude Code para “criar um pacote npm” é simples. Publicar um pacote que outra pessoa consiga instalar com confiança exige mais cuidado. Você precisa de package.json consistente, exports corretos, tipos gerados, README alinhado com a API, checagem com npm pack e uma esteira de CI que publique somente quando os critérios forem cumpridos.

Neste guia vamos criar um pequeno pacote TypeScript de utilitários de string. O Claude Code será usado como parceiro de implementação e revisão, não como autoridade para publicar sem supervisão. Para decisões reais, consulte as fontes oficiais: npm package.json, scoped public packages, npm pack, trusted publishing e a documentação do Claude Code.

Defina o contrato do pacote

O primeiro prompt não deve ser genérico. Informe nome do pacote, público, runtime, formatos de módulo, comandos de verificação e política de publicação. type: "module", main, exports e types precisam apontar para a mesma história. Se um deles for gerado isoladamente, o pacote pode compilar e ainda assim falhar no projeto do usuário.

ÁreaDecisão do exemploO que o Claude Code deve verificar
Nome@acme/string-kitse pacote scoped público exige --access public
UsuáriosNode.js e TypeScriptse ESM import e CJS require funcionam
Buildtsup gera ESM, CJS e tiposse dist contém os arquivos em exports
Conteúdoapenas dist, README.md, LICENSEse npm pack --dry-run mostra arquivos inesperados
PublicaçãoGitHub Actions + npm Trusted Publishingse evita tokens npm de longa duração

O diagrama abaixo ajuda a manter implementação, testes, pacote e publicação no mesmo fluxo.

flowchart LR
  A["Brief do pacote"] --> 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"]

Se o pacote for uma CLI, veja também desenvolvimento de CLI com Claude Code. Para melhorar prompts e verificações, leia dicas de produtividade com Claude Code.

Crie o projeto mínimo

Comece em uma pasta limpa. Em um repositório grande, erros de pacote podem se misturar com workspace, dependências antigas e scripts já existentes.

mkdir string-kit
cd string-kit
npm init -y
npm install -D typescript tsup vitest @types/node
mkdir src scripts

O package.json é o contrato público. main atende CJS, module ajuda alguns bundlers, types atende TypeScript e exports controla os pontos de entrada modernos. files fica restrito para evitar publicar testes, rascunhos, sourcemaps ou configurações locais.

{
  "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 verifica os tipos e o tsup gera os arquivos finais. Essa divisão deixa claro para o Claude Code que dist precisa corresponder aos caminhos expostos.

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "declaration": true,
    "declarationMap": true,
    "skipLibCheck": true,
    "noEmit": true
  },
  "include": ["src", "tsup.config.ts"]
}

Implementação real e testes

Evite exemplo que parece código mas não roda. Este pacote exporta quatro funções pequenas: slugify para slugs ASCII, truncate para limitar texto, interpolate para templates simples e byteLength para contar bytes UTF-8.

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;
}

Os testes cobrem casos normais, limites, exceções e Unicode. Ao pedir testes ao Claude Code, seja explícito: acentos, placeholders desconhecidos, comprimentos inválidos e bytes 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 e README gerado

A configuração do tsup é pequena. outExtension emite ESM como .js e CJS como .cjs, alinhado com package.json. O sourcemap fica desligado para não publicar mapeamentos internos sem uma decisão consciente.

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 desatualizado é uma fonte comum de suporte. Um gerador simples mantém instalação e uso próximos da API real.

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);

Verifique com npm pack

npm publish não deve ser a primeira verificação real. npm pack --dry-run mostra os arquivos que serão enviados. Revise README, LICENSE, tipos, ESM/CJS e a ausência de testes ou rascunhos.

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'))"

Para uma prova mais próxima do usuário, instale o .tgz em outra pasta.

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)))"

Três usos práticos aparecem muito. Um time de produto compartilha regras de texto entre web, admin e documentação. Um fluxo de conteúdo usa truncate e interpolate em descrições, cards e notas de versão. Um design system ou CLI publica utilitários pequenos para que apps atualizem por SemVer.

Publique via GitHub Actions

Publicar por CI torna o caminho revisável. npm Trusted Publishing permite publicação por OIDC e reduz tokens npm longos. Configure o trusted publisher no npm e publique apenas em evento de 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

Para changelog e SemVer mais organizados, combine com Claude Code e Changesets.

Armadilhas comuns

A primeira armadilha é usar só main e esquecer exports. A segunda é publicar arquivos demais por não limitar files. A terceira é manter README antigo depois de mudar nomes de funções ou package scope. A quarta é prometer Unicode completo quando truncate usa comprimento de string JavaScript, não graphemes visuais. A quinta é deixar Claude Code decidir nome, scope, 2FA, Trusted Publishing e aprovação final de release.

Prompt para 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: transforme publicação em modelo

Publicar em npm não termina na primeira versão. README, CI, dependências, versões e permissões mudam. Comece pela cola gratuita de Claude Code para guardar prompts seguros e comandos de verificação. Para modelos reutilizáveis, veja os produtos ClaudeCodeLab. Para times que precisam organizar CLAUDE.md, CI, permissões e revisão, use treinamento e consultoria Claude Code.

Testei este fluxo em uma pasta temporária no Windows: npm install, npm test, npm run build, npm pack --dry-run e smoke tests ESM/CJS com node -e passaram. Na rotina de Masa, pedir ao Claude Code que explique a saída de npm pack antes do release encontra README desatualizado, tipos ausentes e arquivos inesperados no tarball.

Resumo

Claude Code acelera a criação de pacotes npm, mas o contrato de publicação precisa ser explícito. Una package.json, exports, tipos, tsup, testes, README, npm pack e CI. Antes de publicar, verifique dist, o tarball e os pontos de entrada que o usuário realmente usará.

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

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.