
前端接触到的包管理工具有 npm、yarn 以及 pnpm,项目中一般常用 npm 来作为包管理工具,最近有接触到 pnpm,具有安装速度快、节约磁盘控件、安全性好的优点,它的出现是为了解决 npm 和 yarn 存在的问题,然后就研究了一下三者之间的差别
npm 从 v1 - v3 - v5 版本迭代都有重大变化
npm v1 版本中使用了简单的嵌套模式进行依赖管理。比如我们在项目中依赖了 A、C、D 模块,而这三个模块依赖了不同的 B 模块,此时生成的 node_modules 目录如下
node_modules
├── A@1.0.0
| └── node_modules
| └── B@1.0.0
├── C@1.0.0
| └── node_modules
| └── B@2.0.0
├── D@1.0.0
| └── node_modules
| └── B@1.0.0npm v3 完成重写依赖安装程序,npm v3 通过扁平化的方式将子依赖所在的目录中,以减少依赖嵌套导致的深层树和冗余,此时的 node_modules 目录如下
node_modules
├── A@1.0.0
├── B@1.0.0
├── C@1.0.0
└── node_modules
└── B@2.0.0
├── D@1.0.0npm 实现了额外的依赖查找算法,核心是递归向上查找 node_modules。在安装新包时,会不停的向上级 node_modules 中查找。如果找到相同版本的包就不会重新安装,在遇到版本冲突时才会在该模块下的 node_modules 目录下存放该模块的子依赖 v3 的变化,虽然避免了嵌套过深和重复安装问题,带来了新的问题:幽灵依赖(Phantom dependency),带来了结构不确定性
幽灵依赖主要是发生在某个包未在 package.json 中定义,但项目中依然可以引用到的情况
{
"name": "nuxt-demo",
"version": "1.0.0",
"description": "Serverless Nuxt.js Application Created By Serverless Framework",
"author": "yangbo",
"private": true,
"dependencies": {
"A": "^1.15.1",
"C": "^2.14.3"
}
}在 js 文件中可以直接引用 A 包,也可以引用 B 包,因为 B 是 A 的依赖项,安装的时候,npm 会将依赖 B 平铺安装在 node_modules,因此可以引用它,导致的问题:
v5 版本会在下载包时默认生成 package-lock.json 文件
package-lock.json 文件可以帮我们记录每一个包版本和其所依赖的其他包版本,这样在下一次安装的时候就可以通过这个文件来安装。package.json 和 package-lock.json 两者确保得到的 node_modules 目录结构,保证了安装依赖的确定性
yarn 的出现是为了解决 npm v3 中存在的一些问题;yarn 生成的 node_modules 目录结构和 npm v5 是相同的,默认生成一个 yarn.lock(来解决依赖版本错乱的问题) 文件,只不过和 package-lock 的格式有所不同
推出了 Plug'n'Play 零安装模式,放弃了 node_modules,更加保证以来的可靠性,构建速度也得到了极大提升
Plug'n'Play 零安装模式特点如下
pnpm 具有安装速度快、节约磁盘空间、安全性好等优点,它的出现也是为了解决 npm 和 yarn 存在的问题
pnpm 用了另一种方式,不再是复制了,而是都从全局 store 硬连接到 node_modules/.pnpm,然后之间通过软链接来组织依赖关系(如下图)

link也就是软硬连接,这是操作系统提供的机制。硬链接就是同一个文件的不同引用,而软链接是新建一个文件,文件内容指向另一个路径。当然,这两链接使用起来是差不多的
npm install -g pnpm
pnpm add vue
pnpm add vue -D
pnpm add -O [package] //保存到optionalDependencies
pnpm update
pnpm remove/uninstall
pnpm dlx // 从源中获取包而不将其安装为依赖项,热加载,并运行它公开的任何默认命令二进制文件。
pnpm link
pnpm store prune // 删除全局不再被引用的包硬链接可以理解为源文件的副本,使得用户可以通过不同的路径去找到某个文件,他和源文件大小一样但事实是不占用任何空间。pnpm 会在全局 store 目录里存储项目 node_modules 文件的硬链接。硬链接可以使得不同的项目可以从全局可寻址的存储仓库 store 寻找到同一个依赖,大大节省了磁盘空间
如果 A 是 B 的硬链接,则 A 的 indexNode(指针)与 B 的 indexNode 指向的是同一个。删除其中任何一个都不会影响另外一个的访问。作用:允许一个文件拥有多个有效路径,这样用户可以避免勿删
pnpm 在引用依赖时通过符号链接去找对应磁盘目录(.pnpm)下的依赖地址 类似于桌面快捷方式。比如 A 是 B 的软链接(A 和 B 都是文件名),A 和 B 的 indexNode 不相同,但 A 中只是存放着 B 的路径,访问 A 时,系统会自动找到 B,删掉 A 与 B 没有影响,相反删掉 B,A 依然存在,但它的指向是一个无效链接
pnpm 在创建链接时会根据具体情况选择使用硬链接或软链接
SemVer 是指语义版本规范(Semantic Versioning),用来约定包版本格式。它由三部分组成:主版本号、次版本号和修订版本号