pnpx、pnpm dlx、pnpm exec 的关系:到底怎么选?
在前端工程里,我们经常需要「执行一个 CLI」:用脚手架建项目、跑代码生成器、临时调用某个工具,或者在项目里执行已经装好的依赖命令。
pnpm 里和这件事相关的命令有三个:pnpm dlx、pnpx、pnpm exec。它们长得像,但职责并不一样,混用是最常见的踩坑点。
先说结论:
pnpx就是pnpm dlx的别名,两者完全等价,不用纠结。pnpm dlx/pnpx:从 registry 临时下载并运行一个包(不装为项目依赖),相当于 pnpm 版的npx。pnpm exec:在当前项目里执行已经安装好的依赖命令,不会下载任何东西。
一句话区分:要下载着跑用 dlx,跑本地已装好的用 exec。
一、三者分别是什么
1) pnpm dlx
pnpm 官方子命令。从 registry 拉取一个包,不将其安装为项目依赖,热加载后运行它暴露的默认命令。
特点:
- 跑完即走,不会污染当前项目的
package.json和node_modules。 - 拉取过的包仍会进入 pnpm 的全局 store 缓存,下次执行更快。
- 可显式指定版本:
pnpm dlx create-vue@next my-app。 - 支持
--package一次安装多个包再执行:pnpm --package=yo --package=generator-webapp dlx yo webapp。 - 支持
--allow-build(v10.2.0+)放行 postinstall 脚本。 - 支持
catalog:协议,复用 workspace 中定义的版本。
2) pnpx
官方文档原话:Aliases: pnpx is an alias for pnpm dlx。
也就是说 pnpx foo 和 pnpm dlx foo 行为完全一致,只是少打几个字。从 pnpm v7 起官方在命名上对齐了 npm exec / npx 的风格,文档与团队规范里更推荐写成 pnpm dlx,pnpx 留作快捷写法。
⚠️ 别把
pnpx当成npx的同义替换。两者目的类似(都是临时执行 CLI),但pnpx走的是 pnpm 的依赖解析与 store 缓存,安装速度、存储占用、排错思路都和 npm 那套不同。
3) pnpm exec
在当前项目作用域内执行 shell 命令:把项目的 node_modules/.bin 加入 PATH,从而可以直接调用项目依赖里的可执行文件。
特点:
- 只跑本地已安装的命令,不下载新包。如果依赖里没有对应二进制,会直接报错。
exec关键字在不与 pnpm 内置命令冲突时可省略:pnpm jest等价于pnpm exec jest。- 天然支持 workspace:
pnpm -r exec rm -rf node_modules可在每个子包里递归执行。 - 支持
--shell-mode, -c、--parallel、--filter等选项。
二、核心区别对比
三、一张图理清决策
四、典型使用场景
1) 脚手架初始化(新项目)
2) 临时执行一次性工具
3) 运行项目内已安装的工具
注意
prisma generate这类命令:如果 prisma 已经是项目依赖,用pnpm exec prisma generate更准确(不会重复去 registry 拉包);如果临时在没有装它的环境里跑,才用pnpm dlx prisma generate。
4) 团队脚本与 CI
五、常见问题与误区
1) pnpx 和 pnpm dlx 到底有啥区别?
没有区别。pnpx 是 pnpm dlx 的别名,行为完全一致。选哪个只关乎可读性和团队规范——文档和脚本里写 pnpm dlx,本地手敲图省事用 pnpx。
2) 为什么同一命令在不同机器上表现不一致?
常见原因:
- Node 与 pnpm 版本不同(如
--allow-build仅 v10.2.0+ 支持)。 - 未显式锁版本,CLI 默认取最新,导致行为漂移。
- 网络源(registry)配置不同,拉取结果或速度有差异。
建议:关键 CLI 显式指定版本,例如 create-vite@latest 或固定到具体版本号。
3) pnpm exec 找不到命令怎么办?
说明该命令对应的依赖没有在当前项目安装。exec 不会自动下载,要么先 pnpm add -D <pkg>,要么改用 pnpm dlx <pkg> 临时跑。
4) 可以照搬 npm 的 npx 经验吗?
部分可以,但不建议无脑套用。pnpx / pnpm dlx 对标 npx,但走的是 pnpm 的 store 与符号链接机制;而 pnpm exec 更接近 npm exec 的语义(运行本地依赖)。搞清「下载着跑」还是「跑本地的」就不会乱。
5) 这些命令会污染全局环境吗?
不会。它们都不会把工具长期装成全局包。dlx 跑完即走(包进 store 缓存但不挂到项目),exec 只复用项目已有依赖。
六、实用命令清单
七、如何选型(可直接照抄)
- 临时下载运行一个包:
pnpm dlx(文档 / CI)或pnpx(本地手敲)。 - 创建新项目脚手架:
pnpm create <flavor>,或pnpm dlx create-<flavor>。 - 运行项目里已安装的工具:
pnpm exec <cmd>(或省略exec)。 - workspace 批量在子包里执行:
pnpm -r exec <cmd>。 - 团队规范、CI、README:统一用
pnpm dlx和pnpm exec,语义最清晰。
记牢一句话就能应对绝大多数情况:要下载着跑用 dlx,跑本地已装好的用 exec,pnpx 只是 dlx 的短别名。
