<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>包管理器 on Kmoon Blog</title>
    <link>https://blog.kmoon.fun/blog/%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8/</link>
    <description>Recent content in 包管理器 on Kmoon Blog</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    
      <managingEditor>hushan@kmoon.fun (Kmoon)</managingEditor>
    
    
      <webMaster>hushan@kmoon.fun (Kmoon)</webMaster>
    
    
    <copyright>Copyright © 2020-2026. Kmoon.</copyright>
    
    
    <lastBuildDate>Sat, 22 Jun 2024 15:56:44 +0800</lastBuildDate>
    
    
    <follow_challenge>
        <feedId>00000000000000000</feedId>
        <userId>00000000000000000</userId>
    </follow_challenge>
    
    <atom:link href="https://blog.kmoon.fun/blog/%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>区分 npm、pnpm、yarn、npx、bun</title>
      <link>https://blog.kmoon.fun/%E5%8C%BA%E5%88%86-npmpnpmyarnnpxbun/</link>
      <pubDate>Sat, 22 Jun 2024 15:56:44 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/%E5%8C%BA%E5%88%86-npmpnpmyarnnpxbun/</guid>
      <description>&lt;p&gt;上个月我想跑一个开源项目，在 GitHub 上搜了个 star 数挺多的 admin 后台模板，clone 下来，按照 README 写的 npm install。&lt;/p&gt;&#xA;&lt;p&gt;结果报错，满屏的红字。&lt;/p&gt;&#xA;&lt;p&gt;我当时就懵了。这项目不是挺火的吗，怎么跑不起来？&lt;/p&gt;&#xA;&lt;p&gt;仔细看了报错信息，又翻了翻项目的 issues，才发现它在 package.json 旁边有一个 pnpm-lock.yaml 文件。有人说要用 pnpm install 才行。&lt;/p&gt;&#xA;&lt;p&gt;我？？？&lt;/p&gt;&#xA;&lt;p&gt;我当时就觉得，这事儿太离谱了。我学了四年计算机，居然连包管理器都没搞明白。课堂上学的是 npm，网上教程也基本都是 npm，结果现在跑个开源项目，告诉我得用 pnpm。&lt;/p&gt;&#xA;&lt;p&gt;而且还有 yarn、bun、npx，这些东西到底有啥区别？为啥不能只用一种？&lt;/p&gt;&#xA;&lt;p&gt;我想了想，干脆把我这段时间摸索的东西写下来。可能有些想法还不成熟，但都是我踩过坑之后的真实感受。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;先说结论吧，省得你着急。&lt;/p&gt;&#xA;&lt;p&gt;npm、pnpm、yarn，这三个都是&lt;strong&gt;包管理器&lt;/strong&gt;，干的活是一样的，帮你下载和管理项目依赖的那些第三方库。bun 也是包管理器，但它野心更大，想包办你所有的 JavaScript 工具链。npx 则是个&lt;strong&gt;执行器&lt;/strong&gt;，专门用来运行那些你还没安装的命令行工具。&lt;/p&gt;&#xA;&lt;p&gt;搞定。下课。&lt;/p&gt;&#xA;&lt;p&gt;但这样说你肯定不满意，对吧。我们一件一件来聊。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;npm 是这堆东西里的老大哥。&lt;/p&gt;&#xA;&lt;p&gt;它跟着 Node.js 一起出生，2009 年就有了。那时候 JavaScript 还只是个在浏览器里弹 alert 的小玩具，谁能想到十几年后它能统治整个互联网呢。&lt;/p&gt;&#xA;&lt;p&gt;npm 的好处就一个，&lt;strong&gt;自带&lt;/strong&gt;。你装了 Node.js，它就跟着来了，不用额外折腾。这对我们学生来说是最大的友善，毕竟课堂上的示例、网上的教程，基本都是围绕 npm 来的。&lt;/p&gt;&#xA;&lt;p&gt;但 npm 有个臭名昭著的问题，叫「node_modules 黑洞」。&lt;/p&gt;&#xA;&lt;p&gt;你执行 npm install 之后，项目的 node_modules 文件夹会像一个贪吃蛇一样疯狂膨胀。一个 express 项目，源码可能就几十 KB，装完依赖能给你干到几百 MB。我们宿舍那个 256GB 的 Mac，装几个项目就提示磁盘空间不足，给我整懵了。&lt;/p&gt;&#xA;&lt;p&gt;而且 npm 早期的依赖管理有点混乱，经常出现「我电脑上能跑，你电脑上报错」这种玄学问题。你懂的，小组作业的时候最容易碰到这种情况，A 说能跑，B 说跑不了，C 说重装试试，结果重装了一晚上。&lt;/p&gt;&#xA;&lt;p&gt;2016 年，yarn 出现了。&lt;/p&gt;&#xA;&lt;p&gt;yarn 是 Facebook 出的，当时就是为了解决 npm 的一系列痛点。它最大的贡献是引入了 yarn.lock 文件，把依赖的版本死死钉住，再加上缓存机制和并行下载，速度快得飞起。&lt;/p&gt;&#xA;&lt;p&gt;我在实习的时候第一次接触 yarn，那种感觉太爽了。npm install 要跑两分钟的，yarn install 几十秒搞定。&lt;/p&gt;&#xA;&lt;p&gt;而且 yarn 有一个很贴心的设计，就是它的输出格式比 npm 好看多了。npm 安装的时候满屏乱飞的红字黄字，yarn 就干净很多，看着舒服。&lt;/p&gt;&#xA;&lt;p&gt;但 yarn 也不是完美的。它虽然快了，但 node_modules 黑洞的问题还在。毕竟底层还是一样的机制，该占的硬盘空间一点没少。我实习公司的项目，node_modules 能到 1GB 多，每次 clone 新仓库都想哭。&lt;/p&gt;&#xA;&lt;p&gt;这时候，pnpm 登场了。&lt;/p&gt;&#xA;&lt;p&gt;pnpm 的思路很清奇，它说，你们这些包管理器是不是傻，同一个 lodash，十个项目要用，你们就存十份？不能搞个全局仓库，大家共用吗。&lt;/p&gt;&#xA;&lt;p&gt;所以它搞了个叫「内容寻址存储」的东西。所有的包只存一份，项目里用硬链接或者符号链接指向那个全局仓库。这样一来，你的 node_modules 瞬间瘦身，从几百 MB 变成几 MB 都是常有的事。&lt;/p&gt;&#xA;&lt;p&gt;我第一次看到 pnpm 的 node_modules 结构时，真的被震撼到了。文件夹里全是快捷方式，看起来跟幽灵一样，但偏偏都能跑。&lt;/p&gt;&#xA;&lt;p&gt;而且 pnpm 还有一个很硬的优势，它严格遵守依赖树，不会出现 npm 那种「幽灵依赖」的问题。啥叫幽灵依赖，就是你明明没有在 package.json 里声明某个包，但却能在代码里引用它。这是因为 npm 的扁平化结构把依赖都摊在了一级目录下，你不知道哪个包其实是别的包的子依赖。&lt;/p&gt;&#xA;&lt;p&gt;pnpm 的结构是严格嵌套的，你只能在声明了依赖的地方找到它，不会出现这种混乱。&lt;/p&gt;&#xA;&lt;p&gt;说实话我现在新写的作业和项目基本都是 pnpm 了。省硬盘，速度快，结构清晰，没啥理由不用。我那个 256GB 的 Mac 终于能喘口气了。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;说到这，可能有小伙伴纳闷，那 bun 又是啥？&lt;/p&gt;&#xA;&lt;p&gt;bun 是个新玩家，2022 年才出来的，但来势汹汹。它不只是包管理器，它是一个完整的 JavaScript 运行时，对标的是 Node.js 本身。&lt;/p&gt;&#xA;&lt;p&gt;bun 的安装速度快得离谱。它用 Zig 语言写的，号称比 npm 快 30 倍。我自己的测试，一个中等规模的课程项目，npm install 要一分多钟，bun install 十几秒完事。&lt;/p&gt;&#xA;&lt;p&gt;而且 bun 内置了很多东西。Node.js 你要写 TypeScript 得配一堆工具，bun 直接原生支持。你要跑测试，Node.js 得装 jest 或者 vitest，bun 内置了测试 runner。你想打包，bun 也能干。&lt;/p&gt;&#xA;&lt;p&gt;它的野心很大，就是想让你一个工具搞定所有事情。&lt;/p&gt;&#xA;&lt;p&gt;但我目前还是观望状态。为啥呢，因为 bun 太新了，生态还没完全成熟。有些 npm 的包在 bun 上跑会有兼容性问题，特别是一些原生 C++ 扩展的模块。不是说 bun 不好，而是说如果你在做毕业设计或者期末大作业，稳定性可能还是优先考虑 npm 或者 pnpm。交作业前一天报错，那可不是闹着玩的。&lt;/p&gt;&#xA;&lt;p&gt;不过我自己玩一些小 demo 或者刷 LeetCode 的时候，确实会用 bun。那种秒开的感觉，真的太特么赤鸡了。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;好了，现在说 npx。&lt;/p&gt;&#xA;&lt;p&gt;npx 是个异类，它不是包管理器，它是&lt;strong&gt;执行器&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;它的作用很简单，帮你运行那些你没有全局安装的命令行工具。&lt;/p&gt;&#xA;&lt;p&gt;举个例子。你想用 create-react-app 新建一个 React 项目，传统做法是 npm install -g create-react-app，全局装一下，然后再运行。但这样一来，这个工具就常驻你电脑了，你其实只用了一次，但它一直占着茅坑。&lt;/p&gt;&#xA;&lt;p&gt;npx 的做法是，npx create-react-app my-app，它会临时下载这个工具，执行完，然后删掉。干净，利落，不占地方。&lt;/p&gt;&#xA;&lt;p&gt;我现在基本上所有一次性的脚手架工具都用 npx 跑。npx create-next-app，npx degit，npx ts-node，都是这个逻辑。&lt;/p&gt;&#xA;&lt;p&gt;而且 npx 还有一个妙用。有时候你全局装了一个工具，但版本比较老，课程作业需要新版本。你可以用 npx 指定版本跑，npx create-react-app@5 my-app，这样就不会和你全局的老版本冲突。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;说到这，你可能已经有点感觉了。&lt;/p&gt;&#xA;&lt;p&gt;但这几个东西到底怎么选呢？我分享一下我自己的经验，可能有些想法还不成熟，但都是我踩过坑之后的真实感受。&lt;/p&gt;&#xA;&lt;p&gt;如果你是刚接触编程的大一新生，&lt;strong&gt;先用 npm&lt;/strong&gt;。它是标配，老师上课讲的、教材上写的、网上的入门教程，基本都是 npm。先把基础打扎实，别急着追新。&lt;/p&gt;&#xA;&lt;p&gt;如果你开始做课程设计或者小组项目，我推荐 &lt;strong&gt;pnpm&lt;/strong&gt;。node_modules 黑洞在学生电脑上真的是灾难，特别是你 C 盘只有 128GB 的情况下。pnpm 能把你从磁盘空间不足的恐惧中解救出来。而且它的严格依赖树能避免很多「我电脑上能跑」的诡异 bug，小组作业的时候少很多撕逼。&lt;/p&gt;&#xA;&lt;p&gt;如果你喜欢尝鲜，做一些个人 side project 或者参加黑客马拉松，可以试试 &lt;strong&gt;bun&lt;/strong&gt;。它的开发体验确实丝滑，内置的功能也很全，能快速搭出原型。但要有心理准备，遇到兼容性问题时可能要花时间去解决，正式交作业前还是用 npm 或 pnpm 跑一遍稳当。&lt;/p&gt;&#xA;&lt;p&gt;yarn 呢？yarn 现在处于一个比较尴尬的位置。pnpm 出来之后，它的很多优势被蚕食了。但 yarn 有一个独特的场景，就是 Yarn Workspaces，用来做 monorepo 管理。如果你的项目是一个大型仓库，里面包含多个子项目（比如前后端在一起），yarn 的 workspace 功能还是挺成熟的。不过 pnpm 的 workspace 现在也很好用了，所以 yarn 的优势在逐渐缩小。&lt;/p&gt;&#xA;&lt;p&gt;至于 npx，&lt;strong&gt;所有人都应该用起来&lt;/strong&gt;。它和上面这些包管理器不冲突，是一个独立的工具。任何一次性的命令行操作，都用 npx，别全局安装那些你用不了几次的东西。你的电脑会感谢你的。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;其实吧，这些工具之间的撕扯，背后有一个更大的逻辑。&lt;/p&gt;&#xA;&lt;p&gt;JavaScript 的生态一直是这样，百花齐放，各显神通。没有一个「官方标准」，大家都在试，好的留下来，差的被淘汰。npm 不好用，yarn 就来了。yarn 还有问题，pnpm 就冒出来了。Node.js 太慢了，bun 就想颠覆它。&lt;/p&gt;&#xA;&lt;p&gt;这种混乱对于学生来说确实痛苦，你要学的东西太多了，而且永远在变。你今年学的，明年可能就过时了。&lt;/p&gt;&#xA;&lt;p&gt;但从另一个角度看，这也是 JavaScript 生态的活力所在。没有人躺在功劳簿上睡大觉，永远有人在尝试做得更好。你今天觉得 pnpm 已经够快了，明天可能就会出现一个更快的。你今天觉得 bun 已经够全了，后天可能就会有更全的。&lt;/p&gt;&#xA;&lt;p&gt;这就是所谓的「大时代」吧，朋友们。&lt;/p&gt;&#xA;&lt;p&gt;我们这一代人，刚好站在 JavaScript 从「浏览器脚本语言」变成「全栈通用语言」的历史节点上。我们见证了这个生态的野蛮生长，也见证了这些工具的迭代更替。多年以后回头看，你现在纠结的 npm 还是 pnpm，可能会像我们现在看「当年用不用 jQuery」一样，成为一种时代的眼泪。&lt;/p&gt;&#xA;&lt;p&gt;但这就是技术的魅力，不是吗？&lt;/p&gt;&#xA;&lt;p&gt;永远有新的东西值得学习，永远有人在把不可能变成可能。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;最后，回到开头那个跑不起来的开源项目。&lt;/p&gt;&#xA;&lt;p&gt;我用 pnpm install 试了一下，果然跑起来了。当时那种感觉，怎么说呢，有点爽，又有点无语。&lt;/p&gt;&#xA;&lt;p&gt;爽的是问题解决了，无语的是，为啥这些工具不能统一一下？&lt;/p&gt;&#xA;&lt;p&gt;但后来我明白了，这就是技术发展的常态。没有最好的工具，只有最适合的工具。&lt;/p&gt;&#xA;&lt;p&gt;所以我的建议是，&lt;strong&gt;先用 npm，把基础打扎实&lt;/strong&gt;。课堂上的东西、网上的入门教程，基本都是 npm。能跑起来最重要，等你写多了，自然会遇到 npm 解决不了的问题，那时候你就会知道 pnpm 好在哪了。&lt;/p&gt;&#xA;&lt;p&gt;工具是服务于人的，不是来折磨人的。不要为了用新工具而用新工具，也不要因为害怕变化而拒绝新工具。&lt;/p&gt;&#xA;&lt;p&gt;保持好奇，保持开放，但脚要踩在地上。&lt;/p&gt;&#xA;</description>
    </item>
  </channel>
</rss>
