本指南深入 npm 的高级功能领域,涵盖 Workspaces、npx、Link、生命周期钩子、Dist-tags、Hooks、安全强化(2FA/Provenance/签名)、Profile 与 Completion 等。每个命令都配有真实示例,助您掌握专业级的 npm 工作流。
目录
- Workspaces:Monorepo 最佳实践
- Workspace 命令集
- npm exec 与 npx 高级用法
- npm link 高级用法
- 生命周期钩子高级模式
- Dist-tags:分发标签管理
- npm hook:包变更监控
- 安全高级主题:2FA、Provenance 与签名
- Provenance 与签名验证
- profile:用户资料管理
- completion:命令行自动补全
- version 高级技巧
- cache 与 config 高级管理
- diff:版本对比
- outdated:深入依赖过期分析
- access:包访问控制
- star:标记喜爱的包
- dedupe 与依赖树重构
- 发布高级选项:Provenance、tag、dry-run
- 高级工具与实践
1. Workspaces:Monorepo 最佳实践
npm Workspaces 是 npm 7+ 内置的 Monorepo 管理方案,允许在一个根目录下管理多个相关的包,统一依赖管理、脚本执行和版本发布。
1.1 基础配置
在根目录的 package.json 中声明工作区:
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*",
"apps/client",
"apps/server",
"!packages/deprecated" // 排除某些目录
]
}
1.2 初始化 Monorepo
# 创建根项目
mkdir my-monorepo && cd my-monorepo
npm init -y
npm pkg set private=true # 根包必须是私有的,不可发布
npm pkg set workspaces='["packages/*", "apps/*"]'
# 创建工作区子目录
mkdir -p packages/shared apps/web apps/api
cd packages/shared && npm init -y
cd ../apps/web && npm init -y
cd ../apps/api && npm init -y
📋 根包必须设置
private: true,否则 npm 会尝试将整个 Monorepo 发布为一个包。
1.3 工作区之间的相互引用
// packages/shared/package.json
{
"name": "@mycorp/shared",
"version": "1.0.0",
"main": "index.js"
}
// apps/web/package.json
{
"name": "@mycorp/web",
"dependencies": {
"@mycorp/shared": "1.0.0" // 自动链接到本地 packages/shared
}
}
📦 只要版本号匹配,npm 会自动将
@mycorp/shared链接到本地工作区,无需发布。
2. Workspace 命令集
2.1 安装依赖
# 为所有工作区安装依赖(共享依赖提升到根 node_modules)
npm install
# 为特定工作区安装依赖
npm install lodash --workspace=@mycorp/web
# 为所有工作区安装某个依赖(慎用,通常会注入到各自工作区)
npm install lodash --workspaces
2.2 执行脚本
# 在所有工作区运行 test 脚本
npm run test --workspaces
# 在特定工作区运行 build 脚本
npm run build --workspace=@mycorp/web
# 在多个指定工作区运行
npm run build --workspace=@mycorp/web --workspace=@mycorp/api
# 忽略缺失(若某个工作区没有 test 脚本,不报错)
npm run test --workspaces --if-present
2.3 查看工作区信息
npm ls --workspaces # 显示所有工作区的依赖树
npm ls -w a -w b # 显示指定工作区
2.4 高级工作区操作
# npm link 工作区中的某个包到其他项目(用于外部测试)
cd packages/shared
npm link # 创建全局链接
cd ../../external-project
npm link @mycorp/shared # 在外部项目中使用
# 在特定工作区中更新依赖
npm update --workspace=@mycorp/web
# 删除工作区中的 node_modules(递归)
rm -rf node_modules packages/*/node_modules apps/*/node_modules
# 重新安装所有依赖
npm ci --workspaces
3. npm exec 与 npx 高级用法
npm exec(和它的别名 npx)允许运行本地或远程 npm 包中的命令,无需全局安装。
3.1 基本用法对比
# 方式1:使用本地已安装的 tap,传递参数 --bail
npm exec -- tap --bail test/foo.js
# 方式2:npx(参数必须在命令之前)
npx tap --bail test/foo.js
💡 当运行
npx时,所有标志和选项必须放在位置参数之前;而通过npm exec时,用--分隔 npm 选项与命令参数。
3.2 多重包环境
# 提供多个包的环境
npm exec --package=foo --package=bar -- bar --bar-argument
# 显式指定包(避免与命令名冲突)
npx --package=foo bar --bar-argument
3.3 远程执行任意脚本
# 直接从 GitHub Gist 执行(⚠️ 安全警告)
npx https://gist.github.com/username/xxxxxx
# 使用 --yes 跳过确认提示
npx --yes create-react-app my-app
# 不下载(仅使用本地)
npx --no-install eslint
3.4 传递参数给脚本
在 package.json 脚本中使用 npm exec 接收参数:
{
"scripts": {
"serve": "npm exec -- http-server -p $npm_config_port"
}
}
npm run serve --port=8080
3.5 一步启动临时服务器
npx http-server . -p 3000
4. npm link 高级用法
npm link 是本地开发和调试的核心工具,安装步骤为两步:
4.1 两步法
# 步骤1:在包目录中创建全局符号链接
cd ~/projects/my-lib
npm link
# 步骤2:在消费项目中链接
cd ~/projects/my-app
npm link my-lib
4.2 一步法快捷方式
cd ~/projects/my-app
npm link ../my-lib # 一步完成:先全局链接,再链接到当前项目
4.3 带作用域的链接
npm link @mycorp/privatepackage
4.4 工作区中的使用
# 将外部包链接到指定工作区
npm link my-lib --workspace=@mycorp/web
# 将工作区中的包全局链接
npm link --workspace=@mycorp/shared
4.5 保存链接到 package.json
# 将链接保存为 file: 引用(适合临时分享配置)
npm link my-lib --save
# 仅更新 lock 文件而不添加 file: 引用(推荐)
npm install --package-lock-only
⚠️ 链接依赖默认不会被保存到
package.json。如果使用--save,会写入"my-lib": "file:../path/to/my-lib",其他人克隆后会失效。
4.6 解除链接
cd my-app
npm unlink my-lib # 移除项目端链接
npm install # 重新安装正式依赖
cd my-lib
npm unlink # 删除全局链接
4.7 注意事项与常见问题
当使用 npm link 时,被链接的包代码更改会实时同步到消费端。但如果遇到依赖重复实例(如 React 出现两份),是因为符号链接打破了模块解析规则。解决方案:
# 在消费项目中也链接 React(如果被链接包使用 React)
npm link ../my-lib/node_modules/react
5. 生命周期钩子高级模式
除了 pre 和 post,npm 还提供安装和发布时的特殊钩子。
5.1 完整的钩子执行顺序
| 钩子 | 触发时机 |
|---|---|
preinstall | 运行 npm install 之前 |
install / postinstall | 安装依赖完成后 |
preuninstall | 卸载包之前 |
postuninstall | 卸载包之后 |
prepack | npm pack 前(打包 tarball) |
postpack | npm pack 后 |
prepublishOnly | npm publish 前(推荐用于构建) |
prepare | 安装前和发布前运行(跨环境) |
preversion | 版本更新前 |
version | 版本更新后、git 提交前 |
postversion | git 提交后 |
5.2 高级组合示例
{
"scripts": {
"prepare": "husky install",
"prepublishOnly": "npm run test && npm run build",
"postpublish": "git push origin --tags",
"preversion": "npm run test",
"postversion": "git push && git push --tags"
}
}
5.3 条件性钩子结合环境变量
{
"scripts": {
"postinstall": "node -e \"process.env.CI || require('child_process').execSync('npm run setup')\"",
"setup": "husky install"
}
}
6. Dist-tags:分发标签管理
Dist-tags 是为特定版本命名的别名,npm install <pkg> 默认安装 latest 标签指向的版本。
6.1 查看标签
npm dist-tag list lodash
# latest: 4.17.21
# next: 5.0.0-beta.0
6.2 添加标签
# 为版本 1.4.0 添加 stable 标签
npm dist-tag add example-package@1.4.0 stable
# 将 2.0.0-beta.1 标记为 next(测试新功能)
npm dist-tag add axios@2.0.0-beta.1 next
6.3 删除标签
npm dist-tag rm example-package stable
6.4 发布时自动打标签
# 发布时指定标签,不修改 latest
npm publish --tag=beta
6.5 按标签安装
npm install my-package@beta # 安装 beta 标签的版本
npm install my-package@next
6.6 latest 标签的特殊性
- 默认
npm publish将版本设为latest latest是npm install的默认目标- 预发布版本(如 beta)不应设为 latest
7. npm hook:包变更监控
Hook 允许在包发布时接收 webhook 通知,可监控包、用户或作用域的变化。
7.1 添加 Hook
# 监控单个包的发布
npm hook add lodash https://your-server.com/webhook your-secret-key
# 监控一个用户的所有包(用户名前加 ~)
npm hook add ~substack https://example.com/hook secret
# 监控一个作用域(作用域名前加 @)
npm hook add @babel https://example.com/hook secret
7.2 查看 Hook
npm hook ls
npm hook ls lodash
7.3 更新 Hook
npm hook update 123abcd https://new-endpoint.com new-secret
# 123abcd 是从 npm hook ls 获取的 hook ID
7.4 删除 Hook
npm hook rm 123abcd
7.5 应用场景
- CI/CD 自动化:当依赖库发布新版本时,自动触发 CI 运行测试
- 安全监控:关键包发布时发送警报
- 通知服务:团队订阅重要包的更新
8. 安全高级主题:2FA、Provenance 与签名
8.1 配置双因素认证(2FA)
npm 强烈推荐为账户启用双因素认证,npm 现在要求通过 GitHub 等平台进行本地发布时启用 2FA。
在 Web 上启用:
- 登录 npmjs.com → Account Settings → Two-Factor Authentication
- 选择 Authorization and Publishing 模式(最安全)
- 使用 WebAuthn(如指纹、Face ID)代替 TOTP
在 CLI 中启用:
npm profile enable-2fa auth-and-writes # 推荐:发布和设置都需要 2FA
npm profile enable-2fa auth-only # 仅在登录时需要
# 查看 2FA 状态
npm profile get two-factor-auth
8.2 使用 OTP 发布(交互模式)
# 发布时提供一次性密码
npm publish --otp=123456
# 如果环境变量已设置 OTP,可省略
export NPM_OTP=123456
npm publish
8.3 自动化 Token
即使账户开启 2FA,自动化 token 仍可用于 CI 发布:
npm token create --automation
# 输出 token(如 npm_xxxxxx)
npm config set //registry.npmjs.org/:_authToken=npm_xxxxxx
8.4 组织级强制 2FA
# 在组织中强制要求 2FA
npm org set myorg require-2fa true
8.5 Trusted Publishing(OIDC)
这是 npm 的新一代安全机制。在支持 CI 中配置 OIDC,无需手动管理 token:
# GitHub Actions 示例
- name: Publish to npm
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
在 GitHub 仓库设置中,配置要求的发布身份来源(仅允许 actions/ 等可信路径)。
9. Provenance 与签名验证
Provenance(来源证明)为包生成加密签名的发布声明,将发布包与源代码和构建环境绑定。
9.1 启用 Provenance(npm 9.5.0+)
// package.json
{
"publishConfig": {
"provenance": true
}
}
发布时自动生成来源证明:
npm publish --provenance
在 GitHub Actions 中使用 OIDC 发布时,会自动附带来源证明。
9.2 查看来源证明
# 在 npm 网站上查看包的 Provenance 部分
# 或通过 CLI 获取
npm view my-package --json | jq '.provenance'
9.3 验证来源与签名完整性
# 验证 registry 签名(ECDSA)和来源证明
npm audit signatures
# 仅验证某一个包
npm audit signatures lodash@4.17.21
audit signatures 会:
- 检查签名密钥是否有效
- 验证包内容是否被篡改
- 验证来源证明与源代码的关联性
9.4 检查 registry 是否支持签名
curl https://registry.npmjs.org/-/npm/v1/keys
9.5 包完整性验证(integrity)
package-lock.json 中的 integrity 字段包含包的 SHA-512 哈希值,npm 会在安装时验证:
{
"packages": {
"node_modules/lodash": {
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}
}
}
10. profile:用户资料管理
在 CLI 中查看和修改 npm 账户资料。
10.1 查看资料
# 查看所有属性
npm profile get
# 查看特定属性
npm profile get email
npm profile get fullname
npm profile get homepage
npm profile get github
npm profile get twitter
输出示例:
{
"name": "zhangsan",
"email": "zhangsan@example.com",
"fullname": "Zhang San",
"homepage": "https://zhangsan.dev",
"github": "https://github.com/zhangsan",
"twitter": "https://twitter.com/zhangsan"
}
10.2 更新资料
npm profile set email new-email@example.com
npm profile set fullname "New Name"
npm profile set homepage https://new-website.com
10.3 更改密码
npm profile set password
# 交互式输入当前密码和新密码
10.4 管理 2FA(Profile 命令)
# 启用 2FA(交互式)
npm profile enable-2fa auth-and-writes
# 禁用 2FA(需要 OTP)
npm profile disable-2fa --otp=123456
11. completion:命令行自动补全
为 bash / zsh 生成 npm 命令自动补全脚本,极大提升效率。
11.1 生成补全脚本
npm completion >> ~/.bashrc # bash
npm completion >> ~/.zshrc # zsh
source ~/.bashrc
11.2 检查补全是否生效
# 输入 npm install --save-de 后按 Tab
# 应该自动补全为 --save-dev
11.3 不保存文件直接测试
npm completion | bash
12. version 高级技巧
12.1 自定义 commit 消息
npm version patch -m "chore(release): v%s"
# %s 会被替换为版本号(如 v1.0.1)
12.2 跳过 git 操作
npm version patch --no-git-tag-version --no-commit-hooks
12.3 预发布版本流水线
# 从 1.0.0 → 1.0.1-0 (prerelease)
npm version prerelease
# 从 1.0.0 → 1.0.1-beta.0
npm version prepatch --preid=beta
# 从 1.0.0 → 1.1.0-beta.0
npm version preminor --preid=beta
# 从 2.0.0-beta.0 → 2.0.0 (移除 prerelease 标识)
npm version patch
12.4 在 CI 中自动打 Tag
# GitHub Actions 示例
- name: Bump version
run: npm version patch --no-git-tag-version
- name: Commit and push
run: |
git config user.name "github-actions"
git commit -am "chore: bump version"
git tag v$(node -p "require('./package.json').version")
git push --follow-tags
13. cache 与 config 高级管理
13.1 验证缓存完整性
npm cache verify
输出示例:
Cache verified and compressed (~/.npm/_cacache)
Content verified: 1234 (127 MB)
Content garbage-collected: 56 (23 MB)
13.2 离线安装模式
# 优先使用缓存,缺失时才网络请求
npm install --prefer-offline
# 完全离线(节省 CI 时间)
npm install --offline
13.3 配置 Cache 策略
npm config set cache ~/.npm-cache
npm config set prefer-offline true
# 查看配置文件位置
npm config get userconfig # ~/.npmrc
npm config get globalconfig # /usr/local/etc/npmrc
13.4 多环境配置切换
# 使用 --location 参数指定配置层级
npm config set registry https://registry.npmmirror.com --location=project
npm config set registry https://registry.npmjs.org/ --location=global
14. diff:版本对比
npm diff 用于对比不同版本的包文件差异。
14.1 基本用法
# 在包目录中,对比当前版本与最新版本
npm diff
# 对比两个指定版本
npm diff lodash@4.17.20 lodash@4.17.21
# 对比当前包的两个版本
npm diff --diff=1.0.0 --diff=1.1.0
14.2 使用 semver 范围
# 对比当前包与最新兼容版本
npm diff --diff=^1.0.0
14.3 对比不同包的版本
npm diff --diff=express@4.18.2 --diff=knex@2.5.0
14.4 输出预览
diff --git a/index.js b/index.js
index abc123..def456 100644
--- a/index.js
+++ b/index.js
@@ -1,4 +1,5 @@
function add(a, b) {
- return a + b;
+ console.log('Adding numbers...');
+ return a + b + 0;
}
15. outdated:深入依赖过期分析
npm outdated 会检查 registry 以确定已安装的包是否有更新版本。
15.1 输出详解
npm outdated
输出:
Package Current Wanted Latest Location
lodash 4.17.20 4.17.21 4.17.21 my-app
express 4.17.1 4.18.2 4.18.2 my-app
webpack 5.75.0 5.88.0 5.88.0 my-app
- Current:当前安装的版本
- Wanted:符合
package.json范围的最大版本 - Latest:npm registry 中的最新版本
- 黄色:Wanted < Latest(有 major 升级,需谨慎)
15.2 高级选项
# JSON 输出(便于脚本分析)
npm outdated --json
# 仅生产依赖
npm outdated --only=prod
# 全局包
npm outdated -g --depth=0
# 长期支持的版本信息
npm outdated --long
15.3 使用 --depth 深入
# 默认 depth=0,只显示顶层依赖
npm outdated --depth=1
16. access:包访问控制
管理私有包的访问权限(适用于组织付费账户)。
16.1 设置访问级别
# 将作用域包设为公开(可被所有人安装)
npm access public @mycorp/secret-lib
# 设为私有(仅组织成员可访问)
npm access restricted @mycorp/secret-lib
16.2 管理团队权限
# 授予团队读取限
npm access grant read myteam @mycorp/secret-lib
# 授予团队读写权限
npm access grant read-write myteam @mycorp/secret-lib
# 撤销团队权限
npm access revoke myteam @mycorp/secret-lib
16.3 查看包权限
npm access ls-packages
npm access ls-collaborators @mycorp/secret-lib
16.4 配合 publishConfig
// package.json
{
"name": "@mycorp/secret-lib",
"publishConfig": {
"access": "restricted"
}
}
发布时自动设为私有,无需每次指定 --access。
17. star:标记喜爱的包
npm star 让用户标记喜欢的包。
17.1 星标包
# 星标一个
npm star lodash
# 批量星标
npm star lodash express react
17.2 取消星标
npm unstar lodash
17.3 查看已星标的包
# 查看自己星标的包列表
npm stars
# 查看他人星标的包
npm stars username
18. dedupe 与依赖树重构
npm dedupe 进一步扁平化依赖树,移除重复的包副本。算法会移动依赖至树中尽可能高的位置,以实现深度扁平化。
18.1 工作原理
假设初始树:
node_modules/
├── A@1.0.0
├── B@1.0.0 (依赖 C@1.0.0)
├── D@1.0.0 (依赖 C@1.0.0)
└── C@1.0.0 (已存在顶层)
运行 npm dedupe 后,会移除 B 和 D node_modules 下的 C 副本,顶层 C 同时满足三者。
18.2 依赖去重实践
# 去重
npm dedupe
# 安装时优先去重
npm install --prefer-dedupe
# 全局设置 prefer-dedupe
npm config set prefer-dedupe true
18.3 检测重复依赖
# 查看所有包(包括重复)
npm ls
# 查找重复包(将显示重复的实例)
npm ls --depth=1
18.4 是否经常需要 dedupe?
如果使用 npm ci 保持依赖整洁,则 dedupe 极少需要。但项目经过多次 npm install 和 npm remove 后,运行一次能帮助释放空间。
19. 发布高级选项:Provenance、tag、dry-run
19.1 完整的发布命令
# 使用 provenance + 指定标签 + OTP
npm publish --tag=beta --provenance --otp=123456
# 发布为公共访问(作用域包)
npm publish --access=public
# 发布到私有 registry
npm publish --registry=https://npm.mycorp.com
19.2 模拟发布
# 预览发布行为,不实际发送
npm publish --dry-run
# 打包检查文件列表
npm pack --dry-run
19.3 使用 prepare 自动构建
{
"scripts": {
"prepare": "npm run build",
"prepublishOnly": "npm test"
}
}
prepare 会在 npm install(git 依赖)和 npm pack/npm publish 前执行。
20. 高级工具与实践
20.1 使用 npx 一键运行所有检查
# 一次性运行 audit, outdated, doctor
npx npm-audit-resolver
20.2 npm run env 调试环境变量
npm run env | grep npm_package
20.3 npm explain 查找依赖来源
npm why lodash
20.4 构建可重复的 package-lock.json 合并策略
配置 git 使用 npm-merge-driver 自动处理 lock 文件冲突:
npx npm-merge-driver install --global
20.5 从私有 Git 仓库安装
npm install git+https://github.com/mycompany/private-lib.git
npm install git+ssh://git@github.com:mycompany/private-lib.git
20.6 为组织配置专用 registry
npm config set @mycorp:registry https://npm.mycorp.com
总结
npm 的高级功能极大提升了开发效率、安全性和代码管理能力。将 Workspaces、生命周期钩子、Dist-tags、Provenance、签名验证等工具融入日常开发,你将构建出专业、安全、可维护的现代 JavaScript 项目。
关键要点:
| 功能 | 核心价值 |
|---|---|
| Workspaces | Monorepo 原生支持,共享依赖和脚本 |
| npx / npm exec | 无需安装即可运行任意包命令 |
| npm link | 本地开发无缝调试 |
| 生命周期钩子 | 自动化测试、构建、发布流程 |
| Dist-tags | 版本分发策略,beta/stable 分离 |
| 2FA + Provenance | 供应链安全,防篡改 |
| npm audit signatures | 防包篡改 |
| npm dedupe | 减少磁盘占用,优化依赖树 |
| npm access | 私有包权限管理 |
| npm hook | 包变更实时通知 |