npm → pnpm
你熟的 npm 指令与对应的 pnpm 写法并排,并说明 node_modules 不再摊平之后,实际上会有什么东西坏掉。
在你的浏览器中运行
| 要做的事 | npm | pnpm |
|---|---|---|
| 安装 lockfile 里的全部依赖 | ||
| CI 安装,lockfile 若会改动就失败 | ||
| 新增依赖包 | ||
| 新增开发依赖 | ||
| 锁定版本,不用范围 | ||
| 全局安装 | ||
| 移除依赖包 | ||
| 在既有版本范围内更新 | ||
| 列出落后最新版的包 | ||
| 执行 package.json 里的 script | ||
| 不安装就执行包的可执行文件 | ||
| 建立新包 | ||
| 查出某个包为什么被装进来 | ||
| 检查依赖包的安全通报 | ||
| 把依赖装到某一个 workspace |
简短版
| npm | pnpm |
|---|---|
npm install | pnpm install,或 pnpm i |
npm install <pkg> | pnpm add <pkg> |
npm install -D <pkg> | pnpm add -D <pkg> |
npm uninstall <pkg> | pnpm remove <pkg> |
npm run build | pnpm build |
npx <pkg> | pnpm dlx <pkg> |
npm install <pkg> -w <name> | pnpm --filter <name> add <pkg> |
pnpm 的指令刻意做得跟 npm 很接近,所以这一层翻译几乎是机械式的。完整的表格在上面,可以填入你 自己的套件名称。
真正改变的是什么
指令是简单的部分。安装出来的结构才是你换过去的理由,也是东西坏掉的理由。
node_modules 不是摊平的。 npm 与 Yarn 1 会把所有间接相依提升到最上层,于是代码可以
require('某个套件')——即使 package.json 里从来没宣告过它——而且真的会动。pnpm 只把你宣告过的
相依放在最上层,其余全部从一个 content-addressed 的 store 用 symlink 连进去。
这确实抓得出 bug,而且抓出来的多半在别人写的套件里。依赖提升的套件在 pnpm 下会直接
Cannot find module。解法通常是在 .npmrc 加 public-hoist-pattern,有时候是去上游开 issue。
硬盘用量会直接垮下来。 每个套件的每个版本在一台机器上只存一份,再 hard link 进各个专案。 十个专案用同一版 React,只占一份。
pnpm dlx 不是换名字的 npx。 npx 会优先执行本地 node_modules 里已有的执行档;
pnpm dlx 一律抓到暂存区再执行。要跑本地的执行档请用 pnpm exec。
迁移一个专案
- 删掉
package-lock.json与node_modules。 - 执行
pnpm install。 - 跑一次 build 和测试。提升假设是在这里爆的,不是在安装的时候。
- Commit
pnpm-lock.yaml,而且只 commit 这一个。
monorepo 还要加一个 pnpm-workspace.yaml。pnpm 不读 package.json 里的 workspaces
栏位——这是最多人卡住的一点,因为安装会成功,只是什么都没连起来。
相关
npm 转 Yarn,或含 Bun 的 四栏完整对照表。