npm inityarnyarn initpnpmpnpm init交互式创建 package.json,逐项问名字、版本、入口、许可证等。
⚠ 常见坑: 默认按开源库填。如果是内部应用,务必加 `"private": true`,防止哪天手滑 `publish` 把代码推到公网。
npm init
yarn init
pnpm init
npm / yarn / pnpm 命令速查,80+ 条覆盖 init/install/scripts/publish,三个工具对照表。
npm inityarnyarn initpnpmpnpm init交互式创建 package.json,逐项问名字、版本、入口、许可证等。
⚠ 常见坑: 默认按开源库填。如果是内部应用,务必加 `"private": true`,防止哪天手滑 `publish` 把代码推到公网。
npm init
yarn init
pnpm init
npm init -yyarnyarn init -ypnpmpnpm init跳过所有提问,直接生成默认 package.json。开沙箱项目最快的方式。
⚠ 常见坑: pnpm init 没有 -y,因为它本来就不问,直接写默认值。Yarn berry (v2+) 同理,-y 会被忽略。
npm init -y
yarn init -y
pnpm init
npm init <initializer>yarnyarn create <initializer>pnpmpnpm create <initializer>用脚手架生成新项目(vite、next-app、react-app、astro 等)。实际等价于跑 `create-<initializer>`。
⚠ 常见坑: 实际执行的是 `create-<name>` 这个包,不是 `<name>`。`npm init vite` 跑的是 `create-vite`。知道这个原理就能看懂在下载什么。
npm init vite@latest my-app
yarn create next-app my-app
pnpm create astro@latest
npm init <scope>/<initializer>yarnyarn create @<scope>/<name>pnpmpnpm create @<scope>/<name>从带 scope 的脚手架包生成(如 @vitejs/app、@sveltejs/kit)。
npm init @vitejs/app my-app
pnpm create @sveltejs/kit my-app
npm pkg get <field>yarn— 不支持 —pnpm— 不支持 —在命令行直接读 package.json 里某个字段。脚本和 CI 里非常好用。
⚠ 常见坑: 返回的是 JSON 引号包裹的字符串,`npm pkg get version` 给的是 `"1.2.3"`(带引号)。管道 `jq -r` 或 `tr -d \"` 去掉。
npm pkg get version
npm pkg get scripts
npm pkg get dependencies.react
npm init -y --scope=@<scope>yarn— 不支持 —pnpm— 不支持 —生成默认 package.json,名字直接带 scope(如 @acme/utils),省得首次发布前手动改名。
npm init -y --scope=@acme
npm init --scope=@my-org -y
npm pkg set <field>=<value>yarn— 不支持 —pnpm— 不支持 —从命令行写 package.json 任意字段。嵌套键用点路径,数组用结尾 [] 追加。
⚠ 常见坑: 写嵌套对象加 `--json`: `npm pkg set repository.url="git+https://..." --json`,值会按字符串类型写入,而不是被瞎猜。
npm pkg set type="module"
npm pkg set "keywords[]"="cli"
npm pkg set engines.node=">=20" --json
npm pkg fixyarn— 不支持 —pnpm— 不支持 —自动修常见 package.json 问题: 规整 "bin" 字段、修 repository URL 格式、排好已知键。发布前的静默清理。
npm pkg fix
corepack enableyarncorepack enablepnpmcorepack enable启用 Corepack(Node 16.9+ 自带),"packageManager" 里钉死的 yarn / pnpm 版本会被自动调用,不用全局装。
⚠ 常见坑: 要在 package.json 写 `packageManager: "pnpm@9.1.0"` 钉死版本。不写这个字段 Corepack 就没东西可强制,每台机器版本各漂各的。
corepack enable
corepack prepare pnpm@9.1.0 --activate
"packageManager": "pnpm@9.1.0"
npm installyarnyarn installpnpmpnpm install安装 package.json 里列出的全部依赖。读取(或生成)锁文件。JS 生态最常敲的命令。
⚠ 常见坑: 裸跑 `install` 如果 package.json 跟锁文件对不上,会顺手改锁文件。CI 里要用 `npm ci` / `yarn install --frozen-lockfile` / `pnpm install --frozen-lockfile`,锁文件不一致就报错而不是悄悄改。
npm install
npm i
yarn
pnpm i
npm install <pkg>yarnyarn add <pkg>pnpmpnpm add <pkg>加运行时依赖。写入 package.json 的 "dependencies",同时更新锁文件。
⚠ 常见坑: npm 用 `install`/`i`,yarn/pnpm 用 `add`。混着写不会报错,`yarn install <pkg>` 会默默忽略包名,只装现有依赖。
npm install react
yarn add react
pnpm add react
npm install <pkg> -Dyarnyarn add <pkg> -Dpnpmpnpm add <pkg> -D加仅开发期依赖(typescript、eslint、vitest)。写入 "devDependencies"。
⚠ 常见坑: -D 不是装饰,生产安装(`npm ci --omit=dev`)会跳过 devDependencies。构建工具放 -D,运行时依赖放普通 deps。
npm install typescript -D
yarn add eslint -D
pnpm add vitest -D
npm install <pkg> -gyarnyarn global add <pkg>pnpmpnpm add -g <pkg>全局安装 CLI,可执行文件进 $PATH(如 pnpm、vercel、typescript)。
⚠ 常见坑: Yarn berry (v2+) 彻底去掉了 `yarn global`,一次性跑用 `yarn dlx`,常驻就用 npm 装。全局包还是"在我机器上能跑"问题最大来源。
npm install -g pnpm
yarn global add typescript # classic only
pnpm add -g vercel
npm install <pkg>@<version>yarnyarn add <pkg>@<version>pnpmpnpm add <pkg>@<version>指定具体版本、范围、或 dist-tag。`@latest` 强制装最新,`@next` 装预发布。
⚠ 常见坑: 已装过的包,光加 `@latest` 不一定会升,还得带 `--save` 或显式指更高范围。要在现有范围内升,用 `npm update <pkg>`。
npm install react@18.2.0
yarn add lodash@^4.17.0
pnpm add next@latest
npm ciyarnyarn install --frozen-lockfilepnpmpnpm install --frozen-lockfile干净安装。先清空 node_modules,严格按锁文件装。package.json 和锁文件不一致就直接报错。CI 上应该用这个。
⚠ 常见坑: npm ci 必须有 package-lock.json,没有立刻报错。Yarn berry 用 `yarn install --immutable`(--frozen-lockfile 的新别名)。
npm ci
yarn install --frozen-lockfile
pnpm install --frozen-lockfile
npm install --save-exactyarnyarn add <pkg> --exactpnpmpnpm add <pkg> --save-exact装包时不加 ^ / ~ 前缀,package.json 写死具体版本。跨机器要字节一致时有用。
⚠ 常见坑: 写死会让你拿不到补丁修复。对应用类项目,靠锁文件保证可复现,package.json 里留 semver 范围,这样 `npm update` 才有意义。
npm install react --save-exact
pnpm add lodash --save-exact
npm install <pkg> -Oyarnyarn add <pkg> -Opnpmpnpm add <pkg> -O加到 "optionalDependencies"。装失败(比如原生模块编译失败)会被忽略,而不是整个中断。
npm install fsevents -O
pnpm add fsevents -O
npm install <pkg> -Pyarnyarn add <pkg> -Ppnpmpnpm add <pkg> -P强制加到 "dependencies"(npm 默认就是)。一般用于覆盖之前 -D 装错的位置。
npm install react -P
pnpm add react -P
npm install <pkg> --legacy-peer-depsyarn— 不支持 —pnpm— 不支持 —禁用 npm 7+ 自动装 peer 依赖的新行为,退回 npm 6 处理方式。某个传递 peer 冲突时常用。
⚠ 常见坑: 老项目升级时这是常用救命开关。Yarn 默认就忽略 peer 冲突;pnpm 反过来,会严格报错。
npm install --legacy-peer-deps
npm install react@18 --legacy-peer-deps
npm install <pkg> --forceyarnyarn add <pkg> --forcepnpmpnpm add <pkg> --force即使缓存说包还好,也强制重新拉一次,并覆盖冲突警告。最后手段,慎用。
⚠ 常见坑: pnpm --force 还会把 node_modules 整个清空重新展开,比 npm/yarn 重得多。先试普通 `pnpm install`。
npm install --force
pnpm install --force
npm install <git-url>yarnyarn add <git-url>pnpmpnpm add <git-url>直接从 git 仓库装(fork、未发布分支、私有仓库)。
⚠ 常见坑: 锁文件钉的是 commit hash,不是分支,再跑 `install` 不会拉新 commit,要重新 add。要靠谱就 #commit 钉死。
npm install github:user/repo
yarn add git+https://github.com/user/repo.git#v1.2.3
pnpm add github:user/repo#main
npm install file:<path>yarnyarn add file:<path>pnpmpnpm add file:<path>从本地目录或 tarball 装。发布前本地验证很有用。
⚠ 常见坑: pnpm 会把目录复制到 store,改源码后要重装。开发期实时联动用 `link:` 或 `pnpm link`。
npm install file:../my-lib
pnpm add link:../my-lib
npm install ./my-lib-1.0.0.tgz
npm install --omit=devyarnyarn install --productionpnpmpnpm install --prod跳过 devDependencies。生产 Docker 镜像或上线部署用这个。
⚠ 常见坑: 老 npm 用 `--production`,会顺手把 NODE_ENV 设成 production。`--omit=dev` 是新写法(npm 7+),语义更明确,优先用。
npm install --omit=dev
npm ci --omit=dev
pnpm install --prod
npm install --ignore-scriptsyarnyarn install --ignore-scriptspnpmpnpm install --ignore-scripts不跑 postinstall / preinstall / install 脚本。审计新依赖时这是关键的安全加固。
⚠ 常见坑: postinstall 脚本是无数供应链攻击的入口。.npmrc 里默认 `ignore-scripts=true`,信任的包再单独允许。
npm install --ignore-scripts
# .npmrc default: ignore-scripts=true
pnpm install --ignore-scripts
npm iyarnyarnpnpmpnpm i日常最常敲的安装简写。yarn 不带子命令就是安装;`npm i` 和 `pnpm i` 是官方别名。
npm i
yarn
pnpm i
npm install <pkg>@<tag>yarnyarn add <pkg>@<tag>pnpmpnpm add <pkg>@<tag>按 dist-tag 装,而不是版本号。`@next` / `@beta` / `@canary` 拉预发布;`@latest` 强制装最新稳定版。
⚠ 常见坑: tag 是会移动的指针,不是冻结的版本。锁文件记的还是当时解析出的具体版本,所以即便 tag 后来动了,重装仍可复现。
npm install next@canary
yarn add react@beta
pnpm add vite@next
npm install <alias>@npm:<pkg>yarnyarn add <alias>@npm:<pkg>pnpmpnpm add <alias>@npm:<pkg>把一个包以另一个本地名字装下来(别名)。能让同一个库的两个大版本并存。
⚠ 常见坑: 渐进迁移很好用: `npm i lodash4@npm:lodash@4` 和 `lodash3@npm:lodash@3` 同时存在,调用点一个一个挪。
npm install react18@npm:react@18
yarn add vue2@npm:vue@2
pnpm add lodash-es@npm:lodash-es@4
npm install --save-prefix=<char>yarn— 不支持 —pnpm— 不支持 —控制写进 package.json 的版本范围前缀。`~` 只允许补丁更新,`^` 允许小版本,空字符串写死。
⚠ 常见坑: 在 .npmrc 里设一次 `save-prefix="~"`,整个项目走同一策略,不靠每个人记得加 flag。
npm install react --save-prefix="~"
# .npmrc save-prefix=~
npm install --no-saveyarnyarn add <pkg> --mode=skip-buildpnpmpnpm add <pkg> --no-save把包装进 node_modules 但不写进 package.json。临时试一下、不想提交时好用。
⚠ 常见坑: 因为 package.json 里没留痕,之后一跑 `npm ci` 就没了。--no-save 装的东西当用完即弃,别拿来当真依赖。
npm install some-tool --no-save
npm install ./local-tgz --no-save
npm install --prefer-offlineyarnyarn install --prefer-offlinepnpmpnpm install --prefer-offline能用本地缓存就用,只有缺的才走网络。网不稳时安装更快。
⚠ 常见坑: `--offline` 是更严的兄弟: 完全不碰网络,缺缓存就报错。隔离网络的 CI 用 --offline,日常提速用 --prefer-offline。
npm install --prefer-offline
npm ci --prefer-offline
pnpm install --offline
npm install --include=optionalyarn— 不支持 —pnpm— 不支持 —显式安装 optionalDependencies(默认就装,但 `--omit=optional` 或某些 CI 配置可能关掉了)。
⚠ 常见坑: 经典场景: Mac 上开发、Linux CI 安装,`@rollup/rollup-linux-x64-gnu` 这类按平台分的 optional 不一样。锁文件在目标系统上生成,或谨慎用 `--omit=optional`。
npm install --include=optional
npm install --omit=optional
npm dedupeyarnyarn dedupepnpmpnpm dedupe把依赖树压扁: 重复的子依赖往上提,让一份共享副本满足多个依赖方。node_modules 变小。
⚠ 常见坑: 大升级后跑一下,清掉解析器残留的冗余重复版本。yarn berry 内置;npm 7+ 大多数安装也会自动去重。
npm dedupe
npm ddp
pnpm dedupe
npm install --offlineyarn— 不支持 —pnpmpnpm install --offline完全不联网,严格从缓存装。有任何包没缓存就直接报错。可复现构建 / 隔离网络环境专用。
npm install --offline
pnpm install --offline
npm run <script>yarnyarn <script>pnpmpnpm <script>执行 package.json 的 "scripts" 里定义的脚本(build、dev、lint、自定义都行)。
⚠ 常见坑: Yarn 可以省 `run`;pnpm 也可以,但脚本名和内置命令冲突时(如 `install`、`add`、`test`),必须写 `pnpm run <script>`。
npm run build
yarn build
pnpm dev
npm startyarnyarn startpnpmpnpm start`npm run start` 的快捷方式。如果没定义 start 脚本,npm 会回退到 `node server.js`。
npm start
yarn start
pnpm start
npm testyarnyarn testpnpmpnpm test`npm run test` 的快捷方式。三个工具都特殊照顾,不用写 `run`。
npm test
yarn test
pnpm test
npm run <script> -- --flagyarnyarn <script> --flagpnpmpnpm <script> --flag给底层命令传额外参数。npm 必须用 `--` 隔开;yarn 和 pnpm 自动透传。
⚠ 常见坑: npm 漏写 `--`,flag 会被 npm 自己吃掉,不会传给脚本。"为什么我 --watch 没生效"经典坑。
npm run build -- --watch
yarn test --coverage
pnpm lint --fix
npm pkg set scripts.<name>="<cmd>"yarn— 不支持 —pnpm— 不支持 —不用打开 package.json,从命令行直接改。新增或替换一条 scripts 条目。npm 7+ 才有。
⚠ 常见坑: Yarn 和 pnpm 没有等价命令,它们建议直接改 JSON。`npm pkg` 在任何项目里都能用,跟你用哪个包管理器无关。
npm pkg set scripts.build="vite build"
npm pkg set scripts.lint="eslint ."
npm pkg get scripts
npm pkg delete scripts.<name>yarn— 不支持 —pnpm— 不支持 —从命令行删 package.json 里的一条 scripts。配合 `npm pkg set` 用。
npm pkg delete scripts.test
npm pkg delete scripts.prepublish
npm runyarnyarn runpnpmpnpm run不带脚本名时,列出 package.json 里定义的所有脚本。
npm run
yarn run
pnpm run
npx <pkg>yarnyarn dlx <pkg>pnpmpnpm dlx <pkg>不永久装包,直接跑某个 npm 包的可执行文件。一次性命令(create-vite、knip、depcheck)首选。
⚠ 常见坑: npx 会缓存下载的包,第二次就快。yarn dlx / pnpm dlx 每次都重新下,保证"全新"。CI 上按"缓存成本 vs 可复现"权衡。
npx create-vite my-app
yarn dlx knip
pnpm dlx serve dist
npm exec <pkg>yarnyarn exec <pkg>pnpmpnpm exec <pkg>跑本地 node_modules 里的可执行文件,不用敲 `./node_modules/.bin/<cmd>`。npx/dlx 的"不联网"版本。
⚠ 常见坑: npx 找不到本地 binary 会回退去下载。`npm exec` 直接报错,CI 行为更可预期。
npm exec vitest
pnpm exec eslint .
yarn exec prettier --write .
npm run pre<name> / post<name>yarn— 不支持 —pnpm— 不支持 —生命周期钩子: 名为 `prebuild` 的脚本会自动在 `build` 之前跑,`postbuild` 在之后跑。无需配置。
⚠ 常见坑: pnpm 默认禁用了 pre/post 自动执行(pnpm 7 起),依赖这个特性的话,.npmrc 里加 `enable-pre-post-scripts=true`。
"prebuild": "rm -rf dist"
"postinstall": "patch-package"
# pnpm: enable-pre-post-scripts=true
npm run <a> && npm run <b>yarn— 不支持 —pnpm— 不支持 —在脚本值里用 shell 操作符串联。`&&` 顺序执行,前一个失败就停;`&` 后台并行。
⚠ 常见坑: 跨平台并行别靠 `&&` 那套,用 `npm-run-all`(run-s / run-p)或 `concurrently`,Windows 才和 macOS/Linux 行为一致。
"ci": "npm run lint && npm run test && npm run build"
npx run-p lint test
npx concurrently "npm:dev:*"
npm run <script> --silentyarnyarn <script> --silentpnpmpnpm <script> --silent压掉 npm 自己的日志头和生命周期噪音,只留脚本真正的输出。把输出管道给别的命令时尤其好用。
⚠ 常见坑: 别名 `-s`。要彻底安静在 .npmrc 写 `loglevel=silent`。不加 --silent,`npm run get-version` 会把 npm 横幅一起灌进下游命令,解析就乱了。
npm run env --silent
npm run --silent version-info | jq
pnpm -s build
npm run-script <name>yarn— 不支持 —pnpm— 不支持 —`npm run` 的全名。`run` 只是 `run-script` 的别名。读老文档或生成的脚本时知道这点有帮助。
npm run-script build
npm run-script test
npx --no-install <cmd>yarn— 不支持 —pnpmpnpm exec <cmd>强制 npx 只用本地已装的可执行文件,绝不下载。binary 不在 node_modules 里就立刻报错。
⚠ 常见坑: 反过来 `npx --yes <cmd>` 会跳过 y/N 直接确认下载,CI 里方便,但包名打错时就是供应链隐患。
npx --no-install eslint .
npx --yes prettier --check .
pnpm exec tsc --noEmit
npm explore <pkg> -- <cmd>yarn— 不支持 —pnpm— 不支持 —进入某个已装依赖的目录开一个子 shell 并在里面跑命令。检查或重新构建单个包时有用。
npm explore esbuild -- npm run build
npm explore sharp -- node -p "process.platform"
npm uninstall <pkg>yarnyarn remove <pkg>pnpmpnpm remove <pkg>从 node_modules、package.json 对应分类、锁文件里都删掉这个包。
⚠ 常见坑: 别名: `npm un`、`npm rm`、`npm r`。yarn 用 `remove`(或 `rm`);pnpm 两个都行。`npm remove` 也能用,是别名。
npm uninstall react
yarn remove eslint
pnpm remove typescript
npm uninstall <pkg> -gyarnyarn global remove <pkg>pnpmpnpm remove -g <pkg>删全局装的 CLI。
npm uninstall -g create-react-app
pnpm remove -g vercel
npm pruneyarn— 不支持 —pnpm— 不支持 —删 "extraneous" 包,在 node_modules 里但不在 package.json 里的。手动删过依赖后清理用。
⚠ 常见坑: pnpm 的 node_modules 结构特殊(都是符号链接,指向内容寻址 store),`pnpm prune` 等价,但看到的磁盘节省数字不一样。
npm prune
npm prune --production
pnpm prune
rm -rf node_modules <lock>yarn— 不支持 —pnpm— 不支持 —npm 界的"关机重启"大招。删 node_modules 和锁文件,然后重装。最后的手段,不是第一选择。
⚠ 常见坑: 删锁文件会丢失可复现性,每个传递依赖都可能在范围内漂移。先试 `npm install`,再试 `npm ci`,最后才上核弹。
rm -rf node_modules package-lock.json && npm install
rm -rf node_modules pnpm-lock.yaml && pnpm install
npm updateyarnyarn upgradepnpmpnpm update把每个依赖升到 package.json 里 semver 范围允许的最新版本。范围本身不变。
⚠ 常见坑: 不会跨大版本。要跳出 "^1.x",得手动改 package.json 范围,或者用 `npm-check-updates` (ncu) / `yarn upgrade-interactive --latest`。
npm update
yarn upgrade
pnpm update
npm update <pkg>yarnyarn upgrade <pkg>pnpmpnpm update <pkg>只升单个依赖,在现有范围内升到最新。
npm update react
yarn upgrade lodash
pnpm update next
npm outdatedyarnyarn outdatedpnpmpnpm outdated列出所有 current < wanted < latest 的依赖,升级前先看会变什么。
⚠ 常见坑: "Wanted" = 当前 semver 范围内的最大版本。"Latest" = 标签最新。两者差距就是大版本升级,需要主动选。
npm outdated
yarn outdated
pnpm outdated
npm-check-updates (ncu)yarn— 不支持 —pnpm— 不支持 —第三方工具,把 package.json 改到最新版(跨大版本)。改完跑 install 才生效。
⚠ 常见坑: ncu 只改 package.json,不装。改完要跑 `npm install`(或 yarn/pnpm)才生效。另外: 提交前看 diff,大版本经常炸。
npx npm-check-updates
npx ncu -u
npx ncu -i # interactive
npm lsyarnyarn listpnpmpnpm list打印已装的依赖树。看 node_modules 里实际装了什么、版本号。
⚠ 常见坑: 大项目树会很大,找单个用 `npm ls <pkg>`,只看顶层用 `npm ls --depth=0`。pnpm 默认输出更扁更易读。
npm ls
npm ls react
npm ls --depth=0
pnpm list -r
npm explain <pkg>yarnyarn why <pkg>pnpmpnpm why <pkg>说明某个包为什么会出现在 node_modules,哪条依赖链拉进来的。排查幻影依赖必备。
⚠ 常见坑: npm 7+ 才有 `npm explain`,老版本只能 `npm ls <pkg>` 看,信息更少。yarn/pnpm 的 `why` 输出更可读。
npm explain lodash
yarn why lodash
pnpm why lodash
npm update --saveyarn— 不支持 —pnpm— 不支持 —在范围内升级,同时改写 package.json 记下新的最低版本。`npm update`(npm 7+)默认就会保存;老版本要加 --save。
npm update --save
npm update react --save
yarn upgrade-interactiveyarnyarn upgrade-interactivepnpm— 不支持 —Yarn 的交互式升级面板: 列出每个过期依赖的 current/wanted/latest,用键盘勾选要升哪些。
⚠ 常见坑: classic 默认在范围内升,加 `--latest` 才跨大版本。npm 没有原生等价命令,用 `npx npm-check -u` 或 `npx taze` 拿同款体验。
yarn upgrade-interactive
yarn upgrade-interactive --latest
npx taze -I
npm install <pkg>@latestyarnyarn add <pkg>@latestpnpmpnpm add <pkg>@latest把单个依赖跳到最新版并改写 package.json 范围的可靠做法(和 `npm update` 不同,这个会跨大版本)。
⚠ 常见坑: 大多数人说"升级 react"想要的其实是这个,`npm update react` 在 `^17` 范围里只会留在老大版本。要跳出去用 `@latest`。
npm install react@latest
pnpm add next@latest
yarn add typescript@latest -D
npm ls --depth=0yarnyarn list --depth=0pnpmpnpm list --depth=0只列顶层(直接声明)依赖和它们的安装版本。日常看"我到底加了什么"的清爽视图。
npm ls --depth=0
npm ls -g --depth=0
pnpm list --depth=0
npm ls --allyarn— 不支持 —pnpmpnpm list --depth=Infinity打印完整嵌套依赖树,每一层都展开。很重,但要追一个埋很深的传递依赖版本就靠它。
npm ls --all
npm ls --all 2>/dev/null | grep lodash
pnpm list --depth=Infinity
npm packyarnyarn packpnpmpnpm pack生成 .tgz 包(就是 `publish` 会上传的内容),但不真传。验证发布内容的标准做法。
⚠ 常见坑: 发布前先看 tarball 内容! `tar -tzf my-pkg-1.0.0.tgz` 列出所有文件。能抓到漏写 `files`/`.npmignore` 把 .env、dist、.git 带出去的事故。
npm pack
npm pack --dry-run
yarn pack -f my-pkg.tgz
npm publishyarnyarn publishpnpmpnpm publish把包上传到 registry。从 package.json 读 name + version。无 scope 默认公开,带 scope 默认私有。
⚠ 常见坑: 带 scope 的包首次发要加 `--access public`,否则 registry 报 402。同一版本发过一次就不能再发,要先 bump。
npm publish
npm publish --access public
npm publish --tag beta
npm version <major|minor|patch>yarnyarn version --<major|minor|patch>pnpmpnpm version <major|minor|patch>一步搞定 package.json 版本号 + git tag(如 v1.2.3)。发布前的标准动作。
⚠ 常见坑: 默认要求 git 工作区干净,先 commit 或 stash,或用 `--allow-same-version` / `--no-git-tag-version` 绕过。
npm version patch
npm version minor -m "Release v%s"
pnpm version major
npm dist-tag add <pkg>@<version> <tag>yarnyarn tag add <pkg>@<version> <tag>pnpmpnpm dist-tag add <pkg>@<version> <tag>给已发版本打标签(latest、next、beta、lts)。用户用 `<pkg>@<tag>` 按标签装。
⚠ 常见坑: `latest` 是默认安装标签,谨慎指向。发 beta 不动 `latest`,发布时一定要加 `--tag beta`。
npm dist-tag add my-pkg@1.2.3 latest
npm dist-tag ls my-pkg
npm dist-tag rm my-pkg beta
npm unpublish <pkg>@<version>yarn— 不支持 —pnpm— 不支持 —从 registry 撤回已发版本。限制极严,只能在发布 72 小时内撤,且不能有别的包依赖它。
⚠ 常见坑: 超过 72 小时改用 `npm deprecate <pkg>@<version> "<msg>"`,还能装,但会有警告。强撤会炸下游,参见 2016 年 left-pad 事件。
npm unpublish my-pkg@1.0.0
npm deprecate my-pkg@1.0.0 "Use v2.0 instead"
npm whoamiyarnyarn npm whoamipnpmpnpm whoami显示当前登录的 npm 用户。publish 出问题第一件事就查这个。
npm whoami
yarn npm whoami
pnpm whoami
npm loginyarnyarn npm loginpnpmpnpm login登录 registry。发布前必须做。新版 npm 走 web 流;老版走用户名/密码/邮箱。
⚠ 常见坑: 私有 registry 务必加 `--registry <url>` 或在项目级 `.npmrc` 里配,否则凭据被发到公网 registry。
npm login
npm login --registry=https://registry.example.com
npm logout
npm publish --dry-runyarnnpm publish --dry-runpnpmpnpm publish --dry-run模拟发布: 列出 tarball 内容、算出版本号,在真正上传前停下。干净发布的保险绳。
⚠ 常见坑: 配合 `npm publish --provenance`(在 GitHub Actions 上)能挂上签名构建证明,在包页面可见,提升可信度。
npm publish --dry-run
npm publish --provenance --access public
pnpm publish --dry-run --no-git-checks
npm publish --otp=<code>yarn— 不支持 —pnpm— 不支持 —发布带 2FA 时,直接行内传 TOTP 一次性码(不再交互式问)。开了强制 2FA 的 CI 必须这么干。
⚠ 常见坑: 比 --otp 更好的做法: 在 npm 账户设置里建一个 publish 权限的 granular access token,存成 NODE_AUTH_TOKEN。完全无人值守。
npm publish --otp=123456
# CI: NODE_AUTH_TOKEN=$NPM_TOKEN npm publish
npm version prerelease --preid=<tag>yarn— 不支持 —pnpm— 不支持 —升到下一个预发布版(1.2.0 → 1.2.1-beta.0)并打 tag。重复跑就 beta.0 → beta.1 这样走,直到正式发布。
⚠ 常见坑: 配 `npm publish --tag beta` 用,预发布才不会变成默认 `latest`。两个 flag 各管各的: `version` 改号,`publish --tag` 管安装指针。
npm version prerelease --preid=beta
npm version prerelease --preid=rc
npm publish --tag beta
npm version <x.y.z>yarn— 不支持 —pnpm— 不支持 —直接写死具体版本号,而不是按 semver 等级递增。要对齐外部版本方案或发布计划时有用。
⚠ 常见坑: 跳号(1.0.0 → 2.5.0)会让用户和 changelog 工具迷惑。只在确有意图时做,比如让 fork 对齐上游编号。
npm version 2.0.0-rc.1
npm version 1.4.2 --no-git-tag-version
npm deprecate <pkg>@<range> "<msg>"yarn— 不支持 —pnpm— 不支持 —把一个或多个已发版本标记为弃用。仍可安装,但每次安装都打印你的警告。比强撤更体面的做法。
⚠ 常见坑: 传空字符串可取消弃用: `npm deprecate my-pkg@1.0.0 ""`。范围能一次覆盖多个版本,如 `my-pkg@"<2.0.0"`。
npm deprecate my-pkg@"<2.0.0" "v1 is EOL, upgrade to v2"
npm deprecate my-pkg@1.0.0 ""
npm access set status=public <pkg>yarn— 不支持 —pnpm— 不支持 —事后把带 scope 的包在 public / private 间切换(`npm access public` 的新写法)。需要 owner 权限。
⚠ 常见坑: 从 private 切 public 实质不可逆,代码一旦公开就当它已被抓走。`npm access list packages` 看你拥有哪些包。
npm access set status=public @my/utils
npm access list packages
npm access get status @my/utils
npm owner add <user> <pkg>yarn— 不支持 —pnpm— 不支持 —给包加一个能发新版本的共同维护者。配 `npm owner rm` 和 `npm owner ls` 用。
⚠ 常见坑: 组织场景优先用团队授权而不是逐人加 owner,`npm access grant read-write @org:team <pkg>` 比一个个加人更好扩展。
npm owner add alice my-pkg
npm owner ls my-pkg
npm owner rm bob my-pkg
npm publish --tag <tag>yarnyarn publish --tag <tag>pnpmpnpm publish --tag <tag>以非默认 dist-tag 发布,新版本不会变成 `latest`。发 beta 又不打扰稳定用户的正确做法。
⚠ 常见坑: 发预发布忘加 `--tag` 是把坏 beta 推给所有 `npm install <pkg>` 用户的头号事故。预发布一律打 tag。
npm publish --tag next
npm publish --tag canary --access public
pnpm publish --tag beta --no-git-checks
workspaces in package.jsonyarnworkspaces in package.jsonpnpmpnpm-workspace.yaml启用 monorepo 模式。npm/yarn 在根 package.json 写 "workspaces" 数组;pnpm 用独立的 pnpm-workspace.yaml。
⚠ 常见坑: pnpm 分开是为了让这个文件不绑死任何工具。Yarn berry 还多 nohoist / packageExtensions 这些 npm/pnpm 没有的字段。
{ "workspaces": ["packages/*"] }{ "workspaces": ["apps/*", "packages/*"] }packages: - "packages/*"
npm install -w <pkg>yarnyarn workspace <pkg> add <dep>pnpmpnpm add <dep> --filter <pkg>把依赖加到 monorepo 里指定的子包,不是根。
⚠ 常见坑: 常见错误: 根目录裸跑 `npm install <dep>` 会加到根 package.json,不是子包。一定要带 `-w <name>`(npm)或 `--filter <name>`(pnpm)。
npm install lodash -w @my/web
yarn workspace @my/web add lodash
pnpm add lodash --filter @my/web
npm run <script> -w <pkg>yarnyarn workspace <pkg> <script>pnpmpnpm --filter <pkg> <script>monorepo 里任何位置都能跑指定子包的脚本。
npm run build -w @my/web
yarn workspace @my/api start
pnpm --filter @my/web build
npm run <script> --workspacesyarnyarn workspaces foreach run <script>pnpmpnpm -r <script>在所有定义了该脚本的子包里都跑一次。`pnpm -r` 功能最强(并行、按拓扑顺序)。
⚠ 常见坑: npm 顺序跑。pnpm -r 默认并行,脚本有竞态加 `--workspace-concurrency=1`。
npm run build --workspaces
pnpm -r build
pnpm -r --parallel dev
npm run <script> --workspaces --if-presentyarnyarn workspaces foreach --include <pat> run <script>pnpmpnpm -r --if-present <script>跨所有子包跑脚本,但跳过没定义该脚本的包(而不是报错)。
npm run test --workspaces --if-present
pnpm -r --if-present test
workspace:* protocolyarnworkspace:* protocolpnpmworkspace:* protocol在 package.json 里用 `"@my/utils": "workspace:*"` 引用本地另一个 workspace 包。安装时解析为本地版本。
⚠ 常见坑: 发布时会被自动改写成真实 semver 范围。yarn berry / pnpm 处理得很好;npm 7+ 也支持这个协议,但重写不如另两个成熟。
"@my/utils": "workspace:*"
"@my/utils": "workspace:^"
"@my/utils": "workspace:~1.2.3"
npm install -w <pkg> -w <pkg2>yarnyarn workspaces foreach --include <pat>pnpmpnpm --filter <a> --filter <b> <cmd>一条命令操作多个 workspace。pnpm 的 filter 能组合(--filter A --filter B),还支持 glob 和依赖选择器如 `...^@my/api`。
⚠ 常见坑: `pnpm --filter "...@my/api"` 意思是"@my/api 及其全部依赖"(构建顺序考虑)。`pnpm --filter "@my/api..."` 反过来,选所有依赖它的。
pnpm --filter @my/web --filter @my/api build
pnpm --filter "./packages/**" test
pnpm --filter "...@my/api" build
npm install --workspacesyarnyarn installpnpmpnpm install一次性装好所有子包加根的全部依赖。刚 clone 下来的 monorepo 用这一条命令就跑起来。
⚠ 常见坑: npm 有时要带 `--workspaces`;yarn/pnpm 默认就全装。pnpm 还会把跨 workspace 的依赖软链好,本地包不用先构建就能解析。
npm install --workspaces --include-workspace-root
pnpm install
yarn install
npm exec -w <pkg> -- <cmd>yarnyarn workspace <pkg> exec <cmd>pnpmpnpm --filter <pkg> exec <cmd>在某个 workspace 的上下文里(它的 node_modules/.bin)跑任意可执行文件。和跑命名脚本不同。
npm exec -w @my/web -- vitest run
pnpm --filter @my/api exec prisma generate
yarn workspace @my/web exec tsc --noEmit
pnpm --filter <pkg>... <cmd>yarn— 不支持 —pnpmpnpm --filter <pkg>... <cmd>pnpm 依赖选择器: `<pkg>...` 表示该包及所有依赖它的包;`...<pkg>` 表示该包及它的所有依赖。
⚠ 常见坑: 加 `[<ref>]` 按 git 变更圈定: `pnpm --filter "...[origin/main]" build` 只构建自 main 以来动过的包。monorepo CI 提速的杀手锏。
pnpm --filter "@my/ui..." build
pnpm --filter "...@my/ui" test
pnpm --filter "...[origin/main]" build
pnpm -r exec <cmd>yarn— 不支持 —pnpmpnpm -r exec <cmd>在每个子包里按拓扑(依赖)顺序跑一条原始 shell 命令。比 `-r <script>` 灵活,因为不绑 package.json 脚本。
pnpm -r exec rm -rf dist
pnpm -r exec pwd
pnpm -r --parallel exec tsc --noEmit
catalog: protocol (pnpm)yarn— 不支持 —pnpmcatalog: protocolpnpm catalog: 在 pnpm-workspace.yaml 里声明一次共享版本,各包用 `"react": "catalog:"` 引用。整个 monorepo 升版本只改一处。
⚠ 常见坑: 解决"每个包钉的 react 版本都差一点"的漂移问题。需要 pnpm 9.5+。命名 catalog(`catalog:react18`)可同时维护多条版本线。
# pnpm-workspace.yaml catalog: react: ^18.3.0
"react": "catalog:"
"react": "catalog:react18"
npm linkyarnyarn linkpnpmpnpm link两步走: 在被依赖的包里跑 `link` 建一个全局 symlink;再到使用方项目跑 `link <pkg>` 指过去。用真实项目联调库时必备。
⚠ 常见坑: 会引入奇怪的 peer 警告,因为链过来的包带着自己的 node_modules。现代替代方案: pnpm `workspace:*` 或 yarn `portal:` 协议,不用全局状态。
# in lib/ npm link # in app/ npm link my-lib
pnpm link --global
pnpm link /abs/path/to/lib
npm unlinkyarnyarn unlinkpnpmpnpm unlink撤销 `link`。unlink 之后务必重跑 `install`,把 registry 上的真版本装回来。
⚠ 常见坑: unlink 后忘了 install,node_modules 里留下空洞,运行时才崩,install 时没事。
npm unlink my-lib
npm install
pnpm unlink --global my-lib
npm ls -g --linkyarn— 不支持 —pnpm— 不支持 —列出当前全局链接的所有包。symlink 关系搞乱时用来理清。
npm ls -g --link
pnpm list -g
portal: protocol (yarn berry)yarnportal: protocolpnpm— 不支持 —Yarn berry 对 `npm link` 的回答: `"my-lib": "portal:../my-lib"` 软链本地目录并保留它自己的依赖解析,避开 link 那类重复 react 的坑。
⚠ 常见坑: `link:`(也有)不会拉目标自己的依赖;`portal:` 会。联合开发真包用 portal,纯文件目录用 link。
"my-lib": "portal:../my-lib"
"my-lib": "link:../shared"
pnpm link --globalyarn— 不支持 —pnpmpnpm link --globalpnpm 的两步全局 link: 在库里跑 `pnpm link --global`,再到使用方跑 `pnpm link --global <pkg>`。或者直接用路径 link 跳过全局。
⚠ 常见坑: 直接 `pnpm link <path>`(不带 --global)更干净,会往 package.json 写一条限定本项目的 `link:` 依赖,不留全局状态要清。
# in lib/ pnpm link --global
# in app/ pnpm link --global my-lib
pnpm link ../my-lib
npm cache clean --forceyarnyarn cache cleanpnpmpnpm store prune清本地包缓存。下载损坏导致 install 反复失败时用。
⚠ 常见坑: npm 会说 "npm@5 起缓存自愈",一般如此,但少数情况还得 `--force`。pnpm `store prune` 只删没有项目引用的包,更安全。
npm cache clean --force
yarn cache clean
pnpm store prune
npm cache verifyyarn— 不支持 —pnpm— 不支持 —校验缓存条目完整性,顺手清垃圾。比 clean 轻,不会清掉有效缓存。
npm cache verify
npm config get cacheyarnyarn config get cacheFolderpnpmpnpm store path打印缓存目录位置。排查磁盘占用爆炸时有用。
npm config get cache
yarn config get cacheFolder
pnpm store path
npm config set <key> <value>yarnyarn config set <key> <value>pnpmpnpm config set <key> <value>把配置写到 .npmrc / .yarnrc / .npmrc(注意 pnpm 也用 .npmrc)。registry、缓存目录、save-prefix 都从这里来。
⚠ 常见坑: 项目级 .npmrc 覆盖用户级。CI 经常因为项目 .npmrc 指向私有 registry 而 runner 连不到就挂。两级都要查。
npm config set registry https://registry.npmmirror.com
npm config set save-exact true
pnpm config set store-dir /data/.pnpm-store
npm config listyarnyarn configpnpmpnpm config list打印所有生效配置和来源(default / cli / env / user / project)。"我的 registry 怎么不对"必备调试命令。
npm config list
npm config list -l # include defaults
pnpm config list
npm config edityarn— 不支持 —pnpm— 不支持 —用 $EDITOR 打开用户 .npmrc 直接编辑。批量改的时候比 `config set` 快。
npm config edit
EDITOR=vim npm config edit
npm config get registryyarnyarn config get npmRegistryServerpnpmpnpm config get registry打印当前安装走哪个 registry。包"不存在"或装错构建时第一个要查的。
⚠ 常见坑: .npmrc 里残留的 `registry=https://某镜像` 通常就是"在家能装,公司 404"的元凶。把 `npm config get registry` 和官方默认比一比。
npm config get registry
npm config set registry https://registry.npmjs.org
pnpm config get registry
npm config set <key> <value> --location=globalyarn— 不支持 —pnpm— 不支持 —把配置写到全局(机器级) .npmrc 而不是用户级。用 --location=project 限定到当前仓库的 .npmrc。
⚠ 常见坑: npm 9 把 config 的 `--global` 改成了 `--location=global`。三个位置: project、user、global,按这个优先级层叠。
npm config set fund false --location=project
npm config set //registry.npmjs.org/:_authToken=$TOKEN --location=user
npm config delete <key>yarnyarn config unset <key>pnpmpnpm config delete <key>删一个配置键,值回退到默认。撤销一个搞坏安装的 `config set` 的干净做法。
npm config delete registry
npm config delete proxy
pnpm config delete store-dir
pnpm store statusyarn— 不支持 —pnpmpnpm store status检查内容寻址 store 里有没有文件被改过或丢失的包。校验 pnpm 全局共享 store 的完整性。
⚠ 常见坑: 项目莫名解析失败时,先 `pnpm store status` 再 `pnpm install --force` 从验证过的 store 重新软链。比清空 node_modules 省得多。
pnpm store status
pnpm store path
pnpm store prune
npm cache clean --force # only npm < 5 needs ityarn— 不支持 —pnpm— 不支持 —清缓存的提醒: npm 5 起缓存会自愈,损坏很少见。先用 `npm cache verify`;`clean --force` 是更重的最后一步。
npm cache verify
npm cache clean --force
npm audityarnyarn npm auditpnpmpnpm audit扫描已装包的已知漏洞,按严重程度打印报告。
⚠ 常见坑: CI 用 audit 卡门容易翻车,CVE 天天有,传递依赖你也修不完。用 `--audit-level=high` 过滤,接受的用 overrides。
npm audit
npm audit --audit-level=high
pnpm audit --prod
npm audit fixyarnyarn npm audit --recursivepnpmpnpm audit --fix在现有范围内升级依赖来自动修漏洞(--force 可跨大版本)。
⚠ 常见坑: `audit fix --force` 会跨大版本,CI 测试不硬就翻车。锁文件改动单独提交,方便回滚。
npm audit fix
npm audit fix --force
pnpm audit --fix
npm fundyarnyarn npm info <pkg>pnpmpnpm fund列出请求赞助的依赖(带捐赠链接)。信息性的,不是安全问题。
⚠ 常见坑: CI 里加 `--no-fund` 压掉每次 install 输出的提示。.npmrc 里写 `fund=false` 也行。
npm fund
npm install --no-fund
pnpm fund
npm view <pkg>yarnyarn npm info <pkg>pnpmpnpm view <pkg>打印包的元信息: 最新版本、所有版本、依赖、license、仓库地址,不用装。
npm view react
npm view react versions
pnpm view next dist-tags
npm search <keyword>yarnyarn npm search <keyword>pnpmpnpm search <keyword>按关键字搜 registry。说实话: npmjs.com 网站一般更好用。
npm search react state-management
pnpm search vite plugin
npm view <pkg> versions --jsonyarnyarn npm info <pkg> versionspnpmpnpm view <pkg> versions以 JSON 列出某包所有已发版本。钉版本前确认它存在、或找老大版本下最新补丁时有用。
npm view react versions --json
npm view next@"^13" version
pnpm view vite versions
npm view <pkg> dist-tagsyarn— 不支持 —pnpmpnpm view <pkg> dist-tags显示某包的 dist-tag → 版本映射: `latest`、`next`、`beta` 当前各指向哪个版本。一眼看出哪条预发布线在活跃。
npm view next dist-tags
npm view typescript dist-tags --json
pnpm view react dist-tags
npm audit --jsonyarn— 不支持 —pnpmpnpm audit --json以机读 JSON 输出审计报告,供 CI 卡门和看板用。管道 jq 只数 high/critical。
⚠ 常见坑: 用数量卡门,别用退出码: `npm audit --json | jq '.metadata.vulnerabilities.critical'`。原始退出码只要有发现就非零,太吵,卡门没意义。
npm audit --json
npm audit --json | jq '.metadata.vulnerabilities'
pnpm audit --json
npm audit signaturesyarn— 不支持 —pnpm— 不支持 —校验已装包的 registry 签名和 provenance 证明是否有效。能发现从 registry 到你机器之间的篡改。
⚠ 常见坑: CI 里 `npm ci` 之后跑,能抓到被污染的镜像或中间人。只对发布签名的 registry 有效(npmjs.org 有)。
npm audit signatures
# CI: npm ci && npm audit signatures
npm doctoryarn— 不支持 —pnpm— 不支持 —跑一组环境健康检查: registry 连通性、Node/npm 版本、缓存完整性、git 是否存在、关键目录权限。
⚠ 常见坑: 新机器装包出怪问题时最快的第一招,registry 错、缓存旧、权限问题一次全暴露。
npm doctor
npm doctor --no-color
npm pingyarn— 不支持 —pnpm— 不支持 —检查配置的 registry 是否可达并量往返延迟。怪安装之前先做的一行网络体检。
npm ping
npm ping --registry=https://registry.npmmirror.com
package-lock.json merge conflictyarnyarn.lock merge conflictpnpmpnpm-lock.yaml merge conflict两个分支各自加了依赖 → 锁文件冲突。千万别手改。删掉锁文件、重跑 install、提交重新生成的版本。
⚠ 常见坑: 现代做法: `git checkout --theirs`(或 --ours)选一边的锁文件,然后跑 `npm install`(或 yarn/pnpm),让包管理器重新协调。提交前一定要再跑一次 install。
rm package-lock.json && npm install
git checkout --theirs pnpm-lock.yaml && pnpm install
peer dependency conflictyarn— 不支持 —pnpm— 不支持 —两个依赖各自要不同版本的同一个 peer(常见是 react)。npm 7+ 直接报错;yarn 只警告;pnpm 严格报错。
⚠ 常见坑: 三种解法,按优先级: (1) 升级落后的依赖,(2) 用 `overrides`(npm)/`resolutions`(yarn)/`pnpm.overrides` 强制指定单一版本,(3) 实在不行 `--legacy-peer-deps`。
npm pkg set overrides.react="18.2.0"
"resolutions": { "react": "18.2.0" }pnpm i --legacy-peer-deps
phantom dependencyyarn— 不支持 —pnpm— 不支持 —代码里 import 了一个 package.json 没列的包,能跑是因为 npm/yarn 把它从传递依赖里 hoist 上来了。哪天传递依赖换了就崩。
⚠ 常见坑: pnpm 默认就防住了,它非扁平的 node_modules 只暴露你显式声明的依赖。怀疑有幻影依赖直接跑 `pnpm install`,一次性炸出来。
# Add the missing dep: npm install <pkg>
pnpm install # exposes phantoms
# Detect with: npx depcheck
pnpm hoisting / shamefully-hoistyarn— 不支持 —pnpm— 不支持 —某些老工具(next、eslint 插件)假设 node_modules 是扁平的。pnpm 提供 .npmrc 里 `shamefully-hoist=true` 模拟 npm 布局,换兼容性。
⚠ 常见坑: 开 hoist 等于把幻影依赖问题再藏起来,把 pnpm 一半优势浪费了。优先用 `public-hoist-pattern[]` 只 hoist 特定包(eslint-*、prettier-*)。
# .npmrc shamefully-hoist=true
# Better: public-hoist-pattern[]=*eslint* public-hoist-pattern[]=*prettier*
yarn berry vs yarn classic (v1 vs v2+)yarn— 不支持 —pnpm— 不支持 —Yarn v1(classic)和 v2+(berry)是两个不同产品。Berry 默认 Plug-n-Play(没 node_modules),去掉了 `yarn global`,缓存 .yarn/cache 提交进仓库。
⚠ 常见坑: 迁移成本高,大多数项目要么留 classic,要么直接跳到 pnpm。查版本: `yarn --version`。切到 berry: `yarn set version stable`。
yarn --version
yarn set version stable # → berry
yarn set version classic # → v1
npm install vs npm ci (which to use)yarn— 不支持 —pnpm— 不支持 —本地开发用 `install`(能加减依赖)。CI/CD 和部署用 `npm ci`,可复现、更快、新装,且锁文件不一致直接报错。
⚠ 常见坑: CI 里 npm ci 比 install 快 2-3 倍,因为跳过依赖解析。Yarn/pnpm 等价: `yarn install --frozen-lockfile` / `pnpm install --frozen-lockfile`。
# Local: npm install lodash
# CI: npm ci
pnpm install --frozen-lockfile
EACCES on global installyarn— 不支持 —pnpm— 不支持 —全局装报权限错,因为 /usr/local/lib 是 root 的。千万别 `sudo npm install -g`,改 prefix 才对。
⚠ 常见坑: sudo 装会让全部全局包属于 root,后患无穷。用 Node 版本管理器(nvm、fnm、volta),全部装到 home 目录里。
npm config set prefix ~/.npm-global
export PATH=~/.npm-global/bin:$PATH
# Even better: curl -fsSL https://fnm.vercel.app/install | bash
ERR_PNPM_PEER_DEP_ISSUESyarn— 不支持 —pnpm— 不支持 —pnpm 把 peer 依赖不匹配报成 ERROR(npm 只 warning)。要么修版本,要么加到 `pnpm.overrides`,实在不行 `strict-peer-dependencies=false`。
⚠ 常见坑: 全局放宽会藏住真 bug。按包覆盖更安全: `"pnpm": { "peerDependencyRules": { "ignoreMissing": ["@types/*"] } }`。
# .npmrc strict-peer-dependencies=false
"pnpm": { "overrides": { "react": "18.2.0" } }.npmrc precedence (project > user > global)yarn— 不支持 —pnpm— 不支持 —npm 按 项目根 > $HOME > npm prefix > 内置 顺序读 .npmrc,先匹配的赢。项目级最大。
⚠ 常见坑: 父目录里残留的 .npmrc 会影响子项目(npm 会向上找)。跑 `npm config list` 能看到具体哪些文件参与了。
# Project .npmrc beats user .npmrc: echo "registry=https://npm.example.com" > .npmrc
npm config list # see all sources
lock file in or out of git?yarn— 不支持 —pnpm— 不支持 —应用类: 锁文件要提交(大家版本一致)。库类: 一般不提交(消费者各自决定)。"在我机器上能跑"的经典源头。
⚠ 常见坑: 如果是库 + 顺带发 CLI 的项目,要提交锁文件,CLI 用户能拿到你测过的版本。ESLint 插件和框架脚手架作者经常搞错。
# App: commit git add package-lock.json
# Pure library: ignore echo "package-lock.json" >> .gitignore
engines field is just a warningyarn— 不支持 —pnpm— 不支持 —package.json 里 `"engines": { "node": ">=18" }` 默认只是说明,npm/yarn 警告一下照装。要硬卡得在 .npmrc 写 `engine-strict=true`。
⚠ 常见坑: pnpm 默认强制 engines,Node 版本不对直接装不上。能抓到"本地能跑生产崩"的真 bug。
# .npmrc engine-strict=true
"engines": { "node": ">=20", "pnpm": ">=9" }overrides vs resolutions (forcing a transitive version)yarn— 不支持 —pnpm— 不支持 —要把深层传递依赖锁成单一版本: npm 用 `"overrides"`,yarn 用 `"resolutions"`,pnpm 用 `"pnpm.overrides"`。目标一样,package.json 里的键三家各不同。
⚠ 常见坑: override 是大锤,你在推翻依赖自己声明的需求。注明原因(通常是安全补丁),上游修好后记得回收。
"overrides": { "semver": "7.5.4" }"resolutions": { "**/semver": "7.5.4" }"pnpm": { "overrides": { "semver@<7.5.2": "7.5.4" } }sudo npm install -g (do not)yarn— 不支持 —pnpm— 不支持 —用 sudo 装全局会让每个全局可执行文件归 root,以后不带 sudo 的安装就 EACCES 报错。解法是上 Node 版本管理器,不是再加 sudo。
⚠ 常见坑: 已经陷进去了? `sudo chown -R $(whoami) $(npm config get prefix)` 拿回所有权,然后换 fnm/nvm/volta,以后不再发生。
# Wrong: sudo npm install -g pnpm
# Right: curl -fsSL https://fnm.vercel.app/install | bash
sudo chown -R $(whoami) $(npm config get prefix)
mixing package managers in one repoyarn— 不支持 —pnpm— 不支持 —在 yarn 项目里跑 npm(反之亦然)会生成第二个锁文件。两个锁文件就是两个真相源,开发者和 CI 之间悄悄漂移。
⚠ 常见坑: 用 `packageManager` 字段钉死一个工具并开 Corepack,敲错命令直接被拒。把外来锁文件 gitignore 做兜底。
"packageManager": "pnpm@9.1.0"
# .gitignore yarn.lock package-lock.json
npx only-allow pnpm
only-allow: enforce one package manageryarn— 不支持 —pnpm— 不支持 —加 `"preinstall": "npx only-allow pnpm"`,在 pnpm 仓库里有人跑 `npm install` 或 `yarn` 会被拦下并看到清晰提示,杂锁文件还没生成就被挡住。
⚠ 常见坑: preinstall 在依赖还没装时就跑,所以 only-allow 靠 npx 独立运行。配 Corepack: only-allow 挡错工具,Corepack 钉对版本。
"preinstall": "npx only-allow pnpm"
"preinstall": "npx only-allow yarn"
postinstall scripts as a supply-chain riskyarn— 不支持 —pnpm— 不支持 —恶意依赖能在你一安装的瞬间通过它的 `postinstall` 钩子执行任意代码。这是 npm 供应链攻击最常见的入口。
⚠ 常见坑: .npmrc 里默认 `ignore-scripts=true`,再给信任的包开白名单。pnpm 9+ 在跑新增依赖的构建脚本前会先问你一句。
# .npmrc ignore-scripts=true
npm install --ignore-scripts
# pnpm 9+ approve list: onlyBuiltDependencies
caret ^ vs tilde ~ semver rangesyarn— 不支持 —pnpm— 不支持 —`^1.2.3` 允许任意 1.x.y(小版本加补丁);`~1.2.3` 只允许 1.2.y(补丁)。0.x 时两者表现不同: `^0.2.3` 被锁在 0.2.y,因为 0.x 的小版本就当大版本看待。
⚠ 常见坑: 0.x 规则常把人坑到: 按 semver,0.x 每次小版本升级都可能 break。所以 `^0.3.0` 不会自动升到 0.4.0,行为等同 `~0.3.0`。
"react": "^18.2.0" // 18.x.x
"react": "~18.2.0" // 18.2.x
"some-lib": "^0.3.0" // 0.3.x only
node_modules/.bin and PATH in scriptsyarn— 不支持 —pnpm— 不支持 —在 npm/yarn/pnpm 脚本内部,`node_modules/.bin` 会被自动加到 PATH 前面。所以 `"build": "vite build"` 不用 `npx` 或 `./node_modules/.bin/` 也能跑。
⚠ 常见坑: 这个魔法只在脚本内部生效。普通终端里还得 `npx vite` 或 `pnpm exec vite`。这个差异就是"package.json 里能跑,我 shell 里报错"的原因。
"build": "vite build" // no npx needed
# in shell: npx vite build
pnpm exec vite build
files field vs .npmignore (what gets published)yarn— 不支持 —pnpm— 不支持 —发布 tarball 里有什么,由 package.json 的 `"files"` 白名单或 `.npmignore` 黑名单控制。有 `"files"` 就以它为准;否则用 `.npmignore`(没有则退回 `.gitignore`)。
⚠ 常见坑: 发布前一律 `npm pack --dry-run` 验一遍。反复出事的是漏带的 `.env`、本想排除的 `src/`、把包撑大的测试夹具。`"files"` 白名单比黑名单安全。
"files": ["dist", "README.md"]
npm pack --dry-run
tar -tzf my-pkg-1.0.0.tgz
NODE_ENV=production hides devDependenciesyarn— 不支持 —pnpm— 不支持 —NODE_ENV 为 `production` 时,裸跑 `npm install` 会跳过 devDependencies。Docker 构建里需要 typescript、vite 这类装在 devDependencies 的构建工具时就被坑。
⚠ 常见坑: 要么把构建工具挪到 dependencies,要么在构建阶段 `npm install --include=dev`,只在多阶段 Dockerfile 的最终运行阶段 `npm ci --omit=dev`。
npm install --include=dev
# Multi-stage Docker: RUN npm ci RUN npm run build # then runtime: RUN npm ci --omit=dev
可搜索的 npm 速查表,每行都同时列出 yarn 和 pnpm 的等价写法。 80+ 条真实命令,十一类:初始化(init、init -y、init 走 create-*、npm pkg get),安装依赖(-D、-g、@version、ci、 --save-exact、--omit=dev、--ignore-scripts、git/file 装包、 --legacy-peer-deps、--force),脚本(run、start、test、用 -- 传参、npm pkg set scripts、npx vs yarn dlx vs pnpm dlx、npm exec、pre/post 生命周期钩子),卸载(uninstall、prune、核弹级 rm -rf node_modules),更新(update、outdated、 npm-check-updates、ls、explain / yarn why / pnpm why),发布 (pack、publish、--dry-run、--otp、--provenance、version major|minor|patch、dist-tag、unpublish vs deprecate、whoami、 login),工作区(workspaces 数组 vs pnpm-workspace.yaml、-w / --filter、--workspaces、workspace:* 协议、pnpm filter 的 `...` 选择器组合),本地链接(npm link、unlink、ls -g --link), 缓存与配置(cache clean、verify、config get/set/list/edit、 store path),审计与查包(audit、audit fix、fund、view、 search),还有常见坑(锁文件冲突、peer 依赖冲突、幻影依赖、 pnpm shamefully-hoist、yarn berry vs classic、npm install vs npm ci、全局装包 EACCES、ERR_PNPM_PEER_DEP_ISSUES、.npmrc 优 先级、锁文件要不要提交、engine-strict)。每条都把 npm / yarn / pnpm 三种写法并排展示,配中英双语解释和"多数速查不写但你一 定会踩"的真坑(忘写 `--` 导致 flag 没传给脚本?`pnpm init` 没有 -y?scope 包首次 publish 得加 `--access public`?), 再加 1-4 条能直接拷的例子。搜索框跨三栏 + 说明 + 坑 + 例子 同时过滤,分类胶囊缩范围,每一格都能一键复制。完全浏览器内 运行,不上传不追踪。
把内容粘贴或拖入工具面板。
点击按钮,在浏览器内本地处理,文件不上传。
一键复制结果或下载到本地。
适合穿插在写代码、查问题、做 Review、上线前的小任务里。
这些入口会把当前任务接到更完整的工具链里。
你本地 `npm install lodash` 装了包,提交了 package.json,却忘了把 package-lock.json 一起 add。CI 跑 `npm ci` 拒绝解析直接挂。在这份速查里搜 `ci`,确认它要求锁文件存在 且和 package.json 一致,补提交锁文件就好。右边对照栏会提醒你 yarn 的等价写法是 `--frozen-lockfile`,一栏看清三家。
他跑了 `yarn install react-query`,以为能加依赖,可 yarn classic 在 `install` 上会默默 忽略包名,只刷新 node_modules,package.json 一个字没动。在这里查 `add`,看到那一行 标注的坑,改成 `yarn add react-query`。比事后排查「为什么 import 不到」省下五分钟。
你对 `@acme/utils` 跑 `npm publish`,npm 拒绝了,因为 scope 包默认私有。publish 那条坑 写得清楚:首次发布要加 `npm publish --access public`。直接拷这条命令,开了 2FA 再补 `--otp 123456`,包就上线了。公开 scope 包根本不用买付费计划。
你有 8 个包,只想给改过的那个加上依赖它的包一起跑测试。npm 没有干净的选择器,pnpm 有。 搜 `filter` 找到 `pnpm --filter "...pkg-a" test`(`...` 把下游依赖方也带上),再对照 npm 的 `-w` 和 `--workspaces` 两栏,清楚知道切过去会失去什么。
跑 `npm run build --prod` 却发现 flag 根本没传进脚本。脚本名后面的参数会被 npm 自己吃掉,要加分隔符:`npm run build -- --prod`。
敲 `pnpm init -y` 报错。pnpm init 从不交互提问,所以没有 `-y` 这个 flag,直接 `pnpm init` 就会立刻写出 package.json。
跑完 `npm install` 后只提交了 package.json,把锁文件漏在外面。同事和 CI 会解析出不同版本,锁文件一定要和 package.json 一起 add。
全部在你的浏览器里跑。命令清单是打包进页面的内存数组,搜索框在本地过滤,零网络请求。你输入 的搜索词不会离开这个标签页,也不会写进 URL,更没有任何统计去记录你查了什么。边输入边看 DevTools 的 Network 面板,你会看到它一直是静默的。
做你这行的人, 还会一起用这些。