Node.js项目发展到一定规模之后,包管理器本身也会成为一个需要考虑的问题。
以前我比较习惯直接用npm。
但随着项目越来越多,我开始更多地用pnpm。
最直接的原因其实很简单:
快,而且省空间。
npm最大的问题之一:重复依赖
假设电脑上有:
project-a
project-b
project-c三个项目都依赖:
lodash传统的安装方式会在每个项目的node\_modules里分别存一份。
项目多了以后,磁盘空间很快就被大量重复依赖占掉了。
pnpm的思路不一样。
它会把包存在全局的内容寻址存储里,然后通过链接的方式让项目去用这些依赖。
简单理解:
全局Store
│
├── lodash
├── vue
├── typescript
└── vite
↓
项目node_modules这样多个项目可以共用相同的包内容。
pnpm的node\_modules为什么不一样
装完依赖之后你会发现,pnpm的:
node_modules/结构和npm有明显区别。
pnpm会用链接机制来组织依赖。
这样做不仅能减少重复文件,也能让依赖关系更严格。
这点其实挺重要的。
pnpm对依赖访问更严格
有些项目会出现这种情况:
项目只声明了:
{
"dependencies": {
"vue": "^3.0.0"
}
}但代码里却偷偷用了:
import something from 'some-package'而some-package并没有写在package.json里。
在某些情况下,这种代码可能因为依赖被间接安装而"碰巧能跑"。
换个环境可能就直接报错了。
pnpm更严格的依赖结构能帮你暴露这种问题。
从长期维护的角度看,我觉得这是好事。
pnpm Workspace
pnpm真正让我觉得方便的是Workspace。
比如:
my-project/
├── apps/
│ ├── web/
│ └── admin/
│
├── packages/
│ ├── ui/
│ ├── utils/
│ └── types/
│
└── pnpm-workspace.yaml这样可以管理一个Monorepo。
比如:
apps/web
↓
packages/ui
↓
packages/types不同项目之间可以共享代码。
对于组件库、后台管理系统、官网等多个项目组成的工程尤其方便。
常用命令
初始化:
pnpm init安装:
pnpm install添加依赖:
pnpm add vue开发依赖:
pnpm add -D typescript删除:
pnpm remove vue执行脚本:
pnpm dev这些命令和npm差别不大,迁移成本不高。
为什么我现在更喜欢pnpm
我觉得pnpm的优势主要集中在:
依赖安装速度
磁盘空间
依赖隔离
Workspace
Monorepo尤其是电脑上同时维护多个前端项目的时候,磁盘空间的节省还是很明显的。
当然,npm依然是很成熟的方案。
如果只是一个小项目,没必要为了用pnpm而强行迁移。
但如果项目多、依赖复杂,或者开始用Monorepo,我会优先考虑pnpm。
包管理器不是项目架构的核心
最后还是想强调一点。
别因为某个工具流行就觉得一定适合自己。
npm、pnpm、Yarn都能搞定绝大多数前端项目的依赖管理。
真正重要的是:
- 锁定依赖版本
- 保证安装结果一致
- 避免隐式依赖
- CI环境能稳定安装
- 团队统一工具
工具本身只是手段。
对于我目前的前端开发习惯来说,pnpm确实是一个很好用、也比较符合现代前端项目需求的选择。