在 GitHub Actions 中缓存 node_modules

24

我有一个Yarn单体库(工作区),其中包含2个包:后端(Node.js/TypeScript)和前端(React/Typescript)。

/package.json(已削减)

{
  "workspaces": [
    "backend",
    "frontend"
  ],
}

我正在尝试使用GitHub Actions添加持续集成,并尝试使用actions/cache @ v2来缓存Yarn缓存目录和所有项目的node_modules目录。

.github/workflows/CI.yml(已修剪)

    steps:
      - uses: actions/checkout@v2

      - name: Get yarn cache directory path
        id: yarn-cache-dir-path
        run: |
          echo "::set-output name=dir::$(yarn cache dir)"
          echo "::set-output name=version::$(yarn -v)"

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}

      - uses: actions/cache@v2
        with:
          path: |
            ${{ steps.yarn-cache-dir-path.outputs.dir }}
            '**/node_modules'
            '**/.eslintcache'
          key: ${{ runner.os }}-yarn-${{ steps.yarn-cache-dir-path.outputs.version }}-${{ hashFiles('**/yarn.lock') }}

      - name: Install packages
        run: yarn install --frozen-lockfile

我知道缓存会被存储并在后续运行中重新使用:

key: Linux-yarn-1.22.10-143fef95c7228810cf502305eff3be1cbc468dc8a3e0b153a4311c0250aaef6f
Received 158645465 of 175422681 (90.4%), 151.3 MBs/sec
Received 175422681 of 175422681 (100.0%), 138.1 MBs/sec
Cache Size: ~167 MB (175422681 B)
/usr/bin/tar --use-compress-program zstd -d -xf /home/runner/work/_temp/08363700-9a23-447e-a80e-6f3dbec6068f/cache.tzst -P -C /home/runner/work/path
Cache restored successfully
Cache restored from key: Linux-yarn-1.22.10-143fef95c7228810cf502305eff3be1cbc468dc8a3e0b153a4311c0250aaef6f

但是yarn仍然会尝试解决依赖关系:

yarn install --frozen-lockfile
shell: /usr/bin/bash -e {0}
yarn install v1.22.10
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@2.3.2: The platform "linux" is incompatible with this module.
info "fsevents@2.3.2" is an optional dependency and failed compatibility check. Excluding it from installation.
info fsevents@2.3.1: The platform "linux" is incompatible with this module.
info "fsevents@2.3.1" is an optional dependency and failed compatibility check. Excluding it from installation.
info fsevents@1.2.13: The platform "linux" is incompatible with this module.
info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
.....
[4/4] Building fresh packages...
Done in 40.07s.

我的期望是它能够像在我的本地机器上一样工作:

$ yarn --frozen-lockfile
yarn install v1.22.10
[1/4]   Resolving packages...
success Already up-to-date.
✨  Done in 0.72s.

我能否在配置上做些改进以满足预期结果,或这是 GitHub Actions 预期的行为?


更新:尝试使用以下路径时:

          path: |
            '**/node_modules'
            '**/.eslintcache'
或:
          path: |
            'node_modules'
            '*/node_modules'
            '**/.eslintcache'

缓存大小为22字节。可能不匹配任何node_modules目录。


@jonrsharpe 感谢你的改进,但是对于文件名,我已经按照这篇帖子进行了格式化。 - Teneff
1
那不是指导,只是格式沙盒中的随机帖子。如果我们应该遵循那些东西,一切可能看起来像https://meta.stackexchange.com/a/329360/248731! - jonrsharpe
4个回答

23

经过多次尝试和错误,从 path移除引号似乎已经解决了问题。缓存的大小也增加了近两倍。

  - uses: actions/cache@v2
    id: yarn-cache
    with:
      path: |
        **/node_modules
        **/.eslintcache
        ${{ steps.yarn-cache-dir-path.outputs.dir }}

      key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
      restore-keys: |
        ${{ runner.os }}-yarn-

运行 actions/cache@v2

Received 213909504 of 305669200 (70.0%), 203.6 MBs/sec
Received 305669200 of 305669200 (100.0%), 185.6 MBs/sec
Cache Size: ~292 MB (305669200 B)
/usr/bin/tar --use-compress-program zstd -d -xf /home/runner/work/_temp/2e2d2a1d-04d7-44c3-829e-ec4e8faf394b/cache.tzst -P -C /home/runner/work/path
Cache restored successfully
Cache restored from key: Linux-yarn-143fef95c7228810cf502305eff3be1cbc468dc8a3e0b153a4311c0250aaef6f

运行 yarn install --frozen-lockfile

yarn install v1.22.10
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.96s.

你不应该缓存 node_modules,而是使用 yarn 缓存目录。 - Emre
7
我的目标是快速运行构建。如果你能在回答中描述缓存 node_modules 的缺点并比较构建速度,我会接受它。 - Teneff
2
你说得对,似乎没有更好的方法。 - Emre
3
这个帖子里有三个人说缓存 node_modules 不是一个好的建议,但没有解释为什么。现在我开始怀疑了。有人能否解释一下是否存在问题或风险? - EgonBolton
1
一些解释为什么应该避免缓存node_modules解决方案3:使用actions/cache缓存node_modules(不推荐)GitHub Cache Action - Sascha

4

对于其他寻找在GHA中实现yarn缓存的人,以下代码对我来说效果最好:

      - name: Get yarn cache directory path
        id: yarn-cache-dir-path
        run: echo "::set-output name=dir::$(yarn cache dir)" 

      - uses: actions/cache@v2
        id: yarn-cache
        with:
          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-

      - name: Install dependencies
        run: yarn --prefer-offline
        if: steps.yarn-cache.outputs.cache-hit != 'true'


最佳实践是不要缓存node_modules

缓存node_modules来确定要安装的软件包可能会导致不正确的缓存破坏。


为什么不将node_modules缓存是最佳实践? - Paul Razvan Berg
你的问题的答案在@PaulRazvanBerg的帖子中已经明确包含了。 - TillyJonesy
抱歉,我错过了最后一句话! - Paul Razvan Berg

3
对于任何需要仅缓存node_modules的人来说,这是一个最简单的eslint检查示例。如果不需要它,请删除最新的eslint步骤。
name: Lint check
on:
  pull_request:
    branches:
      - dev
jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v3

    - name: Setup node
      uses: actions/setup-node@v3
      with:
        node-version: '16'

    - name: Cache node modules
      uses: actions/cache@v3
      with:
        path: node_modules
        key: node_modules-${{hashFiles('yarn.lock')}}
        restore-keys: node_modules- # Take any latest cache if failed to find it for current yarn.lock

    - name: Install dependencies
      run: yarn

    - name: Run eslint on changed files
      uses: tj-actions/eslint-changed-files@v18

请记住,actions/cache@v3会为每个分支单独保留缓存,只有主分支才能在其他分支之间共享其缓存。因此,对于每个新分支,第一次运行不会命中缓存。为了解决这个问题,我可以提供一个稍微复杂一些的工作流程,从主分支重用缓存。

当您的应用程序依赖项发生更改时,您如何更新缓存的node_modules? - Nick M
1
@NickM 在恢复缓存后,我运行了 yarn 命令,它会更新 node_modules 文件夹,并在 cache@v3 步骤之后进行缓存。但是我会更新我的答案,使其更加智能一些。 - Alexander Danilov
谢谢亚历山大。根据你的建议,我成功地使用应用程序资源完成了这个任务,接下来将尝试使用node_modules。 - Nick M

1

你不应该缓存 node_modules 文件夹!
setup-node GitHub 动作自带 内置缓存功能。 按照文档所述,只需将 cache 属性添加到 GitHub 动作中,其中定义了你的软件包管理器 npm | yarn | pnpm

steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
  with:
    node-version: 16
    cache: 'npm' # or 'yarn' | 'pnpm'
- run: npm ci
- run: npm test

2
setup-node 缓存仅适用于 ~/.npm。即使缓存了该文件,npm ci 也可能需要2分钟以上才能恢复相同的锁定结果。使用基于 package-lock.json 的缓存密钥跳过这2分钟是明智的选择,可以节省大量时间(30秒 vs 2分钟)示例:https://www.jonathan-wilkinson.com/github-actions-cache-everything - huntharo
10
我认为你应该进一步解释“不应该缓存node_modules!”的原因,以便清楚为什么这是一个不好的主意。 - Dancrumb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接