简述下npm,cnpm,yarn和pnpm的区别,以及跟在后面的-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或多或少都会遇到这种情况

  1. 使用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 在安装时使用旧版的对等依赖行为。具体来说,它允许不严格检查对等依赖的版本冲突。
  1. 使用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了,因为它会无形中自动解决一些问题,希望对同道中人有点小用啦。。。

相关推荐
IT、木易9 分钟前
大白话阐述react和vue高阶组件的概念、优势及应用场景,以及区别,给出简单高阶组件的实现代码
前端·vue.js·react.js
HaanLen10 分钟前
React19源码系列之FiberRoot节点和Fiber节点
前端·javascript·react.js
冴羽20 分钟前
SvelteKit 最新中文文档教程(3)—— 数据加载
前端·javascript·svelte
百万蹄蹄向前冲37 分钟前
组建百万前端梦之队-计算机大学生竞赛发展蓝图
前端·vue.js·掘金社区
云隙阳光i1 小时前
实现手机手势签字功能
前端·javascript·vue.js
imkaifan1 小时前
vue2升级Vue3--native、对inheritAttrs作用做以解释、声明的prop属性和未声明prop的属性
前端·vue.js·native修饰符·inheritattrs作用·声明的prop属性·未声明prop的属性
觉醒法师1 小时前
HarmonyOS NEXT - 电商App实例三( 网络请求axios)
前端·华为·typescript·axios·harmonyos·ark-ts
Danta2 小时前
HTTP协议版本演进:从HTTP/0.9到HTTP/3的高分面试回答
前端·网络协议·面试
柠檬树^-^2 小时前
app.config.globalProperties
前端·javascript·vue.js
HAPPY酷2 小时前
微信开发者工具内建终端使用不了npm,但是cmd可以
微信小程序·小程序·npm