ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Mac 安装 Yarn 避坑指南:从芯片架构到 corepack 的完整实践

Mac 安装 Yarn 避坑指南:从芯片架构到 corepack 的完整实践

1. 为什么 Mac 上装 Yarn 这件事值得单独写一篇

很多人看到"Mac 安装 yarn"这个标题,第一反应是:不就一行命令的事吗?npm install -g yarn敲下去不就完了?我一开始也这么想,直到我在三台不同芯片、不同系统版本的 Mac 上反复折腾,才发现这件事的坑远比想象中多。尤其是 Apple Silicon 芯片普及之后,Node 版本管理工具、包管理器、全局路径、权限这几件事搅在一起,新手很容易装完发现命令找不到、版本对不上、或者装到一半报权限错误。

Yarn 是什么?简单说,它是 JavaScript 生态里的一个包管理工具,和 npm 干的是同一件事——帮你下载、管理项目依赖。它最早由几家大厂联合推出,主打速度快、依赖锁定可靠、支持离线缓存。虽然现在 npm 本身也进步了很多,pnpm 也分走了不少用户,但 Yarn 在大量存量项目里依然是标配,尤其是那些用 Yarn Workspaces 做 monorepo 的工程。所以不管你是刚入门前端的新手,还是接手老项目的开发者,在 Mac 上把 Yarn 装好、装对,都是一件绕不开的事。

这篇内容我会从芯片架构差异、安装方式选型、版本管理、常见报错排查几个角度,把这件事彻底讲透。适合三类人看:一是刚买 Mac 准备学前端的同学;二是装了 Yarn 但总出问题的开发者;三是想搞清楚 Yarn 和 npm、pnpm 到底该怎么选的人。我不会只给你一行命令就完事,而是把每一步背后的原因讲清楚,让你装完之后心里有底,出了问题也能自己排查。

先说一个反直觉的结论:在 Mac 上装 Yarn,最不推荐的方式恰恰是很多人最先想到的npm install -g yarn。为什么?往下看。

2. 装之前先搞清楚:你的 Mac 是什么芯片、Node 从哪来

2.1 Apple Silicon 和 Intel 芯片的路径差异

从 2020 年之后,Mac 分成了两条线:老的 Intel 芯片和新的 Apple Silicon(M 系列)芯片。这件事对装 Yarn 的影响,比大多数人以为的要大。

核心差异在于二进制依赖的架构。Yarn 本身是 JavaScript 写的,理论上跨架构没问题,但它依赖的 Node 运行时是分架构的。如果你在 M 系列芯片上装了一个 x86 架构的 Node(比如通过 Rosetta 转译运行的旧版本),那么基于它安装的 Yarn 也可能跑在转译层里,速度慢不说,还容易出现原生模块编译失败的问题。

怎么确认自己的芯片?打开终端,敲:

uname -m
  • 输出arm64:你是 Apple Silicon,走原生 arm64 路线。
  • 输出x86_64:你是 Intel 芯片,或者你的终端正跑在 Rosetta 转译模式下。

这里有个隐藏坑:有些人的终端本身被设置成了 Rosetta 模式,导致uname -m显示x86_64,但机器其实是 M 系列。检查方法是在"访达"里找到终端应用,右键"显示简介",看有没有勾选"使用 Rosetta 打开"。如果有,取消勾选,重启终端再测一次。

为什么要在意这个?因为如果你的 Node 是 x86 版本,装出来的 Yarn 在调用某些原生依赖时会出现架构不匹配的报错,典型症状是mach-o file, but is an incompatible architecture。这个错误我在帮别人排查时遇到过好几次,根源就是架构混用。

2.2 Node 的来源决定了 Yarn 怎么装

Yarn 是跑在 Node 之上的,所以先有 Node,才有 Yarn。而 Node 在 Mac 上的安装方式,直接决定了你该用哪种方式装 Yarn。

常见的 Node 安装方式有三种:

安装方式特点对装 Yarn 的影响
官网 pkg 安装包简单直接,但全局包路径固定,切换版本麻烦用npm -g装 Yarn 会装到系统级路径,可能需要 sudo
Homebrew方便管理,但 Node 版本更新频繁可以用 brew 直接装 Yarn,但版本可能滞后
nvm / fnm 等版本管理器可自由切换 Node 版本,路径隔离干净推荐配合corepack或npm -g,无需 sudo

我的建议很明确:如果你还没装 Node,先装一个版本管理器(nvm 或 fnm),再用它装 Node,最后装 Yarn。这样全局包路径都在你的用户目录下,不需要 sudo,切换 Node 版本时 Yarn 也跟着走,干净利落。

如果你已经用官网 pkg 装了 Node,也别急着卸载,可以先看看当前 Node 版本和路径:

which node node -v npm -v

which node的输出能告诉你 Node 装在哪。如果是/usr/local/bin/node或/opt/homebrew/bin/node,说明是系统级或 brew 级安装;如果是/Users/你的用户名/.nvm/...这种,说明是版本管理器装的。

2.3 一个容易被忽略的前置检查:npm 全局路径权限

不管你最后用哪种方式装 Yarn,都建议先检查一下 npm 的全局路径权限。很多人装 Yarn 时报EACCES: permission denied,根源就在这里。

npm config get prefix

如果输出是/usr/local或/usr,那说明全局包会装到系统目录,普通用户没写权限,就会报权限错误。正确的做法是把 prefix 改到用户目录下:

mkdir -p ~/.npm-global npm config set prefix ~/.npm-global

然后把~/.npm-global/bin加到 PATH 里。在~/.zshrc(Mac 默认 shell 是 zsh)末尾加一行:

export PATH=~/.npm-global/bin:$PATH

执行source ~/.zshrc生效。这一步做完,后面装 Yarn 就不会再被权限问题卡住了。这个操作看起来是额外步骤,但它能帮你避开后面 80% 的报错,非常值得。

3. 四种安装方式实测对比:哪种最适合你

3.1 方式一:corepack(Node 16.10+ 官方推荐)

从 Node 16.10 开始,官方内置了一个叫corepack的工具,专门用来管理 Yarn 和 pnpm 这类包管理器的版本。这是目前最推荐的方式,原因是它把 Yarn 的版本和项目绑定,而不是全局装一个固定版本。

启用方式:

corepack enable

如果提示command not found,说明你的 Node 版本太老,或者 corepack 没被激活。可以先检查:

node -v

Node 16.10 以上才有 corepack。如果版本够但还是找不到,可能是安装 Node 时没带上 corepack,这种情况建议换用版本管理器重装 Node。

启用之后,在项目目录里可以直接指定 Yarn 版本:

corepack prepare yarn@stable --activate

或者更精细地指定:

corepack prepare yarn@4.1.0 --activate

corepack 的好处是每个项目可以用不同的 Yarn 版本,通过项目根目录的packageManager字段自动切换。比如你在package.json里写:

{ "packageManager": "yarn@4.1.0" }

那么进入这个项目时,corepack 会自动使用 4.1.0 版本,完全不用手动切换。这对维护多个老项目的开发者来说,简直是救星。

不过 corepack 也有个坑:它默认可能没在 PATH 里注册 yarn 命令,需要先corepack enable一次。另外某些 Node 版本(尤其是通过某些包管理器装的)可能没带 corepack,这时候就得手动补。

3.2 方式二:npm 全局安装(最传统,但要注意路径)

这是最广为人知的方式:

npm install -g yarn

如果你前面已经把 npm prefix 改到了用户目录,这条命令会顺利执行,Yarn 会装到~/.npm-global/bin/yarn。验证:

yarn -v

能输出版本号就成功了。

但这种方式有两个问题。第一,它装的是 Yarn 1.x(Classic)还是 2.x+(Berry)取决于 npm 源里的 latest 标签,你没法精确控制。第二,全局只有一个版本,切换项目时如果项目要求不同版本,就会冲突。

所以我的看法是:npm 全局安装适合只想快速用一下、不涉及多版本切换的场景。如果你要长期做前端开发,还是 corepack 更靠谱。

3.3 方式三:Homebrew 安装(适合 brew 重度用户)

如果你习惯用 Homebrew 管理一切,那可以:

brew install yarn

Homebrew 会自动处理依赖,把 Yarn 装到/opt/homebrew/bin(Apple Silicon)或/usr/local/bin(Intel)。

但这里有个非常容易踩的坑:brew install yarn有时会顺带装一个 Node 依赖,导致你系统里出现两个 Node——一个是你自己装的,一个是 brew 装的。两个 Node 路径不同,npm 全局包也各管各的,最后yarn命令用的是哪个 Node 都搞不清。

验证方法:

which -a node which -a yarn

如果输出多行,说明有多个版本共存。这时候要么统一用 brew 管理,要么把 brew 装的 Node 卸载掉(brew uninstall node),只保留版本管理器装的。

另外,Homebrew 的 Yarn 版本更新通常比官方慢半拍,如果你需要最新特性,可能等不到。

3.4 方式四:独立脚本安装(不推荐,仅作了解)

Yarn 官方早期提供过一个安装脚本,通过 curl 下载执行。这种方式现在基本被 corepack 取代了,而且脚本安装的版本管理很麻烦,我不建议用。这里提一句只是让你知道有这么回事,遇到老教程提到时能分辨。

3.5 四种方式横向对比

方式优点缺点推荐场景
corepack版本随项目切换,官方推荐,无需 sudo需要 Node 16.10+,初次配置略繁琐长期开发,多项目并存
npm 全局命令简单,人人会版本固定,可能需改 prefix快速试用,单一项目
Homebrew与 brew 生态统一可能引入重复 Node,版本滞后brew 重度用户
独立脚本无需 Node管理混乱,已过时不推荐

看完这张表,结论很清楚:能上 corepack 就上 corepack,实在不行用 npm 全局但记得改 prefix,brew 只在你有明确理由时用。

4. 装完之后必须做的三件验证事

4.1 验证命令可用性和版本

装完第一件事,别急着跑项目,先确认命令真的能用:

yarn -v

如果报command not found,说明 PATH 没配好。回到前面检查~/.zshrc里的 PATH 配置,确认~/.npm-global/bin或 corepack 的 shim 路径在里面。

如果输出了版本号,比如1.22.22或4.1.0,说明命令通了。这里要注意区分Yarn 1.x 和 Yarn 2+,它们的命令行为差异很大。1.x 是经典版,2+ 是所谓的 Berry 版,配置文件、锁文件格式都不一样。

4.2 确认 Yarn 用的是哪个 Node

这一步很多人忽略,但非常关键:

yarn node -v

这条命令会告诉你 Yarn 实际调用的 Node 版本。如果这个版本和你node -v看到的不一致,说明 Yarn 和 Node 来自不同的安装源,后面很可能出问题。

理想情况下,两者应该一致。如果不一致,检查是不是有多个 Node 共存,用which -a node排查。

4.3 检查全局缓存和配置目录

Yarn 会在用户目录下建缓存和配置:

yarn cache dir yarn config list

yarn cache dir告诉你缓存位置,默认在~/Library/Caches/Yarn或类似路径。如果这个目录权限有问题,装包时会失败。yarn config list列出当前所有配置,能帮你确认 registry 等关键项是否正确。

提示:如果你在国内网络环境下遇到下载慢的问题,可以配置镜像源。但具体配置请参考官方文档,我这里不展开,避免给出过时信息。

5. 那些年我踩过的 Yarn 安装坑

5.1 坑一:command not found 的三层排查

yarn: command not found是最常见的报错,但原因可能有三层,得逐层排查。

第一层:PATH 没包含 Yarn 所在目录。用echo $PATH看输出里有没有 Yarn 的安装路径。没有的话,把对应路径加进~/.zshrc。

第二层:shell 配置文件没生效。改完~/.zshrc后必须source ~/.zshrc或者重开终端。有些人改了文件但没生效,以为没配对。

第三层:装到了错误的 shell 配置里。Mac 默认是 zsh,但有些人之前用过 bash,把 PATH 写进了~/.bash_profile。zsh 启动时读的是~/.zshrc,两者不互通。确认你改的是当前 shell 对应的文件,用echo $SHELL看当前 shell。

这三层排查下来,基本能定位所有 command not found 问题。

5.2 坑二:权限报错的根治方法

EACCES: permission denied这个错误,本质是 npm 想往系统目录写文件但没权限。很多人第一反应是加sudo:

sudo npm install -g yarn

千万别这么干。用 sudo 装全局包,会让文件属主变成 root,后续普通用户操作时又会报权限错误,陷入死循环。正确做法是前面说的改 prefix 到用户目录,一劳永逸。

如果已经用 sudo 装过了,得先把属主改回来:

sudo chown -R $(whoami) ~/.npm-global

然后再按正常流程操作。

5.3 坑三:架构不匹配的诡异报错

在 M 系列芯片上,如果你看到类似这样的报错:

mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64')

说明你的 Node 或某个依赖是 x86 架构的,但系统期望 arm64。根源通常是 Node 装错了架构。

解决办法是卸载现有 Node,用版本管理器重装 arm64 版本。用 nvm 的话:

nvm uninstall <版本号> nvm install <版本号>

nvm 会自动根据当前架构下载对应版本。装完再重装 Yarn,问题就解决了。

5.4 坑四:Yarn 1 和 Yarn 2+ 的命令差异

很多人装完发现命令行为和教程对不上,原因是版本不同。Yarn 1.x 和 2+ 有几个关键差异:

操作Yarn 1.xYarn 2+
初始化yarn inityarn init -2或自动
添加依赖yarn add xxxyarn add xxx(类似)
全局安装yarn global add xxx不再支持 global,用yarn dlx
锁文件yarn.lockyarn.lock(格式不同)
配置.yarnrc.yarnrc.yml

最典型的是Yarn 2+ 取消了yarn global add,改用yarn dlx临时执行。如果你照着老教程敲yarn global add,在 2+ 上会报错。搞清楚自己用的是哪个大版本,能省下大量困惑时间。

5.5 坑五:corepack 启用后 yarn 命令反而没了

这个坑比较隐蔽。有些人启用 corepack 后,发现原来的yarn命令不见了。原因是 corepack 接管了 yarn 命令,但需要项目里有packageManager字段才会激活对应版本。在没配置的项目里,可能提示找不到版本。

解决办法是在项目里显式指定:

corepack use yarn@stable

这条命令会写入packageManager字段并激活。之后yarn -v就正常了。

6. Yarn、npm、pnpm 到底该怎么选

6.1 三者的核心差异

装 Yarn 的过程中,很多人会问:现在 npm 这么好用,pnpm 又这么快,我为什么还要用 Yarn?这个问题值得说清楚。

维度npmYarnpnpm
依赖存储扁平化 node_modules扁平化(1.x)/ PnP(2+)硬链接 + 内容寻址
安装速度中等快最快
磁盘占用高高低(共享存储)
锁文件package-lock.jsonyarn.lockpnpm-lock.yaml
monorepo 支持workspacesworkspaces(成熟)workspaces
生态兼容最好好偶有兼容问题

简单说:npm 是默认选项,兼容性最好;Yarn 在 monorepo 和依赖锁定上更成熟;pnpm 在速度和磁盘占用上最优,但个别老包可能不兼容。

6.2 什么情况下必须用 Yarn

有三种情况你基本没得选,必须用 Yarn:

第一,项目里已经有 yarn.lock。锁文件决定了依赖的精确版本,用 npm 或 pnpm 装会生成不同的锁文件,可能导致依赖版本漂移,引发莫名其妙的 bug。

第二,项目用了 Yarn Workspaces 做 monorepo。虽然 npm 和 pnpm 也有 workspaces,但老项目的配置是按 Yarn 写的,换工具要改配置。

第三,团队规范要求。有些团队统一用 Yarn,你跟着用就行,别自作主张。

6.3 我的实际选择建议

就我个人经验,新项目我会优先考虑 pnpm,因为速度和磁盘优势明显。但如果是接手存量项目,项目用什么我就用什么,绝不轻易换包管理器。换包管理器的成本远大于那点速度收益,而且容易引入难以排查的依赖问题。

Yarn 的定位现在有点尴尬,夹在 npm 和 pnpm 之间。但它的 Workspaces 和 PnP(Plug'n'Play)机制依然有独特价值,尤其是 PnP 那种不生成 node_modules 的方案,在大型 monorepo 里能显著提升安装速度。所以学 Yarn 不算过时,只是要清楚它的适用边界。

7. 装好之后,几个提升效率的配置

7.1 配置镜像源加速下载

网络环境不理想时,下载依赖会非常慢。Yarn 支持配置 registry:

yarn config set registry <镜像地址>

具体镜像地址请以官方或可信渠道公布的信息为准,我这里不写死,避免过时。配置后可以用yarn config get registry确认。

7.2 开启全局缓存复用

Yarn 默认就有缓存机制,重复安装同一个包时会从缓存读取。确认缓存开启:

yarn config get enableGlobalCache

如果是true,说明全局缓存已启用。这个机制能大幅减少重复下载,尤其在多个项目共用相同依赖时效果明显。

7.3 用 .yarnrc.yml 做项目级配置

Yarn 2+ 用.yarnrc.yml做项目配置,可以针对单个项目设置 nodeLinker、registry 等。比如强制用 node_modules 模式(而不是 PnP):

nodeLinker: node-modules

这个配置对不熟悉 PnP 的团队很友好,能避免一堆兼容性问题。放在项目根目录,提交到版本库,团队所有人共享。

7.4 定期清理缓存

缓存用久了会占空间,定期清理:

yarn cache clean

这条命令会清空缓存。如果只想看缓存占了多少空间,可以先yarn cache dir找到目录,用du -sh查看大小。我一般几个月清一次,避免磁盘被占满。

8. 关于版本升级和降级的实操

8.1 从 Yarn 1 升级到 Yarn 2+

如果你项目还在用 Yarn 1,想升级到 2+,官方提供了迁移命令:

yarn set version berry

这条命令会下载最新稳定版并写入配置。升级后项目里会多出.yarn目录和.yarnrc.yml,锁文件格式也会变。升级前务必提交代码或备份,因为锁文件变化可能影响依赖解析。

升级后如果遇到兼容问题,可以回退:

yarn set version classic

classic就是 1.x 的代号。

8.2 锁定特定版本避免意外升级

团队协作时,最怕每个人用的 Yarn 版本不一样。解决办法是在package.json里写死:

{ "packageManager": "yarn@4.1.0" }

配合 corepack,任何人进项目都会自动用这个版本,彻底消除版本差异。这个字段是 corepack 识别的关键,强烈建议加上。

8.3 卸载 Yarn 的正确姿势

如果你要换包管理器,得先把 Yarn 卸干净。根据安装方式不同,卸载方法也不同:

  • npm 装的:npm uninstall -g yarn
  • brew 装的:brew uninstall yarn
  • corepack 管理的:corepack disable然后删掉相关配置

卸完记得检查which yarn,确认没有残留。有时候 PATH 里还留着旧路径,需要手动清理~/.zshrc。

9. 写在最后的一点个人体会

折腾了这么多台 Mac、这么多种安装方式,我最大的体会是:装工具这件事,慢就是快。花十分钟把 Node 的来源、PATH 的配置、芯片架构这些前置条件搞清楚,比装完出问题再花两小时排查要划算得多。

我见过太多人一上来就npm install -g yarn,然后被权限、路径、版本问题轮番折磨,最后对前端环境配置产生心理阴影。其实只要按"先版本管理器装 Node,再 corepack 管 Yarn"这个顺序走,整个过程会非常顺。

另外提醒一句,环境配置这东西没有一劳永逸的方案。系统升级、Node 大版本更新、Yarn 从 1 到 4 的演进,都会带来新的变化。保持关注官方文档,遇到报错先看错误信息里的关键词,再针对性搜索,比盲目试错高效得多。

最后分享一个小习惯:我会在~/.zshrc里加一行注释,记录当前 Node 和 Yarn 的安装方式,比如# Node via nvm, Yarn via corepack。过几个月回头看,能立刻想起当初是怎么配的,省去重新排查的麻烦。这个习惯帮我省了不少时间,你也可以试试。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进