Files
xgj/npm-install

npm 依赖安装与缓存 Action

这个 GitHub Action 自动处理 npm 依赖的缓存和安装支持多种包管理器npm、pnpm、yarn可以大幅提升 CI/CD 流水线的执行速度。

特性

  • 🚀 智能缓存: 自动缓存 node_modules避免重复安装
  • 📦 多包管理器支持: 支持 npm、pnpm、yarn自动检测标准锁文件
  • 🎯 灵活配置: 可自定义缓存前缀、安装命令等
  • 🔑 精确 hash 控制: 支持自定义缓存 hash确保依赖变化时缓存失效
  • 🔄 Git 集成: 可选的 git stash 功能
  • 📊 详细输出: 提供缓存命中状态和使用的缓存 key
  • 🧰 自动安装 pnpm: 当选择 package-manager: pnpm 时,自动通过 pnpm/action-setup@v4 确保 pnpm 可用(可指定版本)
  • 🗜️ 缓存 pnpm 二进制: 在安装前缓存 Corepack 的 pnpm 二进制目录,避免重复下载 pnpm 本体(对封闭/慢网环境更友好)

📋 输入参数

参数名 描述 是否必需 默认值
package-manager 包管理器类型 (npm/pnpm/yarn) npm
pnpm-version pnpm 版本(package-manager: pnpm 时生效) 9
cache-mode 缓存模式(node_modulesstore node_modules
cache-prefix 缓存前缀名称 modules
node-modules-path node_modules 目录路径 node_modules
force-install 是否强制安装 false
enable-git-stash 安装后是否执行 git stash false
install-command 自定义安装命令(覆盖默认) ''
install-args 附加到默认安装命令的参数(当未提供 install-command 时生效) ''
cache-hash 缓存 hash 值(推荐使用 自动计算

📤 输出参数

参数名 描述
cache-hit 是否命中缓存 (true/false)
cache-key 使用的缓存 key
cache-path 缓存路径(用于调试与复用)

💡 重要提示

强烈推荐使用 cache-hash 参数!

使用 cache-hash 参数有以下优势:

  • 精确控制: 让你完全控制缓存失效的条件
  • 环境兼容: 避免在不同容器环境中 hash 计算不一致的问题
  • 灵活组合: 可以组合多个文件的 hashpackage.json + package-lock.json + .nvmrc
  • 调试友好: 在 workflow 中可以清楚看到使用的 hash 值
# 推荐用法
with:
  cache-hash: ${{ hashFiles('package-lock.json') }}

如果不提供 cache-hashaction 会自动使用 package.json 作为 fallback但不如手动指定精确。

🚀 使用方法

基础用法 (npm)

- name: 安装npm依赖
  uses: actions/xgj/npm-install@v1

使用 pnpm

- name: 安装pnpm依赖
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: "pnpm"
    # 可选:指定 pnpm 版本(默认 9
    pnpm-version: "9"
    # 可选:切换为包管理器 store 缓存,提升复用率(首次仍需安装链接)
    # cache-mode: "store"
    # 可选:附加安装参数(当未设置 install-command 时生效)
    # 例如:保持锁文件严格、忽略可选依赖
    install-args: "--frozen-lockfile --no-optional"

强制安装 + Git Stash

- name: 强制安装依赖并stash
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: "npm"
    force-install: "true"
    enable-git-stash: "true"

自定义缓存配置

- name: 自定义缓存安装
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: "yarn"
    cache-prefix: "my-project"
    node-modules-path: "./frontend/node_modules"

自定义安装命令

- name: 使用自定义命令安装
  uses: actions/xgj/npm-install@v1
  with:
    install-command: "npm ci --only=production"

仅附加参数(不覆盖命令)

# npm 示例:追加只生产依赖
- name: 安装npm仅生产依赖
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: npm
    install-args: "--only=production"

# pnpm 示例:严格锁文件 + 忽略可选依赖
- name: 安装pnpm严格锁文件
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: pnpm
    install-args: "--frozen-lockfile --no-optional"

# yarn 示例:纯安装(禁用脚本)
- name: 安装yarn禁用脚本
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: yarn
    install-args: "--ignore-scripts"

使用自定义缓存 hash推荐用法

# 推荐手动指定缓存hash确保精确的缓存管理
- name: 安装npm依赖
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: "npm"
    cache-hash: ${{ hashFiles('package-lock.json') }}

# pnpm项目
- name: 安装pnpm依赖
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: "pnpm"
    cache-hash: ${{ hashFiles('pnpm-lock.yaml') }}

# 多文件hash组合
- name: 安装依赖多文件hash
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: "npm"
    cache-hash: ${{ hashFiles('package.json', 'package-lock.json', '.nvmrc') }}

检查缓存状态

- name: 安装依赖
  id: install-deps
  uses: actions/xgj/npm-install@v1
  with:
    package-manager: "pnpm"

- name: 根据缓存状态执行操作
  if: steps.install-deps.outputs.cache-hit != 'true'
  run: |
    echo "依赖已重新安装,执行额外步骤"
    npm run build:fresh

📝 完整工作流示例

name: CI Pipeline

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: 检出代码
        uses: actions/checkout@v4

      - name: 设置Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "18"

      - name: 安装依赖
        id: deps
        uses: actions/xgj/npm-install@v1
        with:
          package-manager: "pnpm"
          force-install: "false"

      - name: 运行测试
        run: pnpm test

      - name: 构建项目
        if: steps.deps.outputs.cache-hit != 'true'
        run: pnpm build

🔧 工作原理

  1. 缓存 Key 生成: 根据包管理器类型和 lock 文件生成唯一的缓存 key
  2. 缓存检查: 使用actions/cache@v4检查是否存在匹配的缓存
  3. 自动安装 pnpm如需: 当 package-manager=pnpm 时,使用 pnpm/action-setup@v4 确保 pnpm 已安装
    • 在此之前,本 Action 会使用 actions/cache@v4 缓存 Corepack 的 pnpm 二进制目录,命中后无需再次从外网拉取 pnpm 本体
  4. 缓存路径确定:
    • cache-mode=node_modules 时,缓存 node_modules(可用 node-modules-path 定义目录)。
    • cache-mode=store 时,缓存包管理器的全局存储:npm~/.npmpnpm → 通过 pnpm store path 动态获取,yarn~/.cache/yarn
  5. 条件安装: 仅在缓存未命中时执行依赖安装
  6. 可选操作: 根据配置执行 git stash 等额外操作

说明:缓存 key 中包含 OS、包管理器以及 pnpm 的版本)、缓存模式与自定义前缀,避免跨包管理器/模式的缓存误用。

🎯 最佳实践

1. 选择合适的包管理器

# 推荐:根据项目实际使用的包管理器
- uses: actions/xgj/npm-install@v1
  with:
    package-manager: "pnpm" # 如果项目使用pnpm

### 1.1 选择合适的缓存模式

```yaml
# 追求最快的安装且目录较稳定:缓存 node_modules默认
- uses: actions/xgj/npm-install@v1
  with:
    package-manager: pnpm
    cache-mode: node_modules

# 追求更高的通用性和复用率:缓存包管理器 store首次仍需 install 链接)
- uses: actions/xgj/npm-install@v1
  with:
    package-manager: pnpm
    cache-mode: store

2. 合理使用强制安装

# 仅在必要时使用强制安装
- uses: actions/xgj/npm-install@v1
  with:
    force-install: "true" # 仅用于解决依赖冲突

3. 自定义缓存前缀避免冲突

# 为不同项目使用不同的缓存前缀
- uses: actions/xgj/npm-install@v1
  with:
    cache-prefix: "frontend-app"

4. 利用输出参数优化流程

- name: 安装依赖
  id: install
  uses: actions/xgj/npm-install@v1

# 仅在重新安装依赖时执行某些步骤
- name: 重建缓存
  if: steps.install.outputs.cache-hit != 'true'
  run: npm run build:cache

# 调试:打印缓存路径(可用于后续步骤复用路径)
- name: 打印缓存路径
  run: echo "Cache path is: ${{ steps.install.outputs.cache-path }}"

🚨 注意事项

  1. Git Stash: 启用enable-git-stash会在安装后执行git stash,请确保这符合你的工作流需求
  2. 缓存大小: node_modules 可能很大,请关注 GitHub Actions 的缓存限制
  3. Lock 文件: 确保 lock 文件已提交到仓库,这是缓存 key 生成的基础
  4. 权限: 某些自定义安装命令可能需要额外的权限
  5. 跨包管理器缓存隔离: 缓存 key 与 restore-keys 均包含包管理器、版本pnpm与模式切换包管理器/模式时会触发一次干净安装,避免污染

🛡️ 封闭网络/慢网优化

在网络较差或对外网络受限的环境中,建议:

  • 本 Action 已默认缓存 pnpm 二进制Corepack 缓存目录),首次成功后后续运行将跳过 pnpm 下载。
    • 缓存路径(按 OS 区分Action 会全部尝试):
      • Linux: ~/.cache/corepack
      • macOS: ~/Library/Caches/CorePack~/Library/Caches/Corepack
      • Windows: C:\Users\runneradmin\AppData\Local\Corepack\cache
    • 缓存 key${{ runner.os }}-corepack-pnpm-${{ inputs.pnpm-version }}
  • 将 registry 指向内网镜像或近源镜像,并(如需)配置 NODE_AUTH_TOKEN
  • 适当降低并发、调大超时与重试,例如设置:pnpm config set network-concurrency 1 与对应的 npm config set network-timeout ... 等。
  • 使用 cache-mode: store 并确保 pnpm store path 被缓存Action 默认已处理)。首次成功安装后,后续基本本地链接即可。

🔍 故障排除

缓存未命中

如果缓存总是未命中,检查:

  • lock 文件是否存在且已提交
  • package.json 或 lock 文件是否有变更
  • 缓存前缀是否与之前一致
  • 是否切换了包管理器或 cache-mode(切换会生成不同的 key 与前缀)

pnpm store 路径

cache-mode=storepackage-manager=pnpm 时,本 Action 会通过 pnpm store path 动态解析缓存目录;若命令不可用,则回退到 ~/.pnpm-store

安装失败

如果安装失败,尝试:

  • 启用force-install
  • 使用自定义安装命令
  • 检查 Node.js 版本兼容性

Git Stash 问题

如果 git stash 出现问题:

  • 确保工作目录有可 stash 的变更
  • 考虑禁用enable-git-stash
  • 在 action 之前确保 git 配置正确