npm 包发布全流程:从零发布到私有 Registry 配置
写好了一个工具库想发到 npm 上?或者公司内部需要搭建私有 npm 仓库管理通用组件?这篇讲清楚从零发布 npm 包的完整流程,以及私有 registry 的配置方式。
发布前的准备
1. 注册 npm 账号
bashnpm adduser # 按提示输入用户名、密码、邮箱 # 验证登录 npm whoami
2. package.json 必填字段
json{ "name": "@your-scope/package-name", "version": "1.0.0", "description": "一句话描述包的功能", "main": "dist/index.js", "types": "dist/index.d.ts", "files": ["dist"], "keywords": ["utility", "format", "date"], "license": "MIT", "repository": { "type": "git", "url": "https://github.com/you/package-name" } }
几个容易忽略但很关键的字段:
files:指定发布时包含哪些文件。不写的话 npm 会把项目根目录下几乎所有文件都打进去(包括测试文件、配置文件)。写了["dist"]就只发布编译产物,安装的人不会下载到源码和测试main:CommonJS 入口,require()时加载这个文件types:TypeScript 类型声明文件入口。没有这个字段,TypeScript 用户用你的包会没有类型提示name里的@your-scope/是作用域包——避免和别人的包名冲突,也支持发到私有 registry
3. .npmignore 控制排除项
shellsrc/ test/ .github/ .eslintrc tsconfig.json *.tsbuildinfo
和 .gitignore 类似,但专门控制 npm 发布时排除的文件。如果同时有 .npmignore 和 files 字段,files 优先级更高。
构建和发布
TypeScript 项目的标准构建流程
json{ "scripts": { "build": "tsc", "prepublishOnly": "npm run build" } }
prepublishOnly 是 npm 生命周期钩子——执行 npm publish 前自动跑 npm run build,确保发布的是编译后的代码而不是源码。
发布版本
bash# 首次发布 npm publish # 作用域包默认是私有的,要公开需要加 --access npm publish --access public # 后续更新:先改版本号再发布 npm version patch # 1.0.0 → 1.0.1(修复 bug) npm version minor # 1.0.1 → 1.1.0(新功能,向后兼容) npm version major # 1.1.0 → 2.0.0(破坏性变更) npm publish
npm version 会同时更新 package.json 的版本号并创建一个 git commit + tag——一步到位,不需要手动改版本号。
不要发布的文件
确保这些不会被打包发布:
.env文件(可能含密钥)node_modules/- 测试文件和 mock 数据
- IDE 配置(
.vscode/、.idea/) - CI 配置(
.github/workflows/)
用 npm pack --dry-run 可以预览将要发布的文件列表,不会真正打包:
bashnpm pack --dry-run # 输出类似: # npm notice 📦 @your-scope/utils@1.0.0 # npm notice Tarball Contents # npm notice 1.2kB dist/index.js # npm notice 0.8kB dist/index.d.ts # npm notice 1.1kB package.json
语义化版本(SemVer)
版本号格式:主版本.次版本.修订版本(Major.Minor.Patch)
- Patch(修订):修复 bug,不改变 API →
npm version patch - Minor(次版本):新增功能,向后兼容 →
npm version minor - Major(主版本):破坏性变更,不向后兼容 →
npm version major
原则:用户在 package.json 里写了 "^1.2.0",你发布 1.3.0 时他们自动升级,但发布 2.0.0 时不会——所以破坏性变更一定要升 Major。
私有 Registry 配置
企业内部不想把包发到公网,需要私有 registry。
使用 Verdaccio(轻量自建方案)
bash# 安装 npm install -g verdaccio # 启动(默认 4873 端口) verdaccio # 创建配置文件 ~/.config/verdaccio/config.yaml
yaml# config.yaml storage: ./storage plugins: ./plugins auth: htpasswd: file: ./htpasswd max_users: 100 uplinks: npmjs: url: https://registry.npmjs.org/ packages: '@company/*': access: $authenticated publish: $authenticated unpublish: $authenticated '**': access: $all proxy: npmjs # 非 @company 包代理到 npm 官方源
这个配置的意思是:@company/* 作用域的包只存在本地私有仓库,其他包自动代理到 npm 官方源。开发者不需要切换 registry——私有包和公共包都能装。
项目级配置
bash# 所有 @company 作用域的包走私有 registry npm config set @company:registry http://your-registry:4873 # 或在 .npmrc 文件中 @company:registry=http://your-registry:4873
发布到私有 registry
bashnpm publish --registry=http://your-registry:4873
或者在 package.json 中指定:
json{ "name": "@company/utils", "publishConfig": { "registry": "http://your-registry:4873" } }
publishConfig 比命令行参数更可靠——不会因为忘了加 --registry 而误发到公网。
CI 中自动发布
yaml# GitHub Actions 示例 - name: Publish to npm run: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
在 npm 网站上生成 Access Token(Settings → Access Tokens),添加到 GitHub Secrets 里。CI 环境不需要 npm login,靠 token 认证。
本地配置 token:
bash# .npmrc //registry.npmjs.org/:_authToken=${NPM_TOKEN}
常见问题
包名已被占用
换成作用域包:@your-name/package-name。作用域包的命名空间归你所有,不会和别人冲突。
发布后想撤回
bash# 24 小时内可以撤回(npm 官方限制) npm unpublish @your-scope/package-name@1.0.0 # 撤回整个包(慎用) npm unpublish @your-scope/package-name --force
超过 24 小时就撤不回了。所以发布前用 npm pack --dry-run 确认内容,用 npm publish --tag beta 先发预览版。
发错版本到生产
用 dist-tag 管理:
bash# 发布为 beta 版本 npm publish --tag beta # 安装 beta 版本 npm install @your-scope/package-name@beta # 正式版才用 latest(默认) npm publish # 默认 tag 是 latest
这样 npm install 只会安装 latest 版本,beta 需要显式指定。