Tips & Tricks (更新: 2026/6/2)

用 Claude Code 创建并发布 npm 包的实战指南

用 Claude Code 创建 npm 包,覆盖 tsup、exports、类型声明、npm pack 验证和 CI 发布流程。

用 Claude Code 创建并发布 npm 包的实战指南

让 Claude Code 生成一个 npm 包并不难,难的是让这个包真正适合发布和维护。初学者最容易漏掉的不是函数实现,而是 package.json 的入口、exports、类型声明、README、npm pack 里的文件、以及发布 CI。只要其中一个环节不清楚,包可能在本地能跑,却在用户项目里无法 import、无法 require,或者把不该发布的文件一起上传到 registry。

本文用一个 TypeScript 字符串工具包作为例子。Claude Code 的角色不是替你盲目发布,而是帮助你生成文件、检查配置、解释风险。npm 规则会更新,所以正式发布前请对照官方资料:npm 的 package.json 文档scoped public packagesnpm packtrusted publishing 以及 Claude Code 官方说明

先写清楚包的设计

不要一开始只说“帮我做一个 npm 包”。更好的提示词应该说明包名、使用者、运行环境、模块格式、测试方式和发布策略。type: "module"mainexportstypes 是一组联动配置,后补容易出错。让 Claude Code 先根据下表检查,再开始写文件。

项目本文选择需要 Claude Code 检查
包名@acme/string-kitscoped public 包是否需要 --access public
使用者Node.js 和 TypeScript 用户ESM import 与 CJS require 是否都能工作
构建tsup 输出 ESM、CJS、声明文件dist 中是否存在 exports 指向的文件
发布内容只发布 distREADME.mdLICENSEnpm pack --dry-run 是否有意外文件
发布方式GitHub Actions + npm Trusted Publishing是否避免长期 npm token

流程可以先画出来,避免 Claude Code 只生成代码却忘记打包和发布检查。

flowchart LR
  A["设计说明"] --> 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"]

如果你的目标是 CLI 包,可以继续阅读 Claude Code CLI 工具开发。日常提示词和验证习惯可以参考 Claude Code 效率技巧

创建最小项目

先在干净目录中验证,不要直接塞进复杂 monorepo。小项目能让你更快分辨问题来自包配置、构建工具还是工作区本身。把下面命令作为 Claude Code 的完成条件之一,可以减少“看起来生成了很多文件,但无法运行”的情况。

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

package.json 是公开契约。main 面向 CJS,module 兼容部分旧 bundler,types 给 TypeScript,exports 控制现代入口。files 要收窄,否则测试数据、草稿、source map 或本地配置都可能被打包。

{
  "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 只负责类型检查,实际输出交给 tsup。这样构建路径单一,Claude Code 也更容易判断 dist 是否与 exports 对齐。

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

写可运行的实现和测试

文章里的代码必须能复制运行,而不是伪代码。下面的包包含四个小函数:slugify 生成英数字 slug,truncate 控制展示长度,interpolate 做简单模板替换,byteLength 返回 UTF-8 字节数。功能不大,但足够覆盖 ESM、CJS、类型、测试和打包。

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

测试要覆盖正常值、边界值、异常和 Unicode。向 Claude Code 提要求时,不要只写“加测试”,而是写清楚“重音字符、未知占位符、非法长度、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 和 README 生成

tsup 的配置保持简单。outExtension 把 ESM 输出成 .js,把 CJS 输出成 .cjs,这和 package.json 的入口一致。这里关闭 sourcemap,是为了避免发布包中意外带出内部源码映射;如果项目需要调试映射,要在发布前明确权衡。

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 很容易和代码不同步。用一个小脚本生成安装和使用示例,可以让 Claude Code 在 API 改动时同步更新文档,也能让 CI 在打包前重新生成 README。

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

用 npm pack 验证发布物

不要把 npm publish 当成第一次真正验证。npm pack --dry-run 会展示即将进入包里的文件。你要检查 README、LICENSE、类型声明、CJS/ESM 输出是否都在,测试文件和草稿是否不在。

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

更严格的做法是把生成的 .tgz 安装到另一个目录,模拟真实用户环境。这样可以发现只在本地源码旁边才会成功的配置错误。

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

这个模式至少有三个实用场景。第一,产品团队可以把重复的字符串格式化逻辑从多个应用中抽出来。第二,内容运营可以用同一套 truncateinterpolate 生成 description、卡片标题和发布说明。第三,设计系统或 CLI 可以把小工具独立发布,让应用按 SemVer 升级,而不是等待大仓库整体发布。

用 GitHub Actions 发布

CI 发布比手动发布更可审计。npm Trusted Publishing 可以通过 OIDC 从 GitHub Actions 发布,减少长期 npm token 的使用。先在 npm 后台配置 trusted publisher,再让 release 事件触发发布。仍然使用 token 的团队,也应该确认 2FA、provenance 和权限范围。

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

如果需要更细的版本说明,可以结合 Claude Code 与 Changesets 版本管理。它能让 Claude Code 更容易判断 patch、minor、major 的边界。

常见陷阱

第一个陷阱是只写 main,不写 exports。很多旧教程仍然这样做,但现代 TypeScript 和 bundler 更需要明确入口。第二个陷阱是发布内容过宽,导致测试数据、草稿、截图或 sourcemap 进入包。第三个陷阱是 README 失真,函数已经改名,文档仍然展示旧 API。

第四个陷阱是过度承诺 Unicode 支持。本文的 truncate 使用 JavaScript 字符串长度,不等于用户看到的字符簇长度。如果要支持 emoji 安全截断,请单独设计 Intl.Segmenter 版本并写明兼容性。第五个陷阱是让 Claude Code 直接决定发布。包名、scope、2FA、Trusted Publishing、最终 release approval 应由人确认。

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:把发布流程变成固定模板

npm 包发布不是一次性任务。版本、README、CI 的 Node.js 版本、依赖和 registry 权限都会变化。可以先领取 免费 Claude Code 速查表,把安全提示词和验证命令放在手边。需要可复用模板时,可以查看 ClaudeCodeLab 产品。如果团队要统一 CLAUDE.md、CI、发布权限和代码审查流程,可以从 Claude Code 培训与咨询 开始。

实际试用本文流程后,在 Windows 临时目录中完成了 npm installnpm testnpm run buildnpm pack --dry-run,并通过 ESM/CJS 的 node -e 冒烟测试。Masa 的经验是,让 Claude Code 在发布前解释 npm pack 输出,最容易提前发现 README 过期、声明文件缺失、tarball 内容异常这三类问题。

总结

Claude Code 可以加速 npm 包创建,但发布契约必须由你写清楚。把 package.jsonexports、类型、tsup、测试、README、npm pack 和 CI 连成一个流程,就能把 AI 生成的雏形推进到更接近公开质量的状态。发布前只问三件事:看过 dist 吗,看过 tarball 吗,用用户入口导入过吗。

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

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。