跳到主要内容

构建缓存与产物管理

1. 概念

CI 构建最耗时的两步:装依赖(npm install)和编译(build)。缓存这两步的中间产物能让 CI 从 10 分钟降到 2 分钟。

2. npm 缓存

2.1 GitHub Actions

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm # 自动缓存 ~/.npm

底层等价于:

- uses: actions/cache@v4
with:
path: ~/.npm
key: $}} runner.os }}-npm-$}} hashFiles('**/package-lock.json') }}
restore-keys: $}} runner.os }}-npm-

2.2 pnpm 缓存

- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm

2.3 GitLab CI

cache:
key:
files: [package-lock.json]
paths:
- .npm/

install:
script:
- npm ci --cache .npm --prefer-offline

3. Docker 层缓存

3.1 GitHub Actions + Buildx

- uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max

type=gha:用 GitHub Actions 内置 cache(10GB 上限)。

3.2 Registry 缓存

cache-from: type=registry,ref=ghcr.io/myorg/myapp:cache
cache-to: type=registry,ref=ghcr.io/myorg/myapp:cache,mode=max

跨 runner 共享。

3.3 Dockerfile 缓存优化

# package.json 单独 COPY → npm ci 层可缓存
COPY package*.json ./
RUN npm ci
# 代码变了只重新 COPY + build,不重装依赖
COPY . .
RUN npm run build

3.4 BuildKit cache mount

RUN --mount=type=cache,target=/root/.npm \
npm ci

不进镜像但本地复用。

4. Monorepo 缓存(Turborepo / Nx)

4.1 Turborepo Remote Cache

// turbo.json
{
"remoteCache": { "enabled": true }
}
npx turbo login
npx turbo link
npx turbo run build # 命中远程缓存秒出

4.2 Nx

npx nx build frontend --skip-nx-cache=false

Nx Cloud 提供分布式缓存 + 任务分发。

4.3 CI 本地缓存

- uses: actions/cache@v4
with:
path: .turbo
key: turbo-$}} github.sha }}
restore-keys: turbo-

5. 产物管理

5.1 Artifact 上传

- uses: actions/upload-artifact@v4
with:
name: dist-$}} github.sha }}
path: dist/
retention-days: 7

5.2 跨 job 传递

jobs:
build:
steps:
- run: npm run build
- uses: actions/upload-artifact@v4
with: { name: dist, path: dist/ }

deploy:
needs: build
steps:
- uses: actions/download-artifact@v4
with: { name: dist, path: dist/ }
- run: deploy ./dist

5.3 产物归档到对象存储

# 版本化归档
aws s3 cp dist/ s3://builds/frontend/v1.2.3/ --recursive
ossutil sync dist/ oss://builds/frontend/v1.2.3/

保留 N 个版本,回滚时直接部署旧产物。

6. 构建速度优化

手段效果
npm ci(代替 install)快 30-50%
缓存 node_modules / .npm省 1-3 分钟
Docker 层缓存省镜像构建 2-5 分钟
Turborepo / Nx 缓存Monorepo 省 60-90%
并行 job总时间 = 最慢而非总和
swc / esbuild 替代 babel/tsc编译快 10-50 倍
只构建变更包(affected)Monorepo 省大量

7. 版本与标记

# 语义化版本
npm version patch/minor/major

# CI 自动标记
git tag "v$(node -p 'require("./package.json").version')"
git push --tags

产物命名包含 git sha:frontend-abc1234.tar.gz

8. 常见反模式

  • 不缓存 npm:每次 CI 装 3 分钟
  • 缓存 node_modules 目录:跨平台不安全,应该缓存 .npm(cache store)
  • artifact 不设过期:磁盘占满
  • 不区分 build / deploy:代码没变也重新 build
  • Monorepo 全量 build:应该只 build affected
  • 产物不版本化:无法回滚到特定版本
  • 缓存 key 不含 lockfile hash:依赖变了还用老缓存

9. 延伸阅读