npm,yarn,cnpm,pnpm的介绍

npm

首先说一下Node.js,简单的说 Node.js 就是运行在服务端的 JavaScript。node通过更改连接到服务器的方式,可以处理高并发任务。

npm: nodejs的包管理器,用于node插件管理(包括安装、卸载、管理依赖等)

npm使用一个名为package.json的文件,用户可以通过npm install --save命令把项目里所有的依赖项保存在这个文件里。

npm安装速度慢的一个重要原因:npm远程服务器在国外,必须首先遍历所有的项目依赖关系,然后再决定如何生成扁平化的node_modules结构。不过,npm有本地缓存,它保存了已经下载的每个版本的压缩包,缓存可以减少安装时间。

安装单个npm包:

npm、yarn、pnpm、cnpm对比其优劣势-编程知识网

devDependencies:通常是开发的工具(eg:测试用的库),开发环境的依赖

dependencies:与生产环境中应用程序相关的

两者的区别在普通项目中,两者都安装,程序才能跑起来(因为devDependencies一般包含程序运行环境依赖);纯node项目,只安装dependencies就可以运行项目了,而安装了 devDependencies后,就会让编辑器的 eslint检测插件开始工作,或者是可以用 jest进行单元测试:

npm、yarn、pnpm、cnpm对比其优劣势-编程知识网

是真正意义上的开发环境与生产环境分离。

npm使用方法:

第一种:

直接安装cnpm 安装淘宝提供的cnpm,并更改服务器地址为淘宝的国内地址, 命令:

npm install -g cnpm --registry=https://registry.npm.taobao.org,以后安装直接采用cpm替代npm, 例如原生npm命令为:npm install uniq --save,cnpm命令为:cnpm install uniq --save

第二种:

替换npm仓库地址为淘宝镜像地址(推荐) 命令:npm config set registry https://registry.npm.taobao.org, 查看是否更改成功:npm config get registry,以后安装时,依然用npm命令,但是实际是从淘宝国内服务器下载的

yarn

安装 | Yarn 中文文档 (bootcss.com)

快速、可靠、安全的依赖管理工具。

一开始是为了解决由于语义版本控制而导致npm安装的不确定的问题,每次安装都生成yarn.lock文件,yarn.lock
文件还包含要安装的内容的校验和,以确保使用的库的版本相同。

yarn的改进:

运行速度得到了显著的提升

像npm一样,yarn使用本地缓存。与npm不同的是,yarn无需互联网连接就能安装本地缓存的依赖项,它提供了离线模式

yarn的workspace

Yarn Workspaces(工作区)是Yarn提供的monorepo的依赖管理机制,从Yarn 1.0开始默认支持,用于在代码仓库的根目录下管理多个package的依赖。

Workspace 能更好的统一管理有多个项目的仓库,既可在每个项目下使用独立的 package.json 管理依赖,又可便利的享受一条 yarn命令安装或者升级所有依赖等。更重要的是可以使多个项目共享同一个 node_modules目录,提升开发效率和降低磁盘空间占用。

pnpm

Fast, disk space efficient package manager | pnpm官网

全称是 “Performant NPM”,即高性能的 npm。利用硬链接和符号链接来避免复制本地缓存源文件,继承了yarn的所有优点,包括离线模式和确定性安装

特点:速度快,节约磁盘空间,安全性高

高效利用磁盘空间

内部基于内容寻址的文件系统存储磁盘上所有的文件:

这个文件好处在于:

1.不会重复安装同一个包。设想一下,假如公司的每个项目都用了 vue 全家桶,那么每个项目都需要安装 vue、vue-router、vuex、axios 等几乎相同的库,如果有 100 个项目,那就要重复安装 100 遍!!非常耗费磁盘空间。

2.即使包的不同版本,pnpm也会极大程度的复用之前版本的代码。举个例子,比如 lodash 有 100 个文件,更新版本之后多了一个文件,那么磁盘当中并不会重新写入 101 个文件,而是保留原来的 100 个文件的 hardlink,仅仅写入那一个新增的文件

支持 monorepo

对于多个项目的管理,一般用多个git仓库。但是monorepo的宗旨就是用一个git仓库管理多个子项目,所有子项目都存放在根目录的packages目录下,那么一个子项目就代表一个package

如果你之前没接触过 monorepo 的概念,建议仔细看看这篇文章以及开源的 monorepo 管理工具lerna,项目目录结构可以参考一下 babel 仓库。

pnpm还保留了非扁平化的node_modules文件夹,避免了扁平化node_modules都带来的幻影依赖,依赖分身的问题。

安装可以使用npm安装:npm i -g pnpm

pnpm 的 node_modules

与依赖提升和扁平化的 node_modules 不同,pnpm 引入了另一套依赖管理策略:内容寻址存储。

cnpm

与npm用法完全一致

npm安装插件是从国外服务器下载,受网络影响大,可能出现异常。淘宝为我们搭建了一个国内的npm服务器cnpm,它目前是每隔10分钟将国外npm仓库的所有内容“搬运”回国内的服务器上,这样我们直接访问淘宝的国内服务器就可以了.

  1. cnpm 比 npm 快多了

  2. cnpm 没有 package-lock.json

cnpm最大的隐患:安装时不会产生 package-lock.json,并且项目中即使有 package-lock.jsoncnpm也是不管不顾的,只读取 package.json。阿hi有一个因哈UN就是用的包不一定遵循Semver规范。

  1. 有些依赖包用不了

有些依赖包用 cnpm 安装就不能用,用 npm 安装就可以用,这个问题估计和 cnpm包的使用软链接的方式有关系(并不确定)。

cnpm 和 npm 混用,导致包挂了,这个可以确定是 cnpm使用软链接的问题。所以,还是尽量不要混用吧。

能用 npm 最好用 npm,公司内部的 私有镜像源也建议做成 npm,毕竟 cnpm 还是存在一些隐患。

扁平化的node_modules

node_modules
├── A
│   └── node_modules
│       └── foo
└── B└── node_modules└── foo

最初,npm就简单通过依赖去递归安装包,A,B都依赖foo,那么就会有两份foo安装。为节省空间,采用了扁平化的node_modules。这样,foo会被提升到顶层,同一个包只会有一份。

node_modules
├── A
├── B
└── foo

但是会带来的问题是引入混乱,扁平化结构可以直接引用foo,但实际上并没有直接指定依赖foo,而是有层级关系,导致了引入上的错乱。如果A,B都不依赖foo,包会报错。

导致的问题:

幻影依赖:项目代码引用的某个包没有直接定义在 package.json中,而是作为子依赖被某个包顺带安装了。代码里依赖幻影依赖的最大隐患是,对包的语义化控制不能穿透到其子包,也就是包 a@patch的改动可能意味着其子依赖包 b@major
级别的 Break Change。(也就是说如果包改变了,那么被依赖的包就会破碎,出错)

但还有一种更难以解决的幻影依赖问题,即用户在 Monorepo 项目根目录安装了某个包,这个包可能被某个子 Package 内的代码寻址到,要彻底解决这个问题,需要配合使用 Rush,在工程上通过依赖问题检测来彻底解决。

比其优劣势

  • npm
    • node_modules扁平化结构
    • 支持workspace,大部分开发人员用npm也能很好的打包
    • 逐行安装(速度较慢)
    • 问题:幻影依赖,依赖分身
  • yarn
    • node_modules扁平化解构
    • 支持workspace,monorepo
    • yarn主要为了解决语义版本控制而导致npm安装不确定的问题,由yarn.lock文件,不过npm也出了package-lock文件
    • 并行安装(速度较快)
    • 问题:幻影依赖,依赖分身
  • pnpm
    • pnpm采用内存寻址存储的方法,通过软硬链接引用依赖,实现node_modules非扁平化结构,
    • 支持workspace,monorepo,速度快,磁盘占用空间小(速度最快)
    • 通过内容寻址存储解决了幻影依赖,依赖分身的问题,安全性高。
    • pnpm 的安装速度在大多数场景都比 npm 和 yarn 快 2 倍,节省的磁盘空间也更多。
    • 问题:
      • 因为依赖源文件是安装在 store 中,调试依赖或 patch-package 给依赖打补丁也不太方便,可能会影响其他项目。
      • 由于 pnpm 创建的 node_modules 依赖软链接,因此在不支持软链接的环境中,无法使用 pnpm,比如 Electron 应用。

npm、yarn、pnpm、cnpm对比其优劣势-编程知识网