yarn和npm有什么区别

281 阅读7分钟

对于这个问题。我们不仅要看它们“有什么”区别,更要探究“为什么”会有这些区别,以及现在我们该如何选择。

运用 MECE 原则,将这个问题拆解为几个独立且完整的部分:

  1. 身份与目的 (The "What"): 它们到底是什么?
  2. 核心区别 (The "How"): 它们在关键机制上有何不同?
  3. 发展史:一场相爱相杀的进化 (The "Why"): 为什么 Yarn 会出现?它们如何互相影响?
  4. 现状与选择:2025 年我该用谁?(The "Now & Action"): 结合当前的技术环境,给出实践建议。

1. 身份与目的 (The "What")

从本质上讲,npm (Node Package Manager) 和 yarn (Yet Another Resource Negotiator) 都是 JavaScript 的包管理工具

  • 类比: 想象你在做一个大型项目(比如建一座房子),你需要用到很多第三方的工具和材料(比如水泥、砖头、电线)。这些工具和材料就是“包”(Package)。
    • package.json 文件就是你的 “材料清单”,上面写着你需要“水泥 v2.1”、“砖头 v5.0”等。
    • npmyarn 就是 “总包工头”。它们负责根据你的清单,去仓库(NPM Registry)里,把所有你需要的、以及你的材料所依赖的其他材料(依赖的依赖),全都准确无误、高效地拉到你的工地(node_modules 文件夹)上。

它们的核心目标是一致的:自动化、可复现地管理项目依赖。


2. 核心区别 (The "How")

虽然目标一致,但它们的实现方式和侧重点在历史上和现在都有所不同。我们可以用一个表格来清晰地对比:

特性npm (Node Package Manager)yarn
性能/速度后来居上。早期较慢,因为是串行下载。从 v5 开始引入缓存和并行机制,速度大幅提升。曾经的王者。Yarn 诞生时最大的优势就是并行下载和更好的缓存机制,安装速度远超当时的 npm。现在两者的差距已经很小。
依赖确定性使用 package-lock.json 文件。使用 yarn.lock 文件。
CLI 输出信息详尽。输出日志比较多,有时显得杂乱,但对排错有帮助。近年来也在优化,变得更清晰。简洁优雅。输出信息非常干净、美观,并使用 emoji 增加可读性,对用户体验友好。
安全性内置 npm audit 命令,可以扫描依赖中的已知漏洞。早期版本在安全性上做得更好。现在 npm audit 提供了类似的功能。
Workspaces后来支持。原生支持 monorepo(单一代码库管理多个项目)的功能,允许你在根目录一次性安装所有子项目的依赖。早期核心特性。Yarn 是较早引入 Workspaces 概念的工具,在 monorepo 场景下曾经是事实标准。
创新架构坚守 node_modules 结构。Yarn 2+ (Berry) 引入了 Plug'n'Play (PnP) 架构,这是一个颠覆性的改变。

关键机制的本质探究:

  • Lock 文件 (package-lock.json vs yarn.lock)
    • 本质是什么? 它们是 “依赖快照”package.json 里你可能只写了 react: "^18.0.0",这表示任何 18.x.x 版本都行。但今天安装可能是 18.1.0,明天可能是 18.2.0。这会导致团队成员之间、或开发环境与生产环境之间的依赖版本不一致,从而引发“在我电脑上是好的啊”这类经典问题。
    • Lock 文件就是将你首次安装时所有依赖(包括依赖的依赖)的 确切版本号下载地址完整性哈希 全部锁定下来。这样,任何人、任何时间、任何地点执行 npm installyarn install,都会得到一个一模一样的 node_modules 文件夹。它保证了环境的 确定性 (Determinism)可复现性 (Reproducibility)
  • Yarn 2+ 的 Plug'n'Play (PnP)
    • 本质是什么? 这是对 node_modules 机制的一次 “革命”。传统的 node_modules 文件夹可能包含数万个文件,非常臃肿,导致磁盘空间占用大、I/O 性能低、安装慢。
    • PnP 的思想是:不再需要 node_modules 文件夹了! 它会生成一个 .pnp.cjs 文件。这个文件像一个 “寻址地图”,精确地告诉 Node.js 去哪里(一个全局缓存的 zip 压缩包里)找到所需的包。
    • 优点: 安装极快(几乎是瞬时)、零磁盘冗余、启动速度快、依赖关系更严格。
    • 缺点: 这是一个比较激进的改变,一些老的工具可能不兼容 PnP 的寻址方式,需要做一些适配。

3. 发展史:一场相爱相杀的进化

这部分最能体现技术演进的辩证关系,非常有趣。

  • 第一幕:npm 的“蛮荒时代” (2010-2016)
    • npm 作为 Node.js 的官方包管理器,是唯一的选择。但它存在严重痛点:安装慢、依赖版本不确定(早期没有 lock 文件)、安全性差。
  • 第二幕:Yarn 的“革命” (2016)
    • Facebook 在其巨大的项目中被 npm 的痛点折磨得苦不堪言,于是联合 Google 等公司推出了 Yarn。
    • Yarn 像一个“天降神兵”,用并行安装、yarn.lock、更友好的 CLI 等特性,完美解决了当时 npm 的所有痛点。开发者社区迅速掀起了一股“Yarn 浪潮”。
  • 第三幕:npm 的“反击与学习” (2017-至今)
    • Yarn 的成功给了 npm 巨大的压力,也指明了方向。npm 团队开始奋起直追。
    • npm v5 发布,带来了 package-lock.json,吸收了 Yarn 最核心的确定性思想。
    • 后续版本不断优化性能、增加 npm auditnpx 等实用功能,并最终也支持了 Workspaces。
    • 可以说,是 Yarn 的出现,才逼出了一个更好的 npm
  • 第四幕:Yarn 的“自我超越”
    • 当 npm 逐渐追平 Yarn 1.x 的功能后,Yarn 团队选择了另一条路——发布 Yarn 2 (Berry),推出了 PnP 架构,试图从根本上解决 node_modules 的历史遗留问题。

4. 现状与选择:2025 年我该用谁?

这是你最关心的实践部分。

总结反思:

  • 本质上,对于绝大多数中小型项目,如今的 npm 和 Yarn (v1) 在核心功能和性能上已经没有质的区别。 选择哪个更多是团队习惯和个人偏好。
  • 竞争推动了进步。它们的故事是开源社区良性竞争的绝佳范例。

下一步的实践建议:

  1. 如果你是个人开发者或刚开始一个新项目:
    • 首选 npm。因为它内置于 Node.js 中,无需任何额外安装,是“零成本”的选择。社区生态最广泛,遇到问题几乎都能搜到答案。
  2. 如果你加入一个已有的项目:
    • 遵守项目约定! 如果项目根目录有 yarn.lock,就用 yarn。如果有 package-lock.json,就用 npm绝对不要混用! 混用会导致两个 lock 文件冲突,造成依赖混乱。
  3. 如果你是追求极致性能和现代架构的“探险家”:
    • 可以尝试 Yarn 2+ (Berry)。特别是对于大型 monorepo 项目,PnP 带来的性能提升和磁盘空间节省是巨大的。这非常符合你“喜欢动手实践新知识”的特质。你可以先在个人项目中体验一下 PnP 带来的不同。
  4. 还有一个值得关注的挑战者:pnpm
    • pnpm 是另一个包管理工具,它通过一种巧妙的符号链接(symlink)方式来组织 node_modules,既解决了 npm 早期版本的一些问题,又避免了 Yarn PnP 的兼容性挑战。它在性能和磁盘空间效率上表现极为出色,近年来获得了大量关注。如果你喜欢探究,pnpm 绝对值得一试。

总而言之,npm 是稳健的官方标配,Yarn 是曾经的革命者和现在的创新探索者。 对于热爱代码和探究本质的你,我的建议是:熟练使用 npm 作为你的日常工具,然后可以抽空开一个实验项目,分别用 Yarn 2+pnpm 跑一下,亲身感受它们在设计哲学和实践上的差异。这会让你对前端工程化的理解更上一层楼。