np 
更好的
npm publish
为什么
- 交互式 UI
- 确保你正在从发布分支(默认为
main和master)进行发布 - 确保工作目录是干净的,并且没有未拉取的更改
- 重新安装依赖项,以确保你的项目与最新的依赖树兼容
- 确保你的 Node.js 和 npm 版本受项目及其依赖项支持
- 运行测试
- 更新 package.json 和 package-lock.json(如果存在)中的版本号,并创建 git 标签
- 防止在
latestdist-tag 下意外发布预发布版本 - 将新版本发布到 npm,可选地指定 dist-tag
- 如果发布失败,将项目回滚到之前的状态
- 将提交和标签(新创建的及之前创建的)推送到 GitHub/GitLab
- 支持双因素认证
- 在新仓库上启用双因素认证
(不适用于外部注册表) - 发布后打开预填好的 GitHub Releases 草稿
- 警告可能存在多余文件被发布的情况
- 通过 dry-run 模式 准确查看将要执行的操作,而不远程推送或发布任何内容
- 支持 GitHub Packages
- 支持 npm 10+、pnpm 11+、Bun 和 Yarn(Classic 和 Berry)
为什么不
- 不支持 Monorepos。
- CI 不是
np的理想环境。它旨在作为交互式工具在本地使用。
先决条件
- Node.js 22 或更高版本
- npm 10 或更高版本
- Git 2.11 或更高版本
安装
npm install --global np
用法
$ np --help
Usage
$ np <version>
Version can be:
patch | minor | major | prepatch | preminor | premajor | prerelease | 1.2.3
Options
--any-branch Allow publishing from any branch
--branch Name of the release branch (default: main | master)
--no-cleanup Skips np's node_modules cleanup step before install
--no-tests Skips tests
--yolo Skips cleanup and testing
--no-publish Skips publishing
--dry-run Show tasks without actually executing them
--tag Publish under a given dist-tag
--contents Subdirectory to publish
--no-release-draft Skips opening a GitHub release draft
--release-draft-only Only opens a GitHub release draft for the latest published version
--no-release-notes Skips generating release notes when opening a GitHub release draft
--test-script Name of npm run script to run tests before publishing (default: test)
--no-2fa Don't enable 2FA on new packages (not recommended)
--message Version bump commit message, '%s' will be replaced with version (default: '%s' with npm and 'v%s' with yarn)
--package-manager Use a specific package manager (default: package.json packageManager/devEngines)
--provenance Publish with npm provenance statements (CI-only)
--remote Git remote to push to (default: origin)
--stage Stage the publish for later approval (npm and pnpm only)
Examples
$ np
$ np patch
$ np 1.0.2
$ np 1.0.2-beta.3 --tag=beta
$ np 1.0.2-beta.3 --tag=beta --contents=dist
交互式 UI
不带参数运行 np 以启动交互式 UI,该界面将引导您发布新版本。
配置
np 可以全局和本地配置。当使用全局 np 二进制文件时,你可以在主目录中的 .np-config.js(作为 CJS)、.np-config.cjs、.np-config.mjs 或 .np-config.json 文件中配置任何 CLI 标志。当使用本地 np 二进制文件时,例如在 npm run 脚本中,你可以通过在 package.json 中的顶级 np 字段或项目目录中上述任一文件类型中设置标志来配置 np。如果存在,本地安装将始终优先。这确保了任何本地配置都与其所针对的 np 版本相匹配。
目前,这些是可以配置的标志:
-
anyBranch- 允许从任意分支发布(默认为false)。 -
branch- 发布分支的名称(默认为main或master)。 -
cleanup- 在安装依赖项之前删除node_modules(默认为true)。将其设置为false仅会跳过 np 的显式清理步骤;包管理器安装命令仍会运行,并可能替换node_modules本身。使用yolo可完全跳过安装。 -
tests- 运行npm test(默认为true)。 -
yolo- 跳过清理和测试(默认为false)。 -
publish- 发布(默认为true)。 -
dryRun- 显示任务而不实际执行它们(默认为false)。CLI 也接受--preview作为别名。 -
tag- 在指定的 dist-tag 下发布(默认为latest)。 -
contents- 要发布的子目录(默认为.)。 -
releaseDraft- 发布后打开 GitHub 发布草稿(默认为true)。 -
releaseNotes- 在打开 GitHub 发布草稿时自动生成发布说明(默认为true)。 -
testScript- 发布前运行测试的 npm run 脚本名称(默认为test)。 -
2fa- 在新包上启用 2FA(默认为true)(不推荐将此设置为false)。 -
message- 用于版本升级的提交信息。字符串中的任何%s都将被替换为新版本。默认情况下,npm 使用%s,Yarn 使用v%s。 -
packageManager- 设置要使用的包管理器。默认为 package.json 中的packageManager或devEngines.packageManager字段,因此仅在某些情况下无法更新 package.json 时才使用。 -
provenance- 使用 npm provenance statements (默认false) 发布。需要 npm 9.5.0+ 以及受支持的 CI 环境(GitHub Actions 或 GitLab CI/CD)。 -
remote- 用于推送标签和提交的 Git 远程仓库。在从 fork 发布时很有用,此时origin是你的 fork,而upstream是主仓库。 -
stage- 使用 staged publishing (默认false)。版本不会立即上线,而是上传到暂存队列,np会打印出stage approve命令,供你准备好时执行以提升版本(这需要 2FA,且可以稍后执行,例如从你的手机或 npmjs.com 执行)。仅支持 npm 和 pnpm,且仅适用于已在注册表中存在的包。
例如,这将配置 np 使用 unit-test 作为测试脚本,并使用 dist 作为发布子目录:
package.json
{
"name": "superb-package",
"np": {
"testScript": "unit-test",
"contents": "dist"
}
}
.np-config.json
{
"testScript": "unit-test",
"contents": "dist"
}
.np-config.js 或 .np-config.cjs
module.exports = {
testScript: 'unit-test',
contents: 'dist'
};
.np-config.mjs
export default {
testScript: 'unit-test',
contents: 'dist'
};
注意: 全局配置仅在使用全局 np 二进制文件时生效,且在使用本地二进制文件时永远不会被继承。
提示
npm 钩子
你可以在 package.json 中使用任何与 test/version/publish 相关的 npm 生命周期钩子 来添加额外行为。
例如,这里我们在标记发布之前构建文档:
{
"name": "my-awesome-package",
"scripts": {
"version": "./build-docs && git add docs"
}
}
发布脚本
你也可以将 np 添加到 package.json 中的自定义脚本里。如果你希望某个包的所有维护者以相同的方式发布(例如,别忘了推送 Git 标签),这会很有用。但是,你不能将 publish 用作脚本名称,因为它是 npm 定义的生命周期钩子。
{
"name": "my-awesome-package",
"scripts": {
"release": "np"
},
"devDependencies": {
"np": "*"
}
}
用户自定义测试
如果你想在发布前运行用户定义的测试脚本,而不是正常的 npm test 或 yarn test,你可以使用 --test-script 标志或 testScript 配置。当你的正常测试脚本带有 --watch 标志运行,或者你想在发布前运行某些特定测试(例如针对打包后的文件)时,这可能会很有用。
例如,np --test-script=publish-test 将运行 publish-test 脚本,而不是默认的 test。
{
"name": "my-awesome-package",
"scripts": {
"test": "ava --watch",
"publish-test": "ava"
},
"devDependencies": {
"np": "*"
}
}
签名的 Git 标签
设置 sign-git-tag npm 配置以签名 Git 标签:
$ npm config set sign-git-tag true
或设置 version-sign-git-tag Yarn 配置:
$ yarn config set version-sign-git-tag true
私有包
你可以使用 np 来处理未公开发布到 npm 的包(例如从私有 git 仓库安装的包)。
在你的 package.json 中设置 "private": true,发布步骤将被跳过。包括版本管理和推送标签在内的所有其他步骤仍会完成。
公共作用域包
要将 作用域包 发布到公共注册表,你需要将访问级别设置为 public。你可以通过在 package.json 中添加以下内容来实现:
"publishConfig": {
"access": "public"
}
如果首次发布一个作用域包,np 会提示你询问是否要将其公开发布。
注意: 发布作用域包时,你发布的首个版本必须使用 np 以交互方式完成。否则,你将无法使用 np 发布该包的未来版本。
私有组织作用域包
要发布 私有组织作用域包,你需要将访问级别设置为 restricted。你可以通过在 package.json 中添加以下内容来实现:
"publishConfig": {
"access": "restricted"
}
发布到自定义注册表
将 package.json 中的 registry 选项 设置为您的注册表 URL:
"publishConfig": {
"registry": "https://my-internal-registry.local"
}
包管理器
如果未在 package.json(packageManager 或 devEngines.packageManager)、通过配置(packageManager)或通过 CLI(--package-manager)中设置包管理器,np 将通过查找 lockfile 来尝试推断要使用的最佳包管理器。但建议在你的 package.json 中设置 packageManager 字段,以与其他工具保持一致。另请参阅 corepack 文档。
通过 CI 发布
如果你使用持续集成服务器来发布你的带标签的提交,请使用 --no-publish 标志来跳过 np 的发布步骤。
发布到 gh-pages
要发布到 gh-pages(或任何其他提供你的静态资源的分支),请安装 branchsite,这是一个类似于 np 的 CLI 工具,旨在补充 np,并创建一个在 np 之后运行的 npm "post" 钩子。
npm install --save-dev branchsite
"scripts": {
"deploy": "np",
"postdeploy": "bs"
}
初始版本
对于新包,在 package.json 中将 version 字段初始化为 0.0.0,并在发布时让 np 将其递增到 1.0.0 或 0.1.0。
发布旧主版本的更新
要为旧主版本发布次要/补丁版本,请从该主版本的 git 标签创建分支并运行 np:
$ git checkout -b fix-old-bug v1.0.0 # Where 1.0.0 is the previous major version
# Create some commits…
$ git push --set-upstream origin HEAD
$ np patch --any-branch --tag=v1
前置步骤在 macOS 上无限运行
如果您使用的是 macOS Sierra 10.12.2 或更高版本,您的 SSH 密钥口令默认不再存储到钥匙串中。这可能会导致 prerequisite 步骤无限运行,因为它会在后台提示输入您的口令。要修复此问题,请将以下行添加到您的 ~/.ssh/config 中,并运行一个简单的 Git 命令,例如 git fetch。
Host *
AddKeysToAgent yes
UseKeychain yes
如果你在使用 SSH 时遇到其他问题,请参阅 GitHub 的支持文章。
忽略策略
忽略策略,无论是维护在 package.json 中的 files 属性中,还是在 .npmignore 中,旨在帮助减小包的大小。为了避免因关键文件被意外忽略而导致包损坏,np 会打印出所有添加到 Git 的新文件和未发布的文件。测试文件和其他从不发布的常见文件 不在考虑范围内。np 假定是标准目录布局,或是在 package.json 中的 directories 属性中表示的自定义布局。
常见问题
通过 Yarn 发布我的包时出现错误
如果你遇到类似这样的错误……
❯ Prerequisite check
✔ Ping npm registry
✔ Check npm version
✔ Check yarn version
✖ Verify user is authenticated
npm ERR! code E403
npm ERR! 403 Forbidden - GET https://registry.yarnpkg.com/-/package/my-awesome-package/collaborators?format=cli - Forbidden
…请检查命令 npm access list collaborators my-awesome-package 是否成功。如果未成功,Yarn 已覆盖您的 registry URL。要修复此问题,请将正确的 registry URL 添加到 package.json:
"publishConfig": {
"registry": "https://registry.npmjs.org"
}
np 在“发布包”步骤期间挂起
如果 np 在发布期间无限期挂起,常见原因包括:
未退出的生命周期脚本
npm 在发布期间会自动运行诸如 prepublish、publish 和 postpublish 之类的生命周期钩子。如果这些脚本未退出(例如,以监视模式运行),np 将会挂起。
{
"scripts": {
"test": "vitest",
"publish": "npm run test && np"
}
}
解决方案:不要将脚本命名为 publish、prepublish 或 postpublish(这些是保留的 npm 生命周期钩子)。请改用类似 release 的名称:
{
"scripts": {
"test": "vitest run",
"release": "np"
}
}
在监视模式下运行的测试
如果你的测试脚本在监视模式下运行,它在运行完测试后不会退出。
解决方案:确保你的测试命令在运行后退出:
{
"scripts": {
"test": "vitest run",
"test:dev": "vitest"
}
}
Registry 配置问题
.npmrc 的 registry 配置中缺少末尾斜杠可能导致挂起。
解决方案:确保 registry URL 包含末尾斜杠:
@ORG:registry=https://npm.pkg.github.com/