文章目录
- 前言
- 一、npm,cnpm,yarn和pnpm的基本介绍和特点
-
-
- 1.npm (Node Package Manager)
- [2. Yarn](#2. Yarn)
- [3. cnpm (China npm)](#3. cnpm (China npm))
- [4. pnpm](#4. pnpm)
-
- [二、简述npm和pnpm 的存储方式和依赖数](#二、简述npm和pnpm 的存储方式和依赖数)
- 三、两者依赖树的差异导致结果的对比
- [四、简单说说-g,--save, --save-dev代表着什么](#四、简单说说-g,--save, --save-dev代表着什么)
- 总结
前言
最近总有些同事问我为什么喜欢使用pnpm,除此之外慢慢开始带实习生,为了让一些基础的能够认清这些差别,所以简述下我的认知(仅供参考)
yarn、npm、cnpm 和 pnpm 是四种流行的 JavaScript 和 Node.js 包管理工具。
虽然它们都用于管理项目依赖,但在设计理念、功能和使用方式上存在一些显著的区别。
一、npm,cnpm,yarn和pnpm的基本介绍和特点
1.npm (Node Package Manager)
- 基本介绍:
- npm 是 Node.js 默认的包管理工具,随着 Node.js 的安装自动提供(其实你安装node,就会自带npm下来了)。
- 特点:
- 安装方式: 默认情况下,会将依赖包安装到每个项目的 node_modules 目录中。
- 性能: 安装速度相对较慢,尤其是当项目依赖较多时,因为每次都需要从头开始安装。
- 依赖管理: 使用扁平化依赖结构,可能导致依赖冲突(如多个版本的同一依赖)。
- 工作空间支持: 在较新版本中加入了工作空间的支持,但相对功能较为基础。
- 安装: 随着node版本安装会自带npm命令
2. Yarn
- 基本介绍:
- yarn 是 Facebook 开发的包管理工具,旨在提供更快的安装速度和更好的依赖管理。
- 特点:
- 安装方式: 默认使用 yarn.lock 文件锁定依赖版本,确保一致性。
- 性能: 通过并行安装和缓存机制,通常比 npm 更快。
- CLI 体验: 提供更友好的 CLI 输出和更好的错误提示。
- 工作空间支持: 支持工作空间,方便管理多包项目。
- 离线模式: 支持离线安装,依赖已经下载过的包可以在离线状态下使用。
- 安装: npm i yarn -g
3. cnpm (China npm)
- 基本介绍:
- cnpm 是一个专为中国用户设计的 npm 镜像,旨在解决 npm 在中国访问速度慢的问题。
- 特点:
- 镜像源: 将 npm 的包使用淘宝的镜像源,从而加速安装。
- 兼容性: 基本上与 npm 兼容,使用的命令和配置方式类似。
- 使用场景: 主要用于中国的开发者,以提高访问速度和稳定性。
- 安装: npm i cnpm -g
4. pnpm
- 基本介绍:
- pnpm 是一个高效的包管理器,专注于提高安装效率和减少磁盘空间的使用。
- 特点:
- 安装方式: 使用全局存储,所有包只存储一份,通过符号链接(symlink)进行引用,减少磁盘空间的占用。
- 性能: 通常比 npm 和 yarn 更快,特别是在处理多个项目之间共享依赖时。
- 依赖管理: 强制确保依赖的一致性,能够更好地处理不同版本的依赖,减少冲突。
- 工作空间支持: 具有强大的工作空间功能,适合多包项目(monorepos)的管理。
- 安装: npm i pnpm -g
二、简述npm和pnpm 的存储方式和依赖数
1.存储方式
javascript
1. npm 的存储方式
* 依赖安装路径:
默认情况下,npm 将所有依赖包安装在项目的 node_modules 目录下。每个包的依赖会在其自己的 node_modules 文件夹中。
如果一个依赖包有自己的依赖(即子依赖),npm 会在该依赖包的目录下再创建一个 node_modules 文件夹来存放这些子依赖。
* 扁平化依赖:
在较新的版本(npm 3及之后),npm 尝试将依赖尽量扁平化。如果多个包依赖于同一版本的依赖,npm 会将其安装在顶层的node_modules 目录中。但如果不同的依赖包需要不同版本的同一依赖,仍然会在相应的依赖包目录中安装这些版本。
* 空间使用:
由于可能会重复安装多个版本的相同依赖,npm 的存储方式可能导致大量的磁盘空间浪费,尤其是在有多个包依赖同一库时。
3. pnpm 的存储方式
* 全局存储:
pnpm 使用全局存储来存放所有包。所有依赖包会被安装到一个共享的位置(通常在用户的主目录下),而项目本身的 node_modules 目录只是存放指向这些全局包的符号链接(symlinks)。
这样,所有项目都可以通过符号链接访问同一依赖,从而避免重复存储。
* 严格的依赖声明:
pnpm 强制每个包只能直接访问其声明的依赖。这意味着包不会直接访问其父级或其他包的依赖,从而提高了模块的隔离性和可预测性。
* 空间使用:
由于采用了全局存储和符号链接,pnpm 在处理多个项目和依赖时,显著降低了磁盘空间的使用。这使得相同的依赖只需下载一次,无论有多少项目需要使用它。
2.依赖树
javascript
1. npm 的依赖树
当使用 npm 安装依赖时,npm 会创建一个层次化的依赖树,每个包的依赖都被单独安装在 node_modules 目录中。主要特点包括:
* 扁平化依赖:
npm 会尽量将依赖扁平化。在同一项目中,如果多个包依赖于同一版本的依赖,npm 会将其安装在根 node_modules 目录中。
* 多版本处理:
如果不同的依赖包依赖于同一库的不同版本,npm 会在相应的包目录中安装这些版本。这就意味着,一个包可能会存在多个版本的同一依赖,每个版本位于其依赖包的 node_modules 目录中。
* 依赖树结构:
依赖树可能看起来像这样:
└── project
├── packageA
│ └── packageB
│ └── packageC
└── packageD
└── packageB
└── packageC
在上述结构中,packageA 和 packageD 都依赖于 packageB,而 packageB 又依赖于 packageC。如果 packageB 需要不同版本的 packageC,则它们会被安装在各自的 node_modules 中。
2. pnpm 的依赖树
pnpm 的依赖处理方式与 npm 有显著不同,主要特点包括:
* 全局存储:
pnpm 将所有包安装到一个全局存储位置,实际的项目中只创建符号链接(symlink)指向这个全局存储。这样可以减少磁盘空间的使用。
* 严格依赖管理:
pnpm 强制每个包只能访问其直接声明的依赖,这意味着包无法访问其父级或其他包的依赖,确保更加一致和可预测的依赖关系。
* 依赖树结构:
依赖树可能看起来像这样:
├── project
│ ├── node_modules
│ │ ├── packageA
│ │ │ └── node_modules
│ │ │ └── packageB
│ │ │ └── node_modules
│ │ │ └── packageC
│ │ └── packageD
│ │ └── node_modules
│ │ └── packageB
│ │ └── node_modules
│ │ └── packageC
│ └── .pnpm
└── global storage
在这个结构中,packageA 和 packageD 仍然依赖于 packageB,但 pnpm 通过全局存储来确保只存储一份 packageB 和 packageC。每个包只能访问它们的直接依赖,从而避免了版本冲突的问题。
三、两者依赖树的差异导致结果的对比
请看以下内容,相信有过一两年的经验,可能使用npm或多或少都会遇到这种情况
- 使用npm i 的情况
上述其实说的问题就是依赖冲突导致不能下载依赖包
项目中postcss-loader
需要安装7.3.4,但另一个依赖要求3.0.0到4.0.0之间,这就是npm依赖树导致的问题,需要人为的手动安装指定版本,或者通过npm install --force 或者 npm install --legacy-peer-deps解决
但是需要注意的是
- --force:选项强制执行某些操作,即使遇到错误或警告,也会继续执行。使用这个选项可以忽略某些依赖冲突或不符合规范的情况。
- --legacy-peer-deps:选项使得 npm 在安装时使用旧版的对等依赖行为。具体来说,它允许不严格检查对等依赖的版本冲突。
- 使用pnpm i 的情况
它会自动处理一些依赖树的关系,也不会存在什么忽略或者强制处理,这样会减少隐藏的一些问题
四、简单说说-g,--save, --save-dev代表着什么
-g / --global:这个选项用于全局安装包。当你希望将包安装到全局环境中,以便在系统的任何地方都能使用时,通常用于命令行工具(CLI)。
--save:将安装的依赖包添加到项目的 package.json 文件的 dependencies 列表中。在 npm 5 之后,默认情况下会自动将依赖保存到 dependencies 中,因此这个选项在现代 npm 使用中不再经常需要。
-D / --save-dev:将安装的包添加到项目的 package.json 文件的 devDependencies 列表中。用于开发过程中需要的工具,例如测试框架、构建工具等,这些工具在生产环境中并不需要。
--save-exact:将安装的包的具体版本(而不是范围版本)保存到 package.json 中。当你希望确保项目在安装时使用确切的版本,而不是可能的较新版本。
--no-save:安装包时不更新 package.json 文件。临时安装某个包用于测试或调试。
--production:仅安装 dependencies 中列出的包,忽略 devDependencies。在生产环境中部署应用程序时使用。
-E / --save-exact:将依赖包的确切版本(不带波浪号或插入符号)保存到 package.json 中。
--legacy-peer-deps:忽略对等依赖的冲突,在安装时使用旧版行为。解决某些依赖冲突问题时使用。
--force:强制执行操作,忽略警告和错误,适用于需要绕过冲突或错误的情况。
总结
以上就是个人收集总结的一些小东西了,给自己总结同时记录,这也就是我为什么偏爱使用pnpm
了,因为它会无形中自动解决一些问题,希望对同道中人有点小用啦。。。