hello,大家新年快乐呀,最近在学习Vue源码时候,需要使用Monorepo进行包管理,结果运用到了"npx tsx --init"这个命令,于是我就开始疑惑为什么有的命令用
npm i,有的用pnpm add,还有的要加npx前缀?于是便自己总结了如下的内容,分享给大家!
一、先立核心认知:三者不是同一类工具
很多人会把三者混为一谈,其实它们的定位天差地别!先看一张表快速 get 核心区别:
| 工具名 | 核心定位 | 本质 / 所属关系 | 核心职责 |
|---|---|---|---|
npm |
Node.js 官方默认包管理器 | 随 Node.js 一同安装,官方标配 | 管理项目依赖(安装 / 卸载 / 更新 / 发布) |
pnpm |
高性能第三方替代包管理器 | 第三方工具,需手动安装 | 同 npm 核心职责,优化性能与磁盘占用 |
npx |
Node 包执行工具 | 随 npm@5.2.0+ 自带,非包管理器 |
执行 Node 包的可执行文件,不管理依赖 |
划重点:npm 和 pnpm 是「包管理器」,负责 "存放和管理依赖";npx 是「执行工具」,负责 "运行依赖包",三者不是同一维度的工具!
二、逐个拆解:功能详解 + 代码示例
1. npm:官方默认,稳字当头
npm(Node Package Manager)是前端开发者的入门标配,它的核心作用就是帮我们管理项目的依赖包,是生态最成熟、兼容性最好的包管理器。
核心功能(附代码示例)

优点 & 缺点
- 优点:兼容性拉满,无需额外配置,几乎支持所有 Node 项目,新手友好。
- 缺点:安装速度慢,磁盘占用高(嵌套
node_modules,依赖重复拷贝),部分场景会出现版本不一致问题,还可能产生幽灵依赖。
2. pnpm:性能怪兽,省空间神器
pnpm(Performant npm)是针对 npm 痛点优化的第三方包管理器,核心功能和 npm 一致,但在「速度」和「磁盘占用」上实现了碾压级提升。而这一切的优势,都源于它的「全局缓存 + 硬链接 + 软链接」机制,同时它还能杜绝幽灵依赖。
核心优势(区别于 npm 的关键)
- 安装速度超快 :比
npm快 2-5 倍,大型项目中差距更明显。 - 极致省磁盘 :采用「全局缓存 + 硬链接 / 符号链接」机制,同一个依赖的同一个版本,全局只存储 1 份,多个项目共享。比如:10 个项目都依赖
react@18,npm会拷贝 10 份,pnpm只存 1 份,大幅节省磁盘空间。 - 杜绝幽灵依赖 :
pnpm的node_modules结构更严谨,只有在package.json中声明的依赖才能被项目使用,避免隐式依赖问题。
深度拆解:pnpm 核心机制(全局缓存 + 硬链接 + 软链接)
在讲解之前,先给大家用通俗的语言解释两个概念,避免晦涩难懂:
- 硬链接(Hard Link) :可以理解为「文件的副本快捷方式」,还可以直白理解成创建了一个word的副本,它和原文件共享同一份磁盘数据。比如你有一个文件
A.txt,给它创建一个硬链接B.txt,修改A.txt内容,B.txt也会同步变化;删除A.txt,B.txt依然可以正常使用(因为它指向的是磁盘数据,不是原文件本身)。 - 软链接(Symbolic Link,也叫符号链接) :可以理解为「Windows 的快捷方式 / Mac 的替身」,它本身不存储任何数据,只记录原文件的路径。比如给
A.txt创建软链接C.txt,打开C.txt其实是通过路径找到并打开A.txt;如果删除A.txt,C.txt就会失效。 - 全局缓存 :
pnpm会在你的电脑上创建一个全局的缓存目录(Windows:C:\Users<用户名>.pnpm-store;Mac/Linux:~/.pnpm-store),所有通过pnpm下载的依赖包,都会先解压并存储到这个全局缓存中,同一个版本的依赖只存储一次。
当你在项目中用 pnpm add <包名> 安装依赖时,pnpm 的工作流程是这样的:
- 先检查全局缓存中是否存在该版本的依赖,如果不存在,就从 npm 仓库下载并存储到全局缓存;
- 在全局缓存中,给该依赖的文件创建「硬链接」到
pnpm的虚拟存储目录; - 在项目的
node_modules中,创建「软链接」指向虚拟存储目录中的依赖文件; - 最终项目的
node_modules中,只有软链接,没有实际拷贝的依赖文件,实现了 "一份缓存,多项目共享"。
通俗总结:全局缓存是 "仓库",硬链接保证 "一份数据多处可用",软链接负责 "项目找到依赖",三者结合让 pnpm 既省空间又快。
深度拆解:幽灵依赖(为什么 npm 有,pnpm 没有?)
先明确:幽灵依赖(Phantom Dependency)就是项目中使用了没有在 package.json 中明确声明的依赖,但项目依然能正常运行的现象。
举个例子帮你理解:
- 你在项目中用
npm i react安装了react,而react本身依赖react-dom(这是react的依赖,不是你项目的直接依赖); - 由于
npm会将所有依赖(直接依赖 + 间接依赖)扁平化到node_modules根目录,所以你在项目中即使没在package.json中声明react-dom,也能直接导入并使用react-dom; - 这种情况就是幽灵依赖:你没明确安装
react-dom,却能使用它,看似方便,实则隐藏巨大风险 ------ 如果某天react升级后不再依赖react-dom,或者依赖的react-dom版本大幅变更,你的项目就会突然报错,难以排查。
而 pnpm 为什么能杜绝幽灵依赖?因为 pnpm 的 node_modules 不是扁平化的,项目的 node_modules 根目录下,只有你在 package.json 中明确声明的直接依赖,间接依赖会被放在虚拟存储目录中,项目无法直接访问未声明的间接依赖,自然就杜绝了幽灵依赖,让项目依赖更严谨、更可控。
核心功能(附代码示例,几乎兼容 npm 命令)

优点 & 缺点
- 优点:速度快、省磁盘、无幽灵依赖、完全兼容
npm生态,依赖管理更严谨。 - 缺点:需要手动安装(非 Node 自带),极少数老旧项目可能存在兼容性问题(几乎可以忽略)。
3. npx:包执行工具,告别全局安装
npx 最容易被误解为包管理器,但它根本不是用来管理依赖的 ,而是用来「执行 Node 包」的工具,解决了 npm 执行包的两大痛点。
解决的核心痛点
- 痛点 1:全局安装包容易导致版本冲突(比如 A 项目要
create-react-app@5,B 项目要create-react-app@4)。 - 痛点 2:本地安装的包,无法直接在命令行执行(路径不在系统环境变量中)。
核心功能(附代码示例,重点!)

核心特性
- 无需手动安装包,临时下载即执行。
- 优先使用本地包,避免版本冲突。
- 无需配置环境变量,自动识别可执行文件路径。
三、实战场景:该用谁?怎么用?
看完理论,我们结合实际开发场景,明确三者的使用选择:
| 场景需求 | 推荐工具 | 命令示例 |
|---|---|---|
| 新手入门、传统项目开发(追求兼容) | npm | npm i react、npm run dev |
| 大型项目、多项目开发(追求性能 / 省空间 / 严谨性) | pnpm | pnpm add react、pnpm dev |
| 临时执行脚手架(如 cra、vite) | npx | npx create-vite my-vite-app |
| 临时运行 TS 文件、格式化代码等 | npx | npx tsx src/index.ts、npx prettier --write . |
| 执行本地安装的包(避免全局版本冲突) | npx | npx tsc --init、npx webpack |
| 发布自己的 npm 包 | npm/pnpm | npm publish、pnpm publish |
四、总结:核心区别一句话记牢
- 身份差异 :
npm(官方包管理器)、pnpm(高性能包管理器)、npx(包执行工具,非包管理器)。 - 职责差异 :
npm/pnpm管「依赖的安装 / 卸载 / 管理」,npx管「依赖的执行」。 - 核心机制差异 :
pnpm靠「全局缓存 + 硬链接 + 软链接」实现高性能和省磁盘,还能杜绝幽灵依赖;npm无此机制,存在幽灵依赖风险。 - 性能差异 :
pnpm>npm(速度、磁盘占用全方位领先),npx无此对比维度。 - 使用差异 :兼容优先用
npm,性能 / 严谨性优先用pnpm,临时执行 / 避免版本冲突用npx。