npm、cnpm、yarn、pnpm

安装

1、安装npm需要安装nodejs,node中自带npm包管理器

node下载地址:下载 | Node.js

2、cnpm安装(需要安装npm)

cnpm是淘宝团队做的npm镜像,淘宝镜像每 10分钟 进行一次同步以保证尽量与官方服务同步。

npm install -g cnpm --registry=https://registry.npm.taobao.org

3、yarn安装(需要安装npm)

npm install -g yarn

官网地址:安装 | Yarn 中文文档

4、pnpm安装(需要安装npm)

npm install -g pnpm

官网地址:安装 | pnpm 中文文档 | pnpm 中文网

npm和yarn的比较

1、并行安装:yarn安装包会同时执行多个任务,npm 需等待上一个任务安装完成才能运行下一个任务(按照在package.json中声明的顺序),所以npm install 下载速度慢,即使是重新 install 时速度依旧慢

2、离线模式:如果你已经安装过一个包,用 yarn 再次安装会从缓存中获取,而 npm 会从网络下载

3、版本锁定:yarn 默认有一个 yarn.lock 文件锁定版本,保证环境统一,npm是通过

package-lock.json

4、更简洁的输出:yarn 安装包时输出的信息较少,npm 输出信息冗余

5、常用指令对比:

npm和yarn同时混用会有什么问题

当我们运行npm i lodash --savelodash将会被当做依赖加入到package.json中:

"dependencies": {
    "loadsh": "^4.17.4"
}

由于package.json文件中的版本号的特点,下面的三个版本号在安装的时候就代表不同的含义。

  • "6.0.3"表示安装指定6.0.3版本,
  • "~6.0.3"表示安装6.0.X中最新的版本,
  • "^6.0.3"表示安装6.X.X中最新的版本,

举个例子:以typescript依赖包为例

1、原项目中使用package.json定义项目中需要依赖的包,这里的typescript版本号为^4.2.4

2、原项目是用npm来进行包管理,从而生成package-lock.json文件,里面存储了各个依赖的具体来源和版本号,其中typescript的版本号为4.2.4,所以今后使用npm进行安装依赖时都会安装typescript的4.2.4版本,不会进行自动升级

3、如开发者使用yarn命令来进行包依赖安装,则package-lock.json文件无效,只看package.json中的文件,但typescript版本号为^4.2.4,从而会安装4.x.x版本中最新版本即为4.6.3版本,同时生成对应yarn.lock文件

4、启动项目会出现typescript类型报错,其原因是因为原项目是在4.2.4typescript版本环境下编写,但使用yarn进行依赖安装把typescript版本自动更新成了 4.6.3版本,同时4.2.4和4.6.3版本的typescript在类型校验上进行了较大的改进和优化,可以检测出更多的类型问题

所以,如有yarn.lock文件而没有package-lock.json文件则项目是以yarn 来进行包管理;

如有package-lock.json文件而没有yarn.lock文件则项目是以npm来进行包管理。

 参考文章:同项目混用npm和yarn出现版本自动更新问题_大狼狗的博客-CSDN博客_npm yarn 混用

pnpm

1、在npm3以前,采用的是嵌套安装的方式。假如我们安装依赖B和C时,如果B和C依赖中依赖了 packageD,那么会将 packageD重复安装2次。这将导致 会占据比较大的磁盘空间,且 windows 的文件路径最长是 260 多个字符,这样嵌套是会超过 windows 路径的长度限制的。

 

2、npm3+和yarn采取铺平的方式,将依赖扁平化,所有的依赖不再一层层嵌套了,而是全部在同一层,这样也就没有依赖重复多次的问题了,也就没有路径过长的问题了。

 

为什么会采取这样的方式呢?当我们运行require("xxx")引入外部模块时,

  • 如果xxx是一个node核心模块,例如fshttp等,那么返回node核心模块。
  • 如果不是,那么会判断判断当前node_modules 文件夹是否有此模块,如果有就返回,如果没有就递归往上层的node_modules目录查找,如果找到就返回,如果到根目录都没找到就报错。

所以当依赖B中的代码使用require("A")的时候,找不到A,会往上层的文件夹的node_modules中继续寻找,所以利用node的require机制,我们可以尽可能的把复用的依赖提升到最上层

a:这样貌似解决了我们的问题,事实上并没有而且引入了更大的问题幽灵依赖(node_modules 中的依赖包在没有 package.json 中声明的情况下使用了其他包的依赖)

如果 A 依赖 B, B 依赖 C,那么 A 当中是可以直接使用 C 的,但问题是 A 当中并没有声明 C 这个依赖。因此会出现这种非法访问的情况。因为没有显式依赖,万一有一天B不依赖C了,那你的代码也就不能跑了,因为你依赖的这个包C,但是现在不会被安装了。

b:除此之外:一个包是可能有多个版本的,提升只能提升一个,所以后面再遇到相同包的不同版本,依然还是用嵌套的方式。这就是依赖结构的不确定性。比如:如果提升了packageD2.0.0,依赖B和依赖C同时依赖了packageD1.0.0,那么D1.0.0还是会被安装多次。当两个不同的组件调用 packageD 时,它们可能会得到两个不同的库实例,这意味着可能会突然出现两个单例的实例.避免这个问题的解决方案:lock 文件

3、pnpm

Fast, disk space efficient package manager | pnpm

前置知识:

inode:每一个文件都有一个唯一的 inode,它包含文件的元信息,在访问文件时,对应的元信息会被 copy 到内存去实现文件的访问。

hard link:硬链接可以理解为是一个相互的指针,创建的 hardlink 指向源文件的 inode,系统并不为它重新分配 inode。硬链接不管有多少个,都指向的是同一个 inode 节点,这意味着当你修改源文件或者链接文件的时候,都会做同步的修改。每新建一个 hardlink 会把节点连接数增加,只要节点的链接数非零,文件就一直存在,不管你删除的是源文件还是 hradlink。只要有一个存在,文件就存在。(同一个文件的不同引用)

soft link:软链接可以理解为是一个单向指针,是一个独立的文件且拥有独立的 inode,永远指向源文件,这就类比于 Windows 系统的快捷方式。删除源文件,软链接就会失效。修改了软链接或硬链接的文件,另外的硬链接或软链接以及源文件都会发生变化,这里感觉是需要小心的,特别是修改文件以调试的时候,记得还原回去,否则另外一个项目用到的时候,可能会出问题。(新建一个文件,文件内容指向另一个路径)

.pnpm

虚拟存储目录——.pnpm,所有直接和间接依赖项都链接到此目录中。该目录通过 <package-name>@<version> 来实现相同模块不同版本之间隔离和复用

Store

pnpm在全局通过Store来存储所有的 node_modules 依赖,并且在 .pnpm 中存储项目的hard links

在使用 pnpm 对项目安装依赖的时候,如果某个依赖在 sotre 目录中存在了话,那么就会直接从 store 目录里面去 hard-link,避免了二次安装带来的时间消耗,如果依赖在 store 目录里面不存在的话,就会去下载一次。

假如全局的包变得非常大怎么办?使用方法为 pnpm store prune ,它提供了一种用于删除一些不被全局项目所引用到的 packages 的功能,例如有个包 axios@1.0.0 被一个项目所引用了,但是某次修改使得项目里这个包被更新到了 1.0.1 ,那么 store 里面的 1.0.0 的 axios 就就成了个不被引用的包,执行 pnpm store prune 就可以在 store 里面删掉它了。

原理分析

我们项目中有一个依赖 bar@1.0.0。bar@1.0.0也有一个依赖 foo@1.0.0。

  • node_modules 下面有 bar@1.0.0 和 .pnpm 目录,没有 foo@1.0.0

  • bar@1.0.0 通过软链接指向 .pnpm/bar@1.0.0/node_modules/bar@1.0.0.pnpm/bar@1.0.0/node_modules/bar@1.0.0 又通过硬链接指向 Store

  • bar@1.0.0 依赖的foo@1.0.0 会安装在跟自己的同一级,这里的设计,我理解是根据 node 的 require 机制,bar 中 require('foo') 的时候,就会先找到 foo@1.0.0,而不会往上寻找,这样就避免依赖包版本不一致的问题。.pnpm/bar@1.0.0/node_modules/foo@1.0.0。并通过软链接指向 .pnpm 下一级的 foo@1.0.0

  • .pnpm/foo@1.0.0 一样通过硬链接指向 Store

参考文章:pnpm 是凭什么对 npm 和 yarn 降维打击的 - 掘金

从npm 到 yarn 再到 pnpm —— 为什么要使用pnpm? - 掘金

最高性能的包管理器-pnpm

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值