第一次发布 npm 包:从准备到正式发布

公開日: 2026-09-01 00:33 3333文字 17 min read

この投稿は「日本語」では表示できません。元の投稿を表示しています。
从 npm 包的用途、常见形式和打包方法讲起,再按顺序完成命名、配置、检查、本地安装和正式发布,适合第一次发布 npm 包的开发者。

如果手上只有一段代码或一个项目,第一步通常会让人困惑:怎样才算一个 npm 包?需要把源码放到哪里?npm pack 和 npm publish 又有什么区别?

先从这些基础概念开始,再按实际操作顺序走一遍完整发布流程。文中的 @your-name/my-tool、GitHub 地址和版本号都要换成自己的内容。

npm 包是什么

npm 包可以理解为一个准备好给别人安装的项目目录。目录中至少要有 package.json,它会告诉 npm:

  • 包叫什么、当前是什么版本。
  • 从哪个文件开始运行或导入。
  • 安装时还需要哪些依赖。
  • 哪些文件应该交给使用者。

一个常见的包目录如下:

my-tool/
├─ package.json
├─ README.md
├─ LICENSE
├─ src/
│  └─ index.ts
└─ dist/
   ├─ index.js
   └─ index.d.ts

这里的 src/ 存放源码,dist/ 存放构建后交付给使用者的文件。普通 JavaScript 项目也可以直接使用源码文件;TypeScript 和需要编译的项目通常会先生成 JavaScript。

安装一个 npm 包时,npm 会下载它的文件和运行依赖,并把它放进项目的 node_modules:

npm install @your-name/my-tool

npm registry 是存放和分发这些包的服务。公开发布后,其他人可以通过包名和版本安装同一份内容。

为什么要发布成 npm 包

适合发布的内容通常有这些:

  • 会在多个项目中重复使用的函数、组件或配置。
  • 希望提供给其他开发者使用的 SDK、插件或工具库。
  • 希望用户安装后直接在终端执行的 CLI。
  • 需要通过版本号维护和分发的公共模块。

完整的网站、桌面应用或服务端项目通常有自己的部署方式。只有其中需要复用或单独安装的部分,才需要整理成 npm 包。

npm 包有哪些形式

从使用方式看,常见形式有三种:

形式用户怎样使用需要配置的入口
普通库在代码中 import 或 requireexports 或 main
CLI安装后在终端运行命令bin
同时提供两种方式既能导入,也能运行命令exports 和 bin

从发布范围看,又可以分为:

形式示例适合什么情况
非 scoped 公共包my-tool名称简单,但要占用全局唯一包名
scoped 公共包@your-name/my-tool归在个人或组织名下,仍可供所有人安装
restricted 包@your-company/my-tool只给有权限的用户或团队使用
本地 .tgzmy-tool-0.1.0.tgz测试、内部传递,暂时不上传 registry

本文主要讲公开包。第一次发布时,使用个人 scope 往往更容易管理名称。

一段代码怎样变成 npm 包

先确定“包目录”。独立工具通常直接使用项目根目录;大型项目可以把要发布的部分放在 cli/、packages/my-tool/ 或单独生成的发布目录中。package.json 所在的目录就是包的根目录。

如果目录里还没有 package.json,可以先运行:

cd my-tool
npm init -y

然后完成下面几件事:

  1. 整理要提供给用户的代码。
  2. TypeScript 等源码先构建成可运行的 JavaScript。
  3. 在 package.json 中填写包名、版本、入口和依赖。
  4. 添加 README、LICENSE,并限制发布文件。
  5. 使用 npm pack 生成 .tgz。
  6. 安装这份 .tgz 做本地测试。
  7. 使用 npm publish 上传到 registry。

最小流程可以记成:

代码
→ package.json 和入口
→ 构建产物
→ npm pack
→ 本地安装测试
→ npm publish

npm pack 只在本地生成压缩包,不会公开任何内容:

npm pack

输出通常类似:

your-name-my-tool-0.1.0.tgz

这份 .tgz 就是等待检查和发布的 npm 包。理解这条流程后,再开始确定正式包名和发布账号。

1. 确定包名和命名空间

npm 包有两种常见命名方式:

my-tool              普通包
@your-name/my-tool   scoped 包

@your-name 叫作 scope,可以使用 npm 用户名或组织名。它相当于一层命名空间,适合管理一组相关的包,例如:

@your-name/core
@your-name/cli
@your-name/config

包名尽量使用小写字母和连字符,名称要能说明用途,也要避开他人的商标和相似包名。npm 的包名建议

可以先查一下名称是否已经存在:

npm view @your-name/my-tool

包名、GitHub 仓库名和 CLI 命令名可以不同。比如 npm 包叫 @your-name/my-tool,仓库叫 my-tool-repo,安装后的命令仍然可以叫 my-tool。

2. 准备 npm 账号和 2FA

到 npmjs.com 创建账号,验证邮箱,然后在账号设置中启用双重认证(2FA)。恢复码要另外保存,别放进项目目录或 Git 仓库。npm 2FA 指南

回到终端,确认 npm 使用官方 registry:

npm config get registry

正常结果是:

https://registry.npmjs.org/

然后登录并确认身份:

npm login --registry=https://registry.npmjs.org/
npm whoami --registry=https://registry.npmjs.org/

npm whoami 应该输出自己的 npm 用户名。如果项目里有 .npmrc,也要检查其中有没有其他 registry。不要把 token 提交到 Git。

3. 完善 package.json

下面是一份适合公开 CLI 包的简化示例:

{
  "name": "@your-name/my-tool",
  "version": "0.1.0",
  "description": "A small command-line tool for processing files.",
  "type": "module",
  "bin": {
    "my-tool": "./dist/cli.js"
  },
  "files": [
    "dist/",
    "README.md",
    "LICENSE"
  ],
  "engines": {
    "node": ">=20"
  },
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/your-name/my-tool.git"
  },
  "homepage": "https://github.com/your-name/my-tool#readme",
  "bugs": {
    "url": "https://github.com/your-name/my-tool/issues"
  },
  "publishConfig": {
    "registry": "https://registry.npmjs.org/",
    "access": "public"
  }
}

先看几个容易写错的字段:

  • name:npm 上显示和安装时使用的名称。
  • version:本次发布的版本,同一个版本不能重复发布。
  • files:允许进入 npm 包的文件,建议使用白名单。
  • bin:CLI 的入口。普通库不需要这个字段。
  • engines:项目实际支持的 Node.js 版本,不要直接照抄示例。
  • repository、homepage、bugs:源码、主页和问题反馈地址。
  • publishConfig:固定发布目标和访问级别,减少发错 registry 的机会。

如果是供代码导入的普通库,可以去掉 bin,改为配置入口:

{
  "type": "module",
  "exports": "./dist/index.js",
  "types": "./dist/index.d.ts"
}

只有生成了 index.d.ts,才填写 types。运行时需要的包放进 dependencies,构建和测试工具放进 devDependencies。npm package.json 文档

private: true 应该怎么用

"private": true 会直接阻止 npm publish。npm private 字段说明

开发阶段可以先加上它,防止误发:

{
  "private": true
}

如果直接从当前目录发布,最终验收前要删掉这个字段。删掉以后需要重新打包和检查,因为压缩包里的 package.json 也发生了变化。

有些项目会保留根目录的 private: true,再把准备发布的文件复制到单独目录。发布目录使用另一份精简的 package.json,其中不带 private: true。后面的 pack:cli 就属于这种做法。

GitHub 地址什么时候填

GitHub 仓库并非发布 npm 包的前置条件。不过,开源项目最好先创建仓库并推送代码,再填写 repository、homepage 和 bugs。这样可以直接验证链接,npm 包页面也不会出现空地址。

4. 添加 LICENSE 和 README

开源项目要选择许可证,并在包目录放一份完整的 LICENSE 文件。package.json 中的 license 要与它一致。MIT、Apache-2.0、GPL 等许可证的要求不同,选择前可以查看 Choose a License。

README 不用写得很长,至少包含:

  1. 这个包解决什么问题。
  2. 安装命令。
  3. 一个能直接复制的使用示例。
  4. 常用参数或配置。
  5. 支持的 Node.js 版本。
  6. 问题反馈地址和许可证。

CLI 包最好加上 --help 示例;普通库要写清楚怎样 import。README 放在发布包的根目录,npm 才会在包页面显示它。npm README 说明

5. 控制要发布的文件

npm 发布的是打包后的文件,不会直接照搬 Git 仓库页面。最简单的控制方式是在 package.json 中使用 files:

{
  "files": [
    "dist/",
    "README.md",
    "LICENSE"
  ]
}

这样比维护一长串排除规则更容易检查。.npmignore 也能排除文件,但最终结果仍然要以 npm pack 生成的内容为准。npm 文件包含规则

重点留意这些内容:

  • .env、token、私钥和证书。
  • 数据库备份、日志和真实用户数据。
  • 测试文件、旧构建产物和其他 .tgz。
  • 打包进 JavaScript 或 source map 的内部地址和敏感值。

6. 运行测试并生成 .tgz

先把项目本身检查一遍。下面是常见命令,按项目实际提供的脚本执行:

npm ci
npm run lint
npm run check
npm test
npm run build
npm audit

使用 pnpm 的项目可以改成:

pnpm install --frozen-lockfile
pnpm lint
pnpm check
pnpm test
pnpm build
pnpm audit

项目没有 check 或 build 脚本时不需要硬加。至少要保证测试通过,并重新生成准备发布的 dist/。

接着预览 npm 会收进去的文件:

npm pack --dry-run

确认文件列表和体积,再生成压缩包:

npm pack

运行后会得到类似这样的文件:

your-name-my-tool-0.1.0.tgz

.tgz 就是 npm 包的压缩文件。npm publish 最后上传的内容也会按这套规则打包。npm pack 文档

pack
是什么

pack:cli 只是项目自定义的脚本名,例如:

{
  "scripts": {
    "pack:cli": "node scripts/pack-cli.mjs"
  }
}

它常用于“主项目里附带一个 CLI”的情况。一个比较稳妥的流程是:

构建 CLI
→ 清空临时发布目录
→ 只复制 CLI 运行需要的文件
→ 生成精简的 package.json
→ 在发布目录执行 npm pack

主项目可以继续保留 private: true。脚本生成的发布目录只包含 dist、README、LICENSE 和发布用的 package.json,可以减少把网站源码、配置或环境文件一起发出去的机会。

独立的小型 npm 包直接使用 files 和 npm pack 就够了。Monorepo 如果使用 pnpm 的 workspace: 依赖,应通过对应 workspace 的打包流程生成包,并检查 .tgz 内的依赖版本。pnpm workspace 发布说明

7. 人工检查 .tgz

不要只看 npm pack 打印的摘要。先列出压缩包中的全部文件:

tar -tzf ./your-name-my-tool-0.1.0.tgz

再把它解压到一个空目录:

mkdir npm-package-review
tar -xzf ./your-name-my-tool-0.1.0.tgz -C npm-package-review

打开 npm-package-review/package/package.json,逐项确认:

  • 包名和版本正确。
  • 没有 private: true。
  • bin、exports、types 指向的文件都存在。
  • dependencies 中没有本地路径。
  • README 和 LICENSE 已包含。
  • 文件列表中没有密钥、环境文件、日志和无关源码。

还可以检查 JSON 能否正常解析:

node -e "JSON.parse(require('node:fs').readFileSync('./npm-package-review/package/package.json', 'utf8')); console.log('package.json OK')"

修改了源码、构建结果或 package.json,就重新生成并检查 .tgz。

8. 在空目录模拟安装

到仓库外面新建一个空目录,然后安装刚才检查过的 .tgz:

npm init -y
npm install "C:/path/to/your-name-my-tool-0.1.0.tgz"

CLI 可以这样测试:

./node_modules/.bin/my-tool --help
./node_modules/.bin/my-tool --version

Windows PowerShell 也可以运行:

./node_modules/.bin/my-tool.cmd --help

普通库可以测试导入:

node --input-type=module -e "import('@your-name/my-tool').then(console.log)"

最后照着 README 完整跑一次主要功能。这个步骤能发现缺少运行依赖、入口写错、文件漏打包等问题。

9. 确认本地代码已经推送

正式发布前,确认本地没有漏提交的改动:

git status
git fetch origin
git status -sb

查看当前提交和远程分支:

git rev-parse HEAD
git rev-parse origin/main

两个提交号应该一致。如果使用其他分支,把 origin/main 换成实际分支。

.tgz 和 dist/ 是否提交到 Git,要看项目约定。更重要的是保存好这次发布对应的源码提交。代码有变化时,重新执行测试、打包和空目录安装。

10. 正式发布

先做最后一次确认:

npm whoami --registry=https://registry.npmjs.org/
npm view @your-name/my-tool@0.1.0 version --registry=https://registry.npmjs.org/

首次发布时,第二条通常会返回找不到包或版本。注意区分名称不存在、网络错误和权限错误。

建议直接发布已经检查和安装过的 .tgz:

npm publish ./your-name-my-tool-0.1.0.tgz --access public --registry=https://registry.npmjs.org/

公开的 scoped 包要加 --access public。普通非 scoped 包也可以保留这个参数,命令更统一。npm scoped 包发布指南

终端会要求完成 2FA 验证。发布成功后,同一个包名和版本号不能再次使用;修复内容时要更新版本号。npm publish 文档

11. 发布后再安装一次

查看线上信息:

npm view @your-name/my-tool@0.1.0

然后在另一个空目录安装线上版本:

npm init -y
npm install @your-name/my-tool@0.1.0 --registry=https://registry.npmjs.org/

重复运行 README 中的主要示例,并打开 npm 包页面检查 README、LICENSE 和 GitHub 链接。

确认没有问题后,可以给对应的 Git 提交加版本标签:

git tag v0.1.0
git push origin v0.1.0

发布前检查清单

  • npm 账号、邮箱和 2FA 已设置好。
  • 包名、scope、版本号和 registry 正确。
  • package.json 的入口、依赖和仓库地址正确。
  • README 与 LICENSE 已放进包目录。
  • 测试和构建通过。
  • .tgz 已人工解压检查。
  • 在仓库外安装并运行过同一份 .tgz。
  • 本地源码已推送到对应远程提交。
  • 公开 scoped 包使用了 --access public。
  • 发布后已从 npm 安装线上版本。

気に入ったならばコメントを残してくださいね~