基础15:npm、yarn、pnpm

news2024/11/21 0:34:42

npm2

用 node 版本管理工具把 node 版本降到 4,那 npm 版本就是 2.x 了。
执行 npm init, npm install express,可以看到node_modules目录如下:

在这里插入图片描述

可以看到,npm2的node_modules是嵌套的。
这种方式的优点就是模块依赖关系清晰。
缺点也比较明显:

  1. 依赖层级太深,会导致文件路径过长的问题,尤其在 window 系统下,最多260多个字符。
  2. 大量重复的包被安装,文件体积超级大。比如跟 foo 同级目录下有一个baz,两者都依赖于同一个版本的lodash,那么 lodash 会分别在两者的 node_modules 中被安装,也就是重复安装。
  3. 模块实例不能共享。比如 React 有一些内部变量,在两个不同包引入的 React 不是同一个模块实例,因此无法共享内部变量,导致一些不可预知的 bug。

当时npm还没解决这些问题,社区就出来一个新的解决方案了,那就是 yarn。

yarn

yarn生成的node_modules目录如下:
在这里插入图片描述

将所有内部依赖平铺到最外面一层,解决了上述嵌套方案的缺陷。
后面npm3 + 也采用类次方案实现了。
所有的依赖都被拍平到node_modules目录下,不再有很深层次的嵌套关系。这样在安装新的包时,根据 node require 机制,会不停往上级的node_modules当中去找,如果找到相同版本的包就不会重新安装,解决了大量包重复安装的问题,而且依赖层级也不会太深。
之前的问题是解决了,但仔细想想这种扁平化的处理方式,它真的就是无懈可击吗?并不是。它照样存在诸多问题:

  1. 依赖结构的不确定性。
  2. 扁平化算法本身的复杂性很高,耗时较长。
  3. 项目中仍然可以非法访问没有声明过依赖的包。

怎么理解第一条中的不确定性呢?
假如现在项目依赖两个包 foo 和 bar,这两个包的依赖又是这样的:

image

那么 npm/yarn install 的时候,通过扁平化处理之后,究竟是这样
image

还是这样的?
image

答案是: 都有可能。取决于 foo 和 bar 在 package.json中的位置,如果 foo 声明在前面,那么就是前面的结构,否则是后面的结构。

这就是为什么会产生依赖结构的不确定问题,也是 lock 文件诞生的原因,无论是package-lock.json(npm 5.x才出现)还是yarn.lock,都是为了保证 install 之后都产生确定的node_modules结构。

Phantom dependencies幽灵依赖

Phantom dependencies 被称之为幽灵依赖或幻影依赖,解释起来很简单,即某个包没有在package.json 被依赖,但是用户却能够引用到这个包。

比如yarn打包:
A依赖B, B依赖C,,那么 A 就算没有声明 C 的依赖,由于有依赖提升的存在,C 被装到了 A 的node_modules里面,在A里面引入C,没什么问题的。
但是,
第一, B 的版本是可能随时变化的,假如之前依赖的是C@1.0.1,现在发了新版,新版本的 B 依赖 C@2.0.1,那么在项目 A 当中 npm/yarn install 之后,装上的是 2.0.1 版本的 C,而 A 当中用的还是 C 当中旧版的 API,可能就直接报错了。
第二,如果 B 更新之后,可能不需要 C 了,那么安装依赖的时候,C 都不会装到node_modules里面,A 当中引用 C 的代码直接报错。
还有一种情况,在 monorepo 项目中,如果 A 依赖 X,B 依赖 X,还有一个 C,它不依赖 X,但它代码里面用到了 X。由于依赖提升的存在,npm/yarn 会把 X 放到根目录的 node_modules 中,这样 C 在本地是能够跑起来的,因为根据 node 的包加载机制,它能够加载到 monorepo 项目根目录下的 node_modules 中的 X。但试想一下,一旦 C 单独发包出去,用户单独安装 C,那么就找不到 X 了,执行到引用 X 的代码时就直接报错了。

npm 也有想过去解决这个问题,指定**–global-style**参数即可禁止变量提升,但这样做相当于回到了当年嵌套依赖的时代,一夜回到解放前,前面提到的嵌套依赖的缺点仍然暴露无遗。

pnpm

回想下,npm3+和yarn为什么要做node_modules 扁平划处理,不就是因为同样的依赖会复制多次,并且路径过长在 windows 下有问题么?
那如果不复制文件,比如通过link。
打开node_modules如下:
在这里插入图片描述
可以看到,该目录结构比较清晰,只有一个我们直接依赖的包express,并没有把express需要引用的包平铺开,并且也不在express包下面嵌套。
同时还有个 .pnpm 目录,目录结构如下:

.pnpm
├── lock.yaml
├── node_modules
│   ├── .bin
│   ├── accepts
│   ├── array-flatten
│   ├── body-parser
│   ├── bytes
│   ├── call-bind
│
│  
├── registry.npmmirror.com+accepts@1.3.8
│   └── node_modules
├── registry.npmmirror.com+array-flatten@1.1.1
│   └── node_modules
├── registry.npmmirror.com+body-parser@1.20.1
│   └── node_modules
├── registry.npmmirror.com+bytes@3.1.2
│   └── node_modules
├── registry.npmmirror.com+call-bind@1.0.2
│   └── node_modules

.pnpm 以平铺的形式储存着所有的包,正常的包都可以在这种命名模式的文件夹中被找到:

.pnpm/<organization-name>+<package-name>@<version>/node_modules/<name>

// 组织名(若无会省略)+包名@版本号/node_modules/名称(项目名称)

我们称.pnmp为虚拟存储目录,该目录通过<package-name>@<version>来实现相同模块不同版本之间隔离和复用,由于它只会根据项目中的依赖生成,并不存在提升,所以它不会存在之前提到的 幽灵依赖 问题!
那么它如何跟文件资源进行关联的呢?又如何被项目中使用呢?
答案是Store + Links!

Store

pnpm 资源在磁盘上的存储位置。

由于每个磁盘有自己的存储方式,所以Store会根据磁盘来划分。 如果磁盘上存在主目录,存储则会被创建在 /.pnpm-store;如果磁盘上没有主目录,那么将在文件系统的根目录中创建该存储。 例如,如果安装发生在挂载在 /mnt 的文件系统上,那么存储将在 /mnt/.pnpm-store 处创建。 Windows系统上也是如此。

可以在不同的磁盘上设置同一个存储,但在这种情况下,pnpm复制包 而不是 硬链接 它们,因为硬链接只能发生在同一文件系统同一分区上。

如果是 npm 或 yarn,那么这个依赖在多个项目中使用,在每次安装的时候都会被重新下载一次。
如果某个依赖在 sotre 目录中存在了话,那么就会直接从 store 目录里面去 hard-link,避免了二次安装带来的时间消耗,如果依赖在 store 目录里面不存在的话,就会去下载一次。

Links(hard link & symbolic link)

pnpm 是怎么做到如此大的性能提升的呢?一部分原因是使用了计算机当中的 Hard link ,它减少了文件下载的数量,从而提升了下载和响应速度。

hard link

通过hard link, 用户可以通过不同的路径引用方式去找到某个文件,需要注意的是一般用户权限下只能硬链接到文件,不能用于目录。
pnpm 会在Store(上面的Store) 目录里存储项目 node_modules 文件的 hard links ,通过访问这些link直接访问文件资源。
举个例子,例如项目里面有个 2MB 的依赖 react,在 pnpm 中,看上去这个 react依赖同时占用了 2MB 的 node_modules 目录以及全局 store 目录 2MB 的空间(加起来是 4MB),但因为 hard link 的机制使得两个目录下相同的 2MB 空间能从两个不同位置进行 CAS寻址 直接引用到文件,因此实际上这个react依赖只用占用2MB 的空间,而不是4MB。

如何判断是否是hard link?

  1. mac和linux中,hard link的文件和普通文件无异,node甚至无法区分hard link文件;
  2. 可以通过 ls -i 列出文件信息,第一个参数就是文件的 inode 值,其中,具有相同 inode 节点的多个文件互为hard link文件;
  3. 这样 就可以通过不同项目观察同一个依赖文件是不是一样的 inode 就能确定是不是同为 hard link了。

symbolic link

由于hark link只能用于文件不能用于目录,但是pnpm的node_modules是树形目录结构,那么如何链接到文件? 通过symbolic link(也可称之为软链或者符号链接)来实现!

pnpm在全局通过Store来存储所有的node_modules依赖,并且在.pnpm/node_modules中存储项目的hard links,通过hard link来链接真实的文件资源,项目中则通过symbolic link链接到.pnpm/node_modules目录中,依赖放置在同一级别避免了循环的软链。

如何判断是否是symbolic link?
打开文件夹,显示简介,mac会有展示,如下图:
在这里插入图片描述

pnpm中是如何结合hard link和symbolic link的

官方给了一张原理图,
在这里插入图片描述
从上图可以看出,项目直接依赖 bar, bar又依赖 foo包。
pnpm下载依赖时,首先在node_modules下创建一个bar@1.0.0的symbolic link,链向图示位置,然后在.pnpm中平铺所有依赖,观察bar@1.0.0/node_modules/,里面的bar文件hard link真实文件,foo又是symbolic link到上层foo@1.0.0,这样bar就能够根据路径找到foo了。

pnpm prune

根据计数引用原理删除不需要的依赖包

npx 、 nvm

npx

首先 npx 是一个工具,旨在帮助完善使用npm注册表中的软件包的体验-npm使得超级容易安装和管理注册表中托管的依赖项,npx使得使用CLI工具和托管在该注册表中的其他可执行文件变得容易 注册表。 到目前为止,它大大简化了许多需要使用纯npm进行一些程序化的事情:

  1. 直接调用项目安装的模块

    npm install -D mocha // 项目中安装mocha测试模块
    // 一般来说,调用 Mocha ,只能在项目脚本和 package.json 的scripts字段里面,
    //  如果想在命令行下调用,必须像下面这样。
    // 项目的根目录下执行 node-modules/.bin/mocha --version
    
    // 如果使用npx
    npx mocha --version
    // npx运行的时候,会到node_modules/.bin路径和环境变量$PATH里面,检查命令是否存在。
    
  2. 控制调用本地/远程模块

    • 强制使用本地模块,不下载远程模块
      npx --no-install http-server
    • 忽略本地同名模块,强制安装并使用远程模块
      npx --ignore-existing create-react-app my-react-app
  3. 执行一次性命令,避免全局安装

    $ npx create-react-app my-app 安装一个临时的 create-react-app 并且调用它,不会污染全局安装

    场景:
    比如尝试一个cli工具,可能这辈子只能用到这一次,不想这次使用完后还一直存在电脑硬盘里占用内存。
    步骤:

    • 当不在$PATH中时调用npx将自动从npm注册表安装一个具有该名称的包,并调用它。
    • npx 将create-react-app下载到一个临时目录,使用以后再删除。
    • 完成后,安装的软件包将会删除,而不会出现在globals中,不必担心全局污染。
  4. 使用不同版本的Node(同样适用于其他库的指定版本)

    npx -p node@ node -v 可以用于一次性运行node版本

  5. 执行Github源码

    # 执行 Gist 代码
    $ npx https://gist.github.com/zkat/4bc19503fe9e9309e2bfaa2c58074d32
    # 执行仓库代码
    $ npx github:piuccio/cowsay hello
    

nvm

这是一个切换node版本的一个工具。和 n 命令类似。

  1. n 是一个需要全局安装的 npm package。所以在使用n时,必须得有一个版本的node环境。
  2. 在安装的时候,n 会先将指定版本的 node 存储下来,然后将其复制到/usr/local/bin。
  3. nvm 是一个独立软件包,需要单独使用它的安装逻辑。
  4. 在使用 nvm 安装 node 的时候,nvm 将不同的 node 版本存储到 ~/.nvm// 下,然后修改 $PATH,将指定版本的 node 路径加入,这样我们调用的 node 命令即是使用指定版本的 node。
  5. nvm 的全局模块存在于各自版本的沙箱中,切换版本后需要重新安装,不同版本间也不存在任何冲突。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/10637.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NDIR二氧化碳传感器原理介绍

文章目录1. 引言2. 分类3. 红外气体传感原理3.1 朗伯-比尔定律3.2 非分光红外&#xff08;NDIR&#xff09;法检测原理3.3 浓度、温湿度标定3.4 响应时间研究4. 参考文献1. 引言 环境领域&#xff1a;近些年&#xff0c;二氧化碳是引起温室效应的主要气体&#xff0c;因此引起…

项目可交付成果的质量管理该怎么做?

通往项目最终服务或产品的道路往往是由许多临时可交付成果铺就的。每一个可交付成果本身都必须完整、质量合适并与所有其他可交付成果协调&#xff0c;同时确保&#xff1a; ● 保持客户和主要利益相关者所要求的质量水平。 ● 项目可交付成果是根据客户的规格和项目目标开发…

使用jenkins自动打包构建Maven项目

1.Jenkins是什么&#xff08;借鉴官网&#xff09; Jenkins是一款开源 CI&CD 软件&#xff0c;用于自动化各种任务&#xff0c;包括构建、测试和部署软件。 Jenkins 支持各种运行方式&#xff0c;可通过系统包、Docker 或者通过一个独立的 Java 程序 2.Jenkins下载安装 …

指纹和虚拟机哪个好用?两者之间的区别是什么?

2022年了&#xff0c;相信大家对指纹浏览器都不陌生了&#xff0c;很多做跨境电商、海外社媒营销、联盟营销的企业都会借助指纹浏览器来多账号批量管理。而在指纹浏览器没出现之前&#xff0c;大部分企业都会使用虚拟机来解决浏览器环境安全问题。所以指纹浏览器和虚拟机到底哪…

EN 14967:防水沥青防潮层—CE认证

防水沥青防潮层CE认证&#xff08;欧盟强制认证&#xff09;&#xff0d;简介 在欧盟市场“CE”标志属强制性认证标志&#xff0c;以表明产品符合欧盟《技术协调与标准化新方法》指令的基本要求。这是欧盟法律对产品提出的一种强制性要求。 在防水沥青防潮层上加贴CE标志不但可…

2021年全国职业院校技能大赛高职组“软件测试”赛项—“阶段二竞赛任务书”

2021年全国职业院校技能大赛高职组 “软件测试”赛项—“阶段二竞赛任务书” 2021年6月 软测讨论611474045 一、竞赛时间、内容及成绩组成 &#xff08;一&#xff09;竞赛时间 本阶段竞赛时间共为3小时&#xff0c;参赛选手自行安排任务进度&#xff0c;休息、饮水、如厕…

操作系统4小时速成:进程管理复习重点,进程,线程,处理机调度,进程同步,死锁

操作系统4小时速成&#xff1a;进程管理复习重点&#xff0c;进程&#xff0c;线程&#xff0c;处理机调度&#xff0c;进程同步&#xff0c;死锁 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开…

基于servlet的校园车辆管理系统

开发环境 eclipsemysql5.7jdk1.8 系统简介 基于Web的校园车辆管理系统主要用于对校园内的车辆进行管理&#xff0c;基本功能包括&#xff1a;人员信息管理模块&#xff0c;车位信息管理模块&#xff0c;IC卡信息管理模块&#xff0c;固定车辆管理模块&#xff0c;临时车辆管…

Java_继承

作者&#xff1a;爱塔居的博客_CSDN博客-JavaSE领域博主 专栏&#xff1a;JavaSE 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结一、为什么需要继承 &#x1f378;继承最大的意义是&#xff1a;对代码可以进行复用。 Java中使用类对现实世界…

Idea下载及配置

1、下载Vscode 1.1、官网 https://code.visualstudio.com/1.2、替换链接 将下载地址中的 az764295.vo.msecnd.net 更换为 vscode.cdn.azure.cn 使用国内的镜像服务器加速 https://vscode.cdn.azure.cn/stable/6261075646f055b99068d3688932416f2346dd3b/VSCodeUserSetup-x6…

【好文鉴赏】面试官说你回答的不够深入,怎么办?

关键词&#xff1a;[产品经理] [面试] 原文链接&#xff1a;https://coffee.pmcaff.com/article/3665424751688832/pmcaffutm_source 前言 生动&#xff0c;往往源于对事实的诠释&#xff1b; 面试官说逻辑力很强、沟通表达也很优秀&#xff0c;但在面试时效果并不太好&…

图片添加边框和文字怎么弄?图片编辑在线教学

大家平时在拍完照片后&#xff0c;会对它进行一些编辑处理吗&#xff1f;像我每次拍完照&#xff0c;都会对图片进行一些后期处理&#xff0c;有时也会给图片添加一些边框或者文字&#xff0c;美化图片并增加图片信息量。那你们平时都是怎么给图片加上边框和文字的呢&#xff1…

广和通5G AIoT模组引领亮相2022国际物联网展(IOTE),智赋行业数字化新价值

11月15-17日&#xff0c;2022国际物联网展&#xff08;IOTE&#xff09;于深圳盛大启幕&#xff0c;本届展会汇聚众多物联网行业大咖&#xff0c;共同展示并探讨物联网产业链的创新实践与成果。广和通以“5GAIoT深度融合&#xff0c;创新智造未来”为主题亮相现场。本次广和通展…

UI组件DevExpress ASP.NET Core v22.1亮点 - 甘特图、UI组件全新升级

DevExpress ASP.NET Web Forms Controls拥有针对Web表单&#xff08;包括报表&#xff09;的110种UI控件&#xff0c;DevExpress ASP.NET MVC Extensions是服务器端MVC扩展或客户端控件&#xff0c;由轻量级JavaScript小部件提供支持的70个高性能DevExpress ASP.NET Core Contr…

深入Spring 5 事务原理与源码分析【精品分享】

从一个编程式事务开始 Spring的声明式事务涉及到Bean的注入还有动态代理相关的知识&#xff0c;门槛会相对高一些。为了更容易理解事务&#xff0c;我们先从编程式事务的例子开始&#xff0c;逐步揭开Spring事务神秘的面纱。 //一个简单的编程式事务的例子Autowiredprivate Pl…

Linux常用工具及服务(ssh,rsync)

目录 一、SSH服务远程终端连接工具 1、SSH的登录原理 2、SSH基本用法 2.1 基本语法&#xff1a; 3、ssh服务认证类型 3.1 基于口令认证 3.2 基于密钥认证 4、ssh服务常见配置 4.1 常见配置 5、ssh客户端附带的远程拷贝scp命令 5.1 基本语法 二、Rsync远程同步及备份工…

k8s的接口文档——swagger-ui服务

文章目录1. 获取配置文件2. 启动swagger-ui2.1 用docker部署2.2 用docker-compose部署2.3 在k8s平台部署1. 获取配置文件 开启k8s的api临时端口 说明&#xff1a; 为导出k8s集群的api信息作为swagger-ui的配置文件&#xff0c;我们临时开一个api的临时端口该端口&#xff1a;只…

Qt 中设置窗体(QWidget)透明度的几种方法

Qt 中设置窗体(QWidget)透明度的几种方法 1. 设置窗体的背景色 在构造函数里添加代码&#xff0c;需要添加头文件qpalette或qgui QPalette pal palette(); pal.setColor(QPalette::Background, QColor(0x00,0xff,0x00,0x00)); setPalette(pal); 通过设置窗体的背景色来实…

连花清瘟卖断货?近一个月解热药价格暴涨33%,销额超206万元

近日&#xff0c;“连花清瘟生产商以岭药业正在疯狂招短期工”的消息登上热搜&#xff0c;以岭药业一度涨停。此外&#xff0c;石家庄其他感冒类药品也迎来线上线下一同销量大涨。 为此&#xff0c;鲸参谋特意查询了京东平台近一个月“解热镇痛”类药品的销售数据。可以看到&am…

SpringBoot自定义banner,如何定制炫酷的banner提升项目B格?

文章目录写在前面自定义banner使用banner.txt文件使用图片手写一个bannerbanner参数在 application.properties 文件中可以配置banner其他属性banner自身参数源码分析在线生成banner写在前面 Springboot启动的时候默认是有一套自己的banner的&#xff1a; 我们如何自定义这个…