当前位置: 首页 > news >正文

pnpm、npm、yarn 包管理工具『优劣对比』及『环境迁移』

前言

博主在开发前端网站的时候,发现随着开发的项目的逐渐增多,安装的依赖包越来越臃肿,依赖包的安装速度也是非常越来越慢,多项目开发管理也是比较麻烦。之前我就了解过 pnpm,但是当时担心更换包管理环境可能会出现的依赖等问题,并且也没有急切的需求,所以当时并没有立即更换

综上所述,随着上面问题的出现,更换包管理环境也逐渐提上日程,所以本文主要将会简单对比 pnpm 和 npm / yarn ,并且详细讲解如何在多项目环境中迁移到 pnpm

Pnpm安装与使用教程- 小白龙博客

介绍

npm v2

此时期主要是采用简单的递归依赖方法,最后形成高度嵌套的依赖树。然后就会造成如下问题:重复依赖嵌套地狱,空间资源浪费,安装速度过慢,文件路径过长等问题。大家都很熟悉,这里不再详细解释

npm v3

v3 版本作了较大的更新,开始采取扁平化的依赖结构。这样的依赖结构可以很好的解决重复依赖的嵌套地狱问题,但是却出现扁平化依赖算法耗时长这样新的问题

官方仓库 issue 的解释:npm@3 wants to be faster · Issue #8826 · npm/npm (github.com)

npm v5

为了解决上面出现的扁平化依赖算法耗时长问题,npm 引入 package-lock.json 机制,package-lock.json 的作用是锁定项目的依赖结构,保证依赖的稳定性,有兴趣的朋友可以直接查看官方文档

官方文档:package.json | npm Docs (npmjs.com)

注:其实在 package-lock.json 机制出现之前,可以通过 npm-shrinkwrap 实现锁定依赖结构,但是 npm-shrinkwrap 默认关闭,需要主动执行。

yarn

官网:Home page | Yarn (yarnpkg.com)

首先需要提出的是 yarn 出现时间为 2016 年,此时 npm 处于 v3 时期,其实当时 yarn 解决的问题基本就是 npm v5 解决的问题,包括使用 yarn.lock 等机制,锁定版本依赖,实现并发网络请求,最大化网络资源利用率,其次还有利用缓存机制,实现了离线模式

其实后面很多 npm 都是在学习 yarn 的机制,上面的机制目前 npm 基本也都实现了,就目前而言 npm 和 yarn 其实并没有差异很大,具体使用 npm 还是 yarn 可以看个人需求

pnpm

中文官网:pnpm - 速度快、节省磁盘空间的软件包管理器 | pnpm中文文档 | pnpm中文网

pnpm 内部使用基于内容寻址的文件系统来存储磁盘上所有的文件,这样可以做到不会出现重复安装,在项目中需要使用到依赖的时候,pnpm 只会安装一次,之后再次使用都会直接硬链接指向该依赖,极大节省磁盘空间,并且加快安装速度

注:硬链接是多个文件名指向同一个文件的实际内容,而软链接(符号链接)是一个独立的文件,指向另一个文件或目录的路径

也许有人说 yarn 默认也是扁平化安装方式,但是 yarn 有独特的 PnP 安装方式,可以直接去掉 node_modules,将依赖包内容写在磁盘,节省了 node 文件 I/O 的开销,这样也能提升安装速度,但是 yarn PnP 和 pnpm 机制是不同的,且总体来说安装速度 pnpm 是要快于 yarn PnP 的,详情请看下面官方文档

官方文档:Overview | Yarn (yarnpkg.com)

最后就是 pnpm 是默认支持 monorepo 多项目管理的,在日渐复杂的前端多项目开发中尤其适用,也就说我们不再需要 lerna 来管理多包项目,可以使用 pnpm + Turborepo 作为我们的项目管理环境

配置工作空间官方文档:工作空间(Workspace) | pnpm

img

还有就是 pnpm 还能管理 nodejs 版本,可以直接替代 nvm,命令如下所示

# 安装 LTS 版本
pnpm env use --global lts
# 安装指定版本
pnpm env use --global 16

迁移

迁移过程中主要有如下问题:因为使用 npm 或 yarn 安装依赖项时,所有包都被提升到模块目录的根目录。因此,源代码可以访问未作为依赖项添加到项目的依赖项。但是默认情况下,pnpm 使用链接仅将项目的直接依赖项添加到模块目录的根目录中

这意味着如果 package.json 没有引用的依赖,那么它将无法解析。这是迁移中的最大障碍。可以使用 auto-install-peers 设置自动执行此操作(默认情况下是false)

对于多个使用 npm 安装依赖的项目,单独删除依赖包很耗时间,我们可以使用 npkill ,该工具可以列出系统中的任何 node_modules 目录以及它们占用的空间。然后可以选择要删除的依赖以释放空间

npkill-demo-0.10.0

首先全局安装包

npm i -g pnpm

迁移步骤如下

1.首先使用 npkill 删除 node_modules 依赖包

2.项目根目录创建 .npmrc,填写如下内容

auto-install-peers=true

3.导入依赖锁定文件(pnpm-lock.yaml)

保证根目录有如下依赖锁定文件(npm-shrinkwrap.json,package-lock.json,yarn.lock)

然后执行如下命令

pnpm import pnpm-lock.yaml

4,最后执行 pnpm i 安装依赖

问题

生成依赖文件警告

官方 issue 解释: Unmet peer dependencies and The command – pnpm/pnpm (github.com)

生成 pnpm-lock.yaml 文件时出现如下警告

 WARN  Issues with peer dependencies found
.
└─┬ vuepress 1.9.9└─┬ @vuepress/core 1.9.9└─┬ vue-loader 15.10.1└─┬ @vue/component-compiler-utils 3.3.0└─┬ consolidate 0.15.1├── ✕ unmet peer react-dom@^16.13.1: found 15.7.0└── ✕ unmet peer react@^16.13.1: found 15.7.0

这是因为在 npm 3 中,不会再强制安装 peerDependencies (对等依赖)中所指定的包,而是通过警告的方式来提示我们。pnpm 会在全局缓存已经下载过的依赖包,如果全局缓存的依赖版本与项目 package.json 中指定的版本不一致,就会出现这种 hint 警告

我们可以在项目的 package.json 中配置 peerDependencyRules 忽略对应的警告提示

{"pnpm": {"peerDependencyRules": {"ignoreMissing": ["react"]}}
}

或者说直接在 .npmrc 配置文件中直接关闭严格的对等依赖模式,可以添加 strict-peer-dependencies=false 到配置文件中,或者执行如下命令

npm config set strict-peer-dependencies=false

然后也可能会出现警告 deprecated subdependencies found,暂时可以忽略

幽灵依赖问题

在最后安装依赖的时候可能会出现幽灵依赖问题,幽灵依赖就是没有在package.json中,但是项目中,或者引用的包中使用到的依赖

举个例子,比如我们现在使用 npm 安装了 v-viewer 依赖,同时 viewerjsv-viewer 的依赖项,由于扁平化依赖机制,我们可以在 node_modules/v-viewer/package.json 中看到声明的 viewerjs 依赖,即使项目根目录下的 package.json 没有声明 viewerjs 依赖,我们仍旧可以使用,这就是幽灵依赖

而现在我们切换为 pnpm 后,在默认情况下不允许访问未声明的依赖,有以下两种解决方案

1.自行安装未声明依赖项

幽灵依赖自动扫描工具:@sugarat/ghost - npm (npmjs.com)

pnpm i -S viewerjs

或者说某些版本 pnpm 会自动爆出幽灵依赖错误 missing peer ...,也可以直接不使用上面的扫描工具,直接自行安装后面的 ... 依赖

2.找到.npmrc 文件,在其中配置 public-hoist-pattern 或者 shamefully-hoist 字段,将依赖提升到根node_modules 目录下解决,也就是所谓的依赖提升

依赖提升官方文档:.npmrc | pnpm

# .npmrc
# 提升含有 eslint(模糊匹配)、prettier(模糊匹配)、viewerjs(精确匹配) 的依赖包到根 node_modules 目录下
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
public-hoist-pattern[]=viewerjs# 提升所有依赖到根 node_modules 目录下,相当于 public-hoist-pattern[]=*,与上面一种方式一般二选一使用
shamefully-hoist=true

当然,极不推荐用这样的方式解决依赖问题,这样没有充分利用 pnpm 依赖访问安全性的优势,又走回了 npm / yarn 的老路。

参考链接

  • pnpm 对比 npm/yarn 好在哪里 - 掘金 (juejin.cn)
  • 现在我更推荐 pnpm 而不是 npm/yarn? - 掘金 (juejin.cn)
  • 如何将 npm / yarn 项目迁移到 pnpm? - 掘金 (juejin.cn)
  • 浅谈 npm, yarn, pnpm之间的区别 - 掘金 (juejin.cn)
  • vue 配套生态已经全面使用 pnpm 了 - 掘金 (juejin.cn)
  • 打造高效Monorepo:Turborepo、pnpm、Changesets实践 – UU跑腿技术团队 (uupt.com)
  • 新一代包管理工具 pnpm 使用心得 - 知乎 (zhihu.com)
  • ERR_PNPM_PEER_DEP_ISSUES Unmet peer dependencies | 天問-专注于大前端技术 (tiven.cn)

本文由博客一文多发平台 OpenWrite 发布!

相关文章:

pnpm、npm、yarn 包管理工具『优劣对比』及『环境迁移』

前言 博主在开发前端网站的时候,发现随着开发的项目的逐渐增多,安装的依赖包越来越臃肿,依赖包的安装速度也是非常越来越慢,多项目开发管理也是比较麻烦。之前我就了解过 pnpm,但是当时担心更换包管理环境可能会出现的…...

【AntDesign】多环境配置和启动

环境分类,可以分为 本地环境、测试环境、生产环境等,通过对不同环境配置内容,来实现对不同环境做不同的事情。 AntDesign 项目,通过 config.xxx.ts 添加不同的后缀来区分配置文件,启动时候通过后缀启动即可。 config…...

Unix Network Programming Episode 78

‘getaddrinfo’ Function The gethostbyname and gethostbyaddr functions only support IPv4. The API for resolving IPv6 addresses went through several iterations, as will be described in Section 11.20(See 8.9.20); the final result is the getaddrinfo function…...

学习笔记(css穿透、vue-cookie、拦截器、vuex、导航守卫、token/Cookie、正则校验)

目录 一、记录 1、CSS穿透 2、输入框是否提示输入 3、插槽 #slot 4、v-deep深入改掉属性值 二、vue-cookie 1、官方文档 2、使用 三、拦截器 1、请求拦截器 2、响应拦截器 四、vuex对信息存取改 五、路由导航守卫 1、登录思路 2、设置白名单 六、Token与Cookie…...

Day4:Linux系统编程1-60P

我的学习方法是:Linux系统编程(看pdf笔记) Linux网络编程 WebServer 01P-17P Linux相关命令及操作 cp -a dirname1 dirname2 复制目录 cp -r dirname1 dirname2 递归复制目录 1 到目录 2 这里-a 和-r 的差别在于,-a 是完全复制…...

【HuggingFace】Transformers(V4.34.0 稳定)支持的模型

Transformer 4.43.40 版本是自然语言处理领域的一个重要工具包,为开发者提供了丰富的预训练模型资源,可以用于各种文本处理任务。在这个版本中,Transformer 支持了众多模型,每个模型都具有不同的优势和适用领域。下面是一个 Trans…...

oracle 导入数据泵常用语句

oracle常用语句 window10 导出导入数据泵文件导入数据泵文件导出数据泵文件 oracle表空间查询、剩余空间查询查询表空间大小及对应文件查询各个表空间大小扩充表空间 window10 导出导入数据泵文件 导入数据泵文件 首先将数据泵文件放在oracle安装得对应位置,例如&…...

tensorflow中的常见方法

1.tf.argmax(input,axis) tf.argmax(input,axis)根据axis取值的不同返回每行或者每列最大值的索引。 axis 0: 比较每一列的元素,将每一列最大元素所在的索引记录下来,最后输出每一列最大元素所在的索引数组。 test[0] array([1, 2, 3]) test[1] …...

【周末闲谈】“PHP是最好的语言”这个梗是怎么来的?

个人主页:【😊个人主页】 系列专栏:【❤️周末闲谈】 系列目录 ✨第一周 二进制VS三进制 ✨第二周 文心一言,模仿还是超越? ✨第二周 畅想AR 文章目录 系列目录前言最早的出处关于PHP语言优点缺点网络评价 总结 前言 …...

四位十进制数字频率计VHDL,仿真视频、代码

名称:四位十进制数字频率计VHDL,quartus仿真 软件:Quartus 语言:VHDL 代码功能: 使用直接测频法测量信号频率,测频范围为1~9999Hz,具有超量程报警功能 演示视频:四位十进制数字频…...

Unity实现设计模式——策略模式

Unity实现设计模式——策略模式 策略模式是一种定义一些列算法的方法,这些所有的算法都是完成相同的工作,只是实现不同。它可以通过相同的方式调用所有的算法,减少各种算法类与使用算法类之间的耦合。 策略模式的 Strategy 类层次为 Contex…...

C++基础——数据类型

1 概述 在创建变量和常量的时候,都需要指定其数据类型,以便为其分配合适的内存空间。 其中宏常量不需要指定类型,是因为宏定义是字符替换。 2 整型 整型表示的是整数,C中的整型有以下几种: 数据类型占用空间取值范…...

文本自动输入/删除的加载动画效果

效果展示 CSS 知识点 绕矩形四周跑的光柱动画实现animation 属性的 steps 属性值运用 页面基础结构实现 <div class"loader"><!-- span 标签是围绕矩形四周的光柱 --><span></span><span></span><span></span>&l…...

PHP8的匿名类-PHP8知识详解

PHP8支持通过new class 来实例化一个匿名类。所谓匿名类&#xff0c;就是指没有名称的类&#xff0c;只能在创建时使用new语句来声明它们。 匿名类是一种没有命名的即时类&#xff0c;可以用于简单的对象封装和实现接口。 以下是PHP 8中匿名类的基本语法示例&#xff1a; $ob…...

WebKit Inside: CSS 样式表的匹配时机

WebKit Inside: CSS 的解析 介绍了 CSS 样式表的解析过程&#xff0c;这篇文章继续介绍 CSS 的匹配时机。 无外部样式表 内部样式表和行内样式表本身就在 HTML 里面&#xff0c;解析 HTML 标签构建 DOM 树时内部样式表和行内样式就会被解析完毕。因此如果 HTML 里面只有内部样式…...

<HarmonyOS第一课>从简单的页面开始——闯关习题及答案

加入鸿蒙应用开发公开课系统学习HarmonyOS应用开发 判断题 1.在Column容器中的子组件默认是按照从上到下的垂直方向布局的&#xff0c;其主轴的方向是垂直方向&#xff0c;在Row容器中的组件默认是按照从左到右的水平方向布局的&#xff0c;其主轴的方向是水平方向。&#xff…...

视频下载plus+:一款强大的视频下载小程序

引言 在当下&#xff0c;随着视频号的火爆和用户数量的不断增加&#xff0c;视频下载已经成为了众多用户追求的目标。尽管市面上有很多视频下载助手&#xff0c;但是很多人对于如何下载视频还是摸不着头脑。今天我将向大家推荐一款我自己使用并且非常好用的视频下载小程序——…...

扭线机控制

扭线机属于线缆加工设备&#xff0c;线缆加工设备种类非常多。有用于网线绞合的单绞&#xff0c;双绞机等&#xff0c;有关单绞机相关算法介绍&#xff0c;大家可以查看专栏相关文章&#xff0c;有详细介绍&#xff0c;常用链接如下&#xff1a; 线缆行业单绞机控制算法&#…...

Android App启动优化之启动框架

android启动优化是个比较重要的部分&#xff0c;也是一大难题&#xff0c;一个优秀的app首先给人第一感觉就是启动速度&#xff0c;启动速度非常影响用户的体验&#xff0c;那么我们今天展开说说启动优化相关的问题。 我们先来简单分析一下启动过程、启动优化方向&#xff0c;…...

zookeeper入门篇之分布式锁

文章目录 前言非公平锁公平锁 前言 上一篇说过&#xff0c;zookeeper是一个类似文件系统的数据结构&#xff0c;每个节点都可以看做是一个文件目录&#xff0c;也就是说&#xff0c;我们所创建的节点是唯一的&#xff0c;那么分布式锁的原理就是基于这个来的。 代码仓库&…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...