项目依赖

12 分钟阅读 · 17 组命令示例

包管理与构建指南:npm / pnpm / npx / scripts

适用场景:依赖安装与管理、npm scripts 编排、npx 执行、node_modules 排查、lock 文件冲突。

适用版本:Node.js 24 LTS、npm 11、pnpm 11;旧版本可能没有安装脚本审批等能力。

最后核对:2026-07-30

30 秒快速路径

bash
npm ci
npm run build
npm explain package-name

目录

  1. 核心概念
  2. npm 基础操作
  3. pnpm — 更快更省空间
  4. npm exec / npx — 临时执行
  5. package.json scripts
  6. 依赖管理进阶
  7. 安装脚本与供应链安全
  8. node_modules 排查
  9. lock 文件
  10. 发布与版本
  11. 常见问题

核心概念

依赖类型

字段 含义 安装命令
dependencies 运行时需要 npm i package
devDependencies 仅开发/构建时需要 npm i -D package
peerDependencies 声明与宿主包的兼容范围;npm 7+ 默认会尝试自动安装 由包管理器和宿主项目共同解析
optionalDependencies 可选,安装失败不报错 npm i -O package

版本号语义(SemVer)

text
major.minor.patch
  2   .  1  .  3

^ 兼容:^2.1.3 → >=2.1.3, <3.0.0(允许 minor + patch 升级)
~ 近似:~2.1.3 → >=2.1.3, <2.2.0(只允许 patch 升级)
固定:  2.1.3  → 精确这个版本

npm 基础操作

bash
# ═══ 初始化 ═══
npm init -y                    # 快速创建 package.json

# ═══ 安装 ═══
npm install                    # 安装 package.json 中所有依赖
npm i                          # 简写
npm i react                    # 安装到 dependencies
npm i -D typescript            # 安装到 devDependencies
npm i -g serve                 # 全局安装
npm i some-package@1.2.3       # 安装指定版本
npm i react@latest             # 安装最新版

# ═══ 卸载 ═══
npm uninstall react            # 移除并从 package.json 删除
npm un react                   # 简写

# ═══ 更新 ═══
npm outdated                   # 查看可更新的包
npm update                     # 更新所有(遵守 ^~ 范围)
npm update react               # 更新单个包

# ═══ 查看 ═══
npm list                       # 查看已安装的依赖树
npm list --depth=0             # 只看顶层
npm info react                 # 查看包信息
npm info react versions        # 查看所有可用版本

# ═══ 运行脚本 ═══
npm run dev                    # 运行 scripts.dev
npm run build                  # 运行 scripts.build
npm test                       # 特殊:可以省略 run
npm start                      # 特殊:可以省略 run

# ═══ 可复现安装与缓存 ═══
npm ci                         # 按 package-lock.json 全量安装;不改 lock
npm cache verify               # 优先验证缓存完整性
# npm cache clean --force      # 极少需要;确认缓存确实损坏后才清理

pnpm — 更快更省空间

pnpm 使用内容寻址存储,并通过硬链接或复制优化在同一 store/磁盘上复用包内容;具体占用取决于文件系统、store 位置与导入方式。

bash
# 安装 pnpm
npm i -g pnpm

# ═══ 基本命令(和 npm 几乎一样)═══
pnpm install                   # 安装所有依赖
pnpm add react                 # 安装到 dependencies
pnpm add -D typescript         # devDependencies
pnpm remove react              # 卸载
pnpm update                    # 更新
pnpm run dev                   # 运行脚本
pnpm dev                       # 可以省略 run(pnpm 特性)

# ═══ pnpm 独有功能 ═══
pnpm store status              # 查看全局存储状态
pnpm store prune               # 清理未引用的包
pnpm why react                 # 查看谁依赖了 react
pnpm list --depth=0            # 顶层依赖

# ═══ monorepo(workspace)═══
# pnpm-workspace.yaml:
# packages:
#   - 'packages/*'

pnpm -r run build              # 所有子包执行 build
pnpm --filter @app/web dev     # 指定子包运行
pnpm add lodash --filter @app/web  # 给指定子包装依赖

npm vs pnpm 对比

方面 npm pnpm
安装速度 取决于缓存、网络和项目 通常有较好的缓存与并发表现
磁盘占用 每项目独立副本 硬链接共享
未声明依赖访问 扁平布局下更容易意外访问 默认布局更严格,但可受 hoist 配置影响
monorepo 原生支持 npm workspaces 原生支持 pnpm workspaces 和过滤器
lock 文件 package-lock.json pnpm-lock.yaml

npm exec / npx — 临时执行

npxnpm exec 的便捷接口,两者都能运行项目本地或从 registry 获取的包命令。远程包会进入 npm cache,并非“用完不留”;执行陌生包等同于运行第三方代码,应固定版本并确认包名和来源。

bash
# 执行本地 node_modules/.bin 中的命令
npx tsc --init                 # 运行本地安装的 TypeScript
npx eslint .                   # 运行本地 ESLint
npm exec -- eslint .           # 等价的 npm exec 写法;-- 后面是命令参数

# 交互式创建新项目时,明确选择 latest
npm create vite@latest my-app -- --template react
npm create astro@latest

# 自动化或临时工具固定已审查版本,减少意外变化
npx serve@14 dist/             # 临时起一个静态文件服务器
npx json-server@1 db.json      # 临时起一个 REST API
npm exec --package=serve@14 -- serve dist/

# 结束端口监听者前先用系统命令确认 PID,不要直接运行陌生的 kill-port 包

# 指定主版本
npx create-next-app@16         # 使用已审查的 Next.js 16 脚手架

# 本地 package.json scripts 中 npx 可省略
# 因为 npm run 会自动把 node_modules/.bin 加到 PATH

package.json scripts

基础

json
{
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "preview": "astro preview",
    "lint": "eslint src/",
    "format": "prettier --write src/",
    "typecheck": "tsc --noEmit"
  }
}

高级模式

json
{
  "scripts": {
    "clean": "rimraf dist",
    "prebuild": "npm run clean",
    "build": "cross-env NODE_ENV=production astro build",
    "postbuild": "node -e \"console.log('Done!')\"",
    "check": "npm run lint && npm run typecheck",
    "dev": "concurrently \"npm:dev:*\"",
    "dev:app": "astro dev",
    "dev:css": "tailwindcss -w",
    "lint": "eslint",
    "start": "node server.js"
  }
}
  • prebuild / postbuild 会在 npm run build 前后自动执行。
  • && 串行执行,前一条失败后停止。
  • concurrently 用于并行任务。
  • 调用 npm run lint -- --fix 时,-- 后的参数传给底层命令。
  • 使用 rimrafcross-env 和 Node 命令,避免把 Unix 专用语法写进跨平台 scripts。

常用脚本工具

用途
concurrently 并行运行多个命令
cross-env 跨平台设置环境变量
npm-run-all 串行/并行运行多个 scripts
rimraf 跨平台的 rm -rf
wait-on 等待端口/文件就绪再执行

依赖管理进阶

bash
# ═══ 查看依赖关系 ═══
npm ls react                   # react 被谁引入的
npm ls --all                   # 完整依赖树
pnpm why react                 # pnpm 的 why 更清晰

# ═══ 查看包体积 ═══
# 线上工具:bundlephobia.com
npx package-size react react-dom  # 查看打包大小

# ═══ 安全审计 ═══
npm audit                      # 查看安全漏洞
npm audit fix                  # 自动修复
# npm audit fix --force        # 可能跨 major 升级;评估变更并测试后才考虑

# ═══ 查看全局安装了什么 ═══
npm list -g --depth=0
pnpm list -g

# ═══ 按现有 lock 干净重装 ═══
npm ci                         # 会自动移除现有 node_modules

# pnpm 版:保留 pnpm-lock.yaml
pnpm install --frozen-lockfile

删除 lock 文件会重新解析整棵依赖树,不应作为第一步排障。只有在明确调整依赖约束、确认 package.json 正确并准备评审完整 lock diff 时,才重新生成 lock。


安装脚本与供应链安全

依赖的 preinstallinstallpostinstall 等脚本会在本机或 CI 中执行代码。除了审计已知漏洞,还要控制“谁可以在安装时运行脚本”。

bash
# npm 11:查看、批准或拒绝依赖安装脚本
npm install-scripts ls
npm install-scripts approve sharp
npm install-scripts deny suspicious-package

# 一次性执行远程工具时,只批准确实需要脚本的包
npm exec --allow-scripts=reviewed-package --package=reviewed-package@1.2.3 -- reviewed-command

# pnpm 10.1+:交互审批依赖构建脚本
pnpm approve-builds
pnpm ignored-builds

pnpm 还可以在 pnpm-workspace.yaml 中延迟安装刚发布的版本。pnpm 11 默认 minimumReleaseAge 为 1440 分钟;显式写入可让团队策略清晰,并可用排除项处理确实需要立即升级的包:

yaml
minimumReleaseAge: 1440
minimumReleaseAgeExclude:
  - '@my-org/*'

安装脚本审批、lock 文件评审、固定运行时版本和来源校验互相补充,不能用其中一项代替全部供应链检查。


node_modules 排查

bash
# 查看 node_modules 大小
du -sh node_modules            # Linux/Git Bash

# 查看哪个包最大
du -sh node_modules/* | sort -rh | head -20

# 查看某个包为什么被安装
npm explain package-name       # npm 7+
pnpm why package-name

# 查看某个包的实际安装版本
node -p "require('./node_modules/react/package.json').version"

# 查看同一个包是否安装了多个版本
npm ls react --all

# 第三方静态分析工具可能误判动态 import、插件和脚本引用,删除依赖前要复核
npx depcheck
powershell
# PowerShell 查看 node_modules 大小
(Get-ChildItem node_modules -Recurse -File |
  Measure-Object Length -Sum).Sum / 1MB

lock 文件

作用

lock 文件锁定依赖的精确版本,确保团队/CI 安装完全相同的依赖树。

包管理器 lock 文件
npm package-lock.json
pnpm pnpm-lock.yaml
yarn yarn.lock

规则

  • lock 文件必须提交到 Git
  • 不要手动编辑 lock 文件
  • 不要混用包管理器(一个项目只用一种)

lock 冲突解决

bash
# 1. 先解决并检查 package.json 冲突
git diff -- package.json

# 2. 让当前 npm 根据已解决的 package.json 更新 lock
npm install --package-lock-only

# 3. 验证 lock 与 package.json 一致,并运行测试
npm ci
npm test                                  # 项目定义了 test script 时

# 4. 检查 lock diff 后再继续 merge/rebase
git diff -- package-lock.json
git add package-lock.json
git rebase --continue                     # rebase 流程
# merge 流程则正常 git commit

在 rebase 中,ours / theirs 的含义容易与直觉相反,不要不检查就对 lock 文件执行 git checkout --theirs。团队还应统一 npm 版本,减少无意义的 lock 格式抖动。


发布与版本

bash
# ═══ 版本号管理 ═══
npm version patch              # 0.1.0 → 0.1.1(自动 commit + tag)
npm version minor              # 0.1.0 → 0.2.0
npm version major              # 0.1.0 → 1.0.0

# ═══ 发布到 npm registry ═══
npm login                      # 登录
npm publish                    # 发布
npm publish --dry-run          # 模拟发布(不实际上传)
npm unpublish package@1.0.0    # 永久操作;是否允许取决于 registry 当前政策和依赖情况
npm deprecate package@1.0.0 "请升级到 1.0.1"  # 通常优先弃用错误版本

# ═══ 作用域包 ═══
npm publish --access public    # @scope/package 默认是 private,需要加 --access public

常见问题

ERESOLVE — 依赖冲突

bash
npm ERR! ERESOLVE unable to resolve dependency tree

# 先定位冲突双方及其 peerDependencies
npm explain conflicting-package
npm view conflicting-package peerDependencies

# 优先调整直接依赖版本,使 peer 范围真正兼容
# 仅在理解后果的临时场景使用:
npm i --legacy-peer-deps       # 忽略 peer 约束,运行时仍可能不兼容
# npm i --force                # 最后手段;必须完整测试

EACCES — 权限问题(Linux/macOS 全局安装)

bash
# 不要用 sudo npm install -g!改用:
mkdir ~/.npm-global
npm config set prefix "$HOME/.npm-global"
export PATH=~/.npm-global/bin:$PATH    # 加到 .bashrc/.zshrc

安装卡住或超时

bash
# 切换镜像源
npm config set registry https://registry.npmmirror.com    # 国内镜像
npm config get registry                                    # 查看当前源
npm config delete registry                                 # 恢复官方源

node 版本不兼容

bash
# 用 nvm 管理多个 node 版本
nvm install 24
nvm use 24
nvm list                       # 已安装的版本
nvm alias default 24           # 设置默认版本

# Windows 用 nvm-windows 或 fnm
fnm install 24
fnm use 24

官方参考