Quiet
  • HOME
  • ARCHIVE
  • CATEGORIES
  • TAGS
  • LINKS
  • ABOUT

李致知

  • HOME
  • ARCHIVE
  • CATEGORIES
  • TAGS
  • LINKS
  • ABOUT
Quiet主题
  • pnpm
  • npm
  • yarn

对比:包管理器

李致知
对比系列

2023-09-18 14:36:57

文章目录
  1. 一,我为什么整理出这一篇文章?
  2. 二,包管理器是干啥的?
    1. 1,怎么实现依赖管理?
    2. 2,包管理器面临的难点
  3. 三,他们之间有什么区别?
    1. 1,Bower vs Npm:
    2. 2,Npm vs Yarn vs Pnpm:
  4. 四,总结
  5. #,参考资料

#毫无营养,只是第一次整理的初稿,请阅读参考文章,而且废话挺多哈哈。

一,我为什么整理出这一篇文章?

一直以来我对包管理器都不是很熟知,只是本能地认为pnpm>yarn>npm。但是我的主管就经常使用yarn而非pnpm。很多开源项目也是使用yarn,虽然这可能存在时间上的原因。但是这不禁让我想更加深入地了解一下前端包管理器。

二,包管理器是干啥的?

写代码时,很多功能我们不会从零开发手写,有很多其他人写的现成的包可用。对于这些包我们需要进行管理。

常见的我知道的包管理工具:

  • JS:bower、npm、yarn、pnpm
  • Java:Maven、Gradle
  • Go:dep、glide
  • Python:pip

1,怎么实现依赖管理?

简单地考虑地话,我们需要考虑我们的依赖的版本问题(依赖是会更新的吧,我们总不能跟着人家变吧)、依赖的存储问题(我们下载下来的第三方依赖怎么存储,他们之间可能还存在某种关系,数据结构怎么设计)

版本标识:A.B.C

  • A为主版本号,当接口发生改变,与之前的版本不兼容时。

  • B为次版本号,当增加了功能,但是向后兼容时。

  • C为补丁版本号,当修复了缺陷,但是向后兼容时。

  • 修饰符

    6.0.3 安装指定6.0.3版本
    ~6.0.3 安装6.0.X中最新的版本
    ^6.0.3表示安装6.X.X中最新的版本
    *表示会直接安装最新版本
    

2,包管理器面临的难点

  • 网络:部署在国外的第三方包怎么下载到国内
  • 依赖不确定性:依赖包使用的修饰符原因导致我们可能依赖的包会改变,这种情况怎么办
  • 嵌套层数太深:A依赖B、B依赖C、C依赖D,这会导致安装很耗时
  • 依赖冲突:A依赖B的1.0.0,C依赖B的2.0.0,我们是都下载下来呢还是只下载一个。
  • 磁盘空间占用大:依赖包每个项目都要下载一次,占用磁盘空间很大。
  • 目录路径很长:对windows来说,很多程序无法处理超过260个字符的文件路径名。

这些面临的问题,目前都有了一定的解决方案。

三,他们之间有什么区别?

所有的包管理器都有很多缺点,你只需要选择你可以忍受的。

1,Bower vs Npm:

历史上:

npm是2009年跟随Node.js出现而诞生的,它最初的目的是为了管理node.js模块,后来逐渐扩展到前端开发中,逐渐被广泛使用。

而Bower是在npm出现之后出现的。它在2012年出现,定位是前端开发中的包管理器(专门做了优化)。Bower在一段时间内得到广泛使用,但是后来随着npm的发展,Bower逐渐没落,并且于2017年宣布停止维护。

功能上:

  • npm专注于javascript脚本,但是Bower包括样式等其他前端资源(文字、HTML、字体甚至图像等等)。

  • npm做嵌套依赖(但不需要的情况下依旧是扁平的),而Bower扁平依赖。(扁平简单地说就是所有依赖包都放在一起,都只能下载一个版本而且只能下载一次,这就是Bower做出的优化,只下载一次依赖包,不就是优化嘛)

    怎么理解呢?如果我们项目的一个依赖包A本身需要用到1.0.0版本的pkg包,另一个依赖B本身要用到2.0.0版本的pkg包。

    当扁平处理的话,只会存在一个pkg包。这时就会出现问题。A和B到底谁能正常工作,这就是一种依赖冲突。

用途上:

不能说Bower就一无是处了。比如Bower可以用于运行时(这种情况下为了避免重复),Npm用于其他情况。当然最好还是别用Bower了哈哈。

2,Npm vs Yarn vs Pnpm:

历史上:

前面我已经说了npm的出身了;

而yarn是Facebook在2016年发布的包管理器,旨在解决npm的性能问题和安装过程中的不稳定性,提供了比如离线模式、并行安装和锁定文件(yarn.lock)等功能(等会详细说),除此之外它的workspaces功能非常好用。

pnpm在2016年由Zoltan Kochan创建,旨在减少磁盘空间占用和安装时间,此外还提供了类似yarn的一些功能,比如并行安装和锁定文件(pnpm.lock.yaml)。

我个人是倾向于使用pnpm。

三者的下载量:image-20230920205100554image-20230920205011727image-20230920205610316

可以看出来npm依旧是非常稳健,而pnpm后来者居上,下载量成为最高(但是有水分的,因为npm是默认捆绑在node上,这个没算上,所以还是有点不准滴)

功能上:

(介绍一下三者的功能,其实很多功能三者就相互学习,你有了之后我立马安排上了,所以有时候我们会觉得这三者越来越像了,他们之间的区别也越来越少了)

  • npm

    • 锁定文件:没错,yarn出我觉得挺好,我也出一个
    • 扁平目录:npmv3之前是非扁平,npm v3及之后则改为扁平。
  • yarn

    注意:大家一般使用的都是yarn classic(即yarn v1版本),但是现在yarn现在已经更新到yarn modern(yarn v3版本),现在我们通过npm安装的yarn依旧是yarn classic。

    我个人试了一下,存在迁移压力(逻辑和之前的不一样,v1就能用,迁移很烦的拜托),故还是用yarn v1哈哈。

    • 离线模式:会缓存下载过的包,意味着不需要再次下载相同的包(可以在没联网情况下载,直接从本地用户目录读取)

      #查询yarn缓存目录
      yarn cache dir
      #清除yarn的cache
      yarn cache clean
      #改变yarn缓存位置(这东西很吃存储,所以可以换个位置,又一个存储优化小妙招)
      yarn config set cache-folder "路径"
      
      #顺便说一下npm和pnpm的cache吧
      #查询npm缓存位置
      npm config get cache
      #清除npm的cache
      npm cache clean --force
      #设置npm缓存位置
      npm config set cache "路径"
      
      #查询pnpm的缓存目录
      pnpm c list
      #清除pnpm的缓存
      pnpm cache prune
      #清除由于版本更新不被引用的依赖包
      pnpm store prune
      #设置pnpm缓存路径
      pnpm config set store-dir "路径"
      
    • 锁定文件(yarn.lock):锁死项目的依赖包版本,确保依赖包版本更新不影响项目开发。

    • 并行下载:避免请求瀑布,提高下载速度

    • 扁平模式:传统情况下(指npm v3版本之前),npm将依赖包安装在每个依赖包的目录下(所以我们不会知道我们的依赖包的依赖包的确切版本),这可能会导致冲突。扁平化将依赖版本信息都放在yarn.lock里,之后找到一个兼容版本,将该版本安装在node_modules根目录下(只安装一次)。

    • 补丁制作:有些第三方依赖包我们想对它进行修改,可以使用yarn进行修复

    • Yarn PnP(中文名即插即用,yarn v2之后出现的东西,已经被pnpm也实现了):一种新的安装策略,不使用node_module形式,安装速度极大提升,占用内存极大减少。但是目前前端社区很多东西都依赖node_module的查找机制(比如TS类型声明定义,ESLint等等,所以不建议新手尝试这个东西)

    • Workspaces机制:用于monorepo的依赖管理机制,很受欢迎(与lerna配合使用更香哦)。

      yarn的workspaces机制是新手友好的,而lerna是配置更加复杂和多样的(嗯,新手不友好)。社区现在主流的方案是使用yarn workspaces来管理依赖,使用lerna来管理npm包的版本发布。

      基本所有功能都被同行做到了,只有workspaces和PnP是有优势的,但是PnP没被大众认可,workspaces机制社区非常喜欢。

  • pnpm

    • 非常快:比npm和yarn classic(经典模式的yarn,PnP模式下的yarn还是很能打的)都快。传统的三阶段安装是解析、获取、链接但是是全部的包完成才可以下一步。而pnpm不会等全部包下载才进行下一步。

    • 节省磁盘空间:所有文件都存在磁盘的某一个位置上(pnpm-store),如果你用到了某依赖项的不同版本,只会将不同版本间有差异的文件添加到仓库。

    • 高效:文件为复制或链接内容寻址存储库

    • 支持monorepo和PnP、离线模式、补丁制作:Pnpm内置支持单仓多包和PnP以及离线模式(友军(指yarn)有的我也有嘿嘿,但是确实更猛了,卷吧,都卷吧)

    • 非扁平的node_module目录:

      • npm和yarn classic安装依赖包都会被提升到模块目录的根目录,这导致我们项目代码可以访问依赖包的依赖(有时候我们没有在dependences写入的包但是能用,是因为我们的dependences有依赖包的依赖包有这个包,这样子导致之后可能会出现问题,这就是幽灵依赖)。所以pnpm使用这种非平铺的方式避免这种问题。

      • 除此之外,我们还要考虑一个问题。这种非扁平的方式npm早期使用,为啥npm放弃了,然后pnpm怎么解决npm当时放弃的原因的问题呢?当时npm放弃是避免npm v2 创建的嵌套 node_modules 引起的长路径问题。而pnpm使用一个.pnpm文件夹,这个文件夹下放置扁平化的依赖包。详情阅读参考文章pnpm相关的部分。

      • 非扁平的依赖关系树算法也比较简单

      • 这里还有一个符号链接(软链接,windows的软链接使用junctions替代,本质是一种文件夹形式的硬链接)的机制,它很适配Node的模块解析算法。它既避免了依赖目录过深,又满足node的模板解析算法。参考文章image-20230921232109616

      • 上一个问题简单的说:pnpm通过hard link(硬链接)来链接到真正的文件资源,项目中则通过使用symbolic link(软链接,又叫符号链接)链接到项目node-modules/.pnpm/node_modules。

      • image.png

        这里要说明一个问题,我们的pnpm-store要和我们的项目在一个磁盘上,不然它是复制而不是硬链接(因为硬链接只能创建在同一个分区或者说磁盘)。

        我们在一个磁盘上创建项目并使用pnpm安装的话,会在当前磁盘创建.pnpm/pnpm-store存放依赖包,然后hard-link到项目里。

这里要单独讲一讲他们的数据结构和对依赖的处理:

以我的一个微型项目为例:

这是pnpm:将所有次级依赖包(依赖包的依赖包)和根依赖包都放在了.pnpm文件夹里。node_modules目录下只放根依赖包。

image-20230921113722738这是peerdependences(举个例子,ant-design想要安装要求安装指定的react版本,我们有时候install完会弹出警告我们没安装相应的peer),比较复杂,前面的包+后面的peer包以及版本号image-20230921220359601

这是yarn:所有的依赖包以及(依赖包的依赖包)都放到一起image-20230921114431282

这是npm:和yarn一样image-20230921131020299

三者比较表格:功能比较 | pnpm

四,总结

实话说,你用的哪个爽就用哪个呗,真实开发你会发现哪个都行,没啥太大的区别(安装慢点多摸会鱼不香嘛,为啥就要快快快,如果再从空间上来说,我觉得直接硬件提升到2TB,你随便下载,那空间都不带掉的)。我反正是喜欢新东西,我用pnpm(现在大家新项目一般pnpm能做到前两者所有的事情了)。但是有时候用yarn和npm感觉也挺好的,没必要纠结这个,就酱。

#,参考资料

谈谈前端包管理进化简史 - mdnice 墨滴

Bower — a package manager for the web

npm Docs (npmjs.com)

javascript - Bower 和 npm 有什么区别? - SegmentFault 思否

漫谈前端包管理工具 - 掘金 (juejin.cn)

yarn - npm (npmjs.com)

Home page | Yarn (yarnpkg.com)

npm、yarn全局和缓存目录 - MINIDIY

前端各包管理器清除缓存攻略教程 | npm、yarn、pnpm | 清除缓存方法-诚哥博客 (chengzz.com)

pnpm - npm (npmjs.com)

Lerna · 是一个管理工具,用于管理包含多个软件包(package)的 JavaScript 项目 | Lerna 中文文档 (lernajs.cn)

Yarn Workspace使用指南 - 掘金 (juejin.cn)

Yarn Plug’n’Play可否助你脱离node_modules苦海? - 掘金 (juejin.cn)

Fast, disk space efficient package manager | pnpm

都2023年了,别再用 Yarn v1 啦 - JiPai Store

平铺的结构不是 node_modules 的唯一实现方式 | pnpm

Why should we use pnpm? by @ZoltanKochan

基于符号链接的 node_modules 结构 | pnpm

pnpm又是什么? - 简书 (jianshu.com)

都2022年了,pnpm快到碗里来! - 掘金 (juejin.cn)

PNPM设置全局包的安装路径 - 掘金 (juejin.cn)

peers 是如何被处理的 | pnpm

探讨npm依赖管理之peerDependencies - wonyun - 博客园 (cnblogs.com)

Windows的快捷方式、符号链接、目录联接、硬链接的区别_符号连接 目录连接_零号萌新的博客-CSDN博客

上一篇

对比:构建工具

下一篇

CSS布局方式

©2023 By 李致知. 主题: Quiet 鲁ICP备2022039519号-1
Quiet主题