setup-node 缓存命中,Yarn install 为什么还在执行
区分Yarn包缓存与项目依赖安装,核对锁文件路径、安装目录和cache-hit的实际含义。
Actions 日志已经显示 Cache restored from key,下一步 yarn install 仍然出现 Fetching packages 和 Linking dependencies。对于 Yarn Classic 1.x,这通常不矛盾:setup-node 恢复的是包管理器缓存,项目的依赖安装还需要执行。
这一路径在 setup-node v2、Yarn 1.22.15 的环境中就出现过。正式版 setup-node 7.1.0 仍明确不缓存 node_modules。不能只凭安装阶段的名称,就认定所有依赖又从网络下载了一遍。
命中的缓存放在哪里
Yarn 1.x 的缓存路径由 yarn cache dir 返回;Yarn Berry 使用 yarn config get cacheFolder,两者的缓存方式和配置不同。先确认工作流实际使用的 Yarn,再在安装步骤同一工作目录查看:
yarn --version
yarn cache dir
第二条针对 Yarn Classic。它显示的包缓存目录与项目里的 node_modules 不是同一个目录。恢复前者后,安装器仍要解析锁文件、从缓存取得所需包、建立项目依赖布局,并按项目配置处理安装脚本。
因此,“缓存已恢复”和“安装尚未完成”可以同时成立。要判断是否复用了下载内容,应结合实际缓存路径和安装日志;安装耗时还包含链接、脚本等工作,不能直接换算成网络下载量。
安装步骤照常保留
下面是已经完成 checkout、已按项目要求提供 Yarn Classic 的工作流片段。Node 版本继续由仓库的 .nvmrc 指定,示例的前端子项目位于 apps/web:
- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: yarn
cache-dependency-path: apps/web/yarn.lock
- name: Install web dependencies
working-directory: apps/web
run: yarn install --frozen-lockfile
示例使用 setup-node v7,自托管 runner 需要满足 v2.327.1 及以上的运行要求;.nvmrc 指定的是项目 Node 版本,不会替代 action 自身的 Node 24 运行时。
.nvmrc、子项目路径和 Yarn 的提供方式都要与实际仓库一致。缓存选项不会代替项目对包管理器版本的安排,示例也不是给 Yarn Berry 使用的完整安装配置。
不要给安装步骤加上“cache-hit 为 true 就跳过”的条件。新 runner 恢复包缓存后,并不因此拥有完整的项目依赖目录;跳过安装,后续构建可能缺少模块或可执行文件。
锁文件位置也要与安装目录一致
setup-node 根据依赖锁文件计算缓存键。锁文件在子目录,却默认从仓库根目录寻找,可能得到找不到锁文件的错误,也可能使用了根目录另一个项目的锁文件。
monorepo 应明确 cache-dependency-path,并核对安装步骤的 working-directory。有多个锁文件时,按项目依赖关系配置对应路径;不要为了提高命中率改成永远不变的缓存键。
还要区分不同 action 的输出含义。setup-node 7.1.0 的 cache-hit 根据是否恢复到缓存生成;某些 Yarn Berry 场景还允许前缀恢复,不能把它一概当成 actions/cache 的“精确主键匹配”。
安装发生在 Docker 构建步骤里时,还要另外检查短期令牌作为 ARG 导致安装层失去缓存。setup-node 的包缓存不会自动变成 Docker 构建缓存,两段日志应分别判断。
复查时保留原工作流,对照同一锁文件的后续运行:缓存目录是否恢复、安装是否正常完成、构建是否使用了预期依赖。需要衡量收益,就比较各阶段记录;只看到 Fetching packages 不足以判断缓存失效,也没有理由据此删掉安装步骤。


