GitHub Action中NPM缓存配置失效问题求助
我来帮你拆解下问题所在,以及对应的修复方案:
核心问题分析
你的脚本里存在几个关键问题,导致缓存没有正常工作:
1. 重复的缓存配置冲突
你同时启用了 actions/setup-node 的内置缓存(cache: npm)和两个手动的 actions/cache 步骤。这两种缓存机制的逻辑会互相干扰,导致缓存无法正确命中或恢复。
2. 路径不匹配(Option 1 的问题)
你的缓存路径设置为 app/node_modules,但如果你的 npm install 命令是在项目根目录执行的,那么 node_modules 会被生成在根目录,而不是 app 文件夹下。缓存的路径和实际生成的路径不一致,自然无法复用缓存。
3. 全局缓存的局限性(Option 2 的问题)
缓存 ~/.npm 是针对 npm 的全局缓存目录,它能减少包的下载时间,但并不能直接复用本地的 node_modules 文件夹。即使全局缓存命中,npm 仍然需要把包从全局缓存复制到本地项目的 node_modules,这一步仍然会消耗时间,而且如果 hashFiles('**/package-lock.json') 匹配到多个 package-lock.json 文件(比如根目录和 app 目录各有一个),会导致缓存 key 频繁变化,缓存无法持久。
4. npm install 的行为特性
默认的 npm install 会检查本地依赖和 package-lock.json 的一致性,如果发现差异就会重新下载或更新依赖。相比之下,npm ci 会严格按照 package-lock.json 安装依赖,不会修改锁文件,更适合 CI 环境,缓存命中时能更快跳过安装步骤。
修复方案
你可以选择以下两种方案中的一种,不要同时混用:
方案一:使用 actions/setup-node 内置缓存(最简单)
actions/setup-node 的 cache: npm 选项已经帮你处理了大部分缓存逻辑,无需手动配置 actions/cache:
name: unit on: push: branches: ['*'] pull_request: branches: ['*'] workflow_dispatch: jobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v2 with: node-version: '15' cache: npm # 内置缓存自动处理依赖缓存 - name: Install dependencies run: cd app && npm ci # 切换到app目录执行安装,用npm ci替代npm install - name: Run unit tests run: cd app && npm run test
方案二:手动缓存本地 node_modules
如果你需要更精细的控制,可以手动配置 actions/cache,但要确保路径和命令匹配:
name: unit on: push: branches: ['*'] pull_request: branches: ['*'] workflow_dispatch: jobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v2 with: node-version: '15' # 移除内置缓存选项,避免冲突 - name: Cache app node_modules uses: actions/cache@v2 with: path: app/node_modules key: ${{ runner.os }}-node-${{ hashFiles('app/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - name: Install dependencies run: cd app && npm ci # 在app目录执行npm ci,确保依赖安装到正确路径 - name: Run unit tests run: cd app && npm run test
验证缓存是否生效
运行工作流后,你可以在 GitHub Actions 的日志中查看缓存步骤的输出:
- 如果看到
Cache restored successfully,说明缓存命中; - 如果看到
Cache saved successfully,说明本次运行生成了新的缓存。
内容的提问来源于stack exchange,提问作者Raffaele




