跳到主要內容

GitHub Actions 實戰:獨立開發者的 CI/CD 完整設定

你把 code 推上 main,結果忘了跑 lint,type error 直接進了 production。或者你每次部署都手動跑 pnpm build && vercel --prod,某天忘了一步,上線的是壞掉的版本。

CI/CD 不是大公司才需要的東西。對獨立開發者來說,它是防止你在凌晨三點犯蠢的安全網。

GitHub Actions 基本概念

GitHub Actions 是 GitHub 內建的 CI/CD 平台。你在 .github/workflows/ 放 YAML 檔,GitHub 會在指定事件發生時自動執行。

四個核心概念:

  • Workflow — 一個 YAML 檔案,定義整個自動化流程
  • Job — workflow 裡的一組任務,預設平行執行
  • Step — job 裡的單一操作(跑指令或用 action)
  • Runner — 執行 job 的虛擬機(GitHub 提供免費的 Ubuntu/macOS/Windows)

免費額度:public repo 無限制,private repo 每月 2,000 分鐘。對獨立開發者來說綽綽有餘。

Workflow 1:PR 自動檢查

每次開 PR 自動跑 lint、type check 和 test。這是最基本也最重要的 workflow:

# .github/workflows/ci.yml
name: CI

on:
  pull_request:
    branches: [main]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile

      - name: Lint
        run: pnpm lint

      - name: Type Check
        run: pnpm turbo run build --filter='./packages/*'

      - name: Test
        run: pnpm test

幾個重點:

  • --frozen-lockfile — 確保 CI 用的 dependency 跟你本地一模一樣,不會偷偷更新
  • cache: 'pnpm'setup-node 會自動快取 pnpm store,第二次跑不用重新下載所有 package
  • 先 build packages 再 test — 如果你的 test 依賴 packages 的 build output,順序很重要

PR 有任何一步失敗,GitHub 會在 PR 頁面顯示紅叉,阻止合併。

Workflow 2:推 main 自動部署

合併到 main 後自動部署到 Vercel:

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile

      - name: Build
        run: pnpm turbo run build
        env:
          NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
          NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}

      - name: Deploy to Vercel
        run: |
          pnpm add -g vercel
          vercel --prod --token=${{ secrets.VERCEL_TOKEN }}
        env:
          VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
          VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

如果你用 Vercel 的 Git Integration(推 main 自動部署),其實不需要這個 workflow。但如果你想在部署前跑額外的 build 驗證、或部署到多個環境,自己控制部署流程更有彈性。

Workflow 3:每週 dependency audit

每週自動檢查有沒有已知的安全漏洞:

# .github/workflows/audit.yml
name: Security Audit

on:
  schedule:
    - cron: '0 9 * * 1'  # 每週一早上 9 點 (UTC)
  workflow_dispatch:        # 也可以手動觸發

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile

      - name: Audit
        run: pnpm audit --audit-level=high
        continue-on-error: true

      - name: Check outdated
        run: pnpm outdated --recursive || true

schedule 用 cron 語法,時區是 UTC。workflow_dispatch 讓你在 GitHub UI 上手動跑。continue-on-error: true 讓 audit 有問題時不會讓整個 workflow 失敗——你會看到警告,但不會阻塞其他工作。

管理 Secrets

敏感資訊(API key、token、密碼)絕對不能寫在 YAML 裡。用 GitHub Secrets:

  1. 到 repo 的 Settings → Secrets and variables → Actions
  2. 點 New repository secret
  3. 在 workflow 裡用 ${{ secrets.YOUR_SECRET_NAME }} 引用

常見需要設定的 secrets:

VERCEL_TOKEN          # Vercel 部署 token
VERCEL_ORG_ID         # Vercel organization ID
VERCEL_PROJECT_ID     # Vercel project ID
NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY
TURBO_TOKEN           # Turborepo remote cache token
TURBO_TEAM            # Turborepo team name

注意:NEXT_PUBLIC_ 開頭的變數雖然在前端是公開的,但在 CI 環境中仍然建議用 Secrets 管理,避免硬編碼在 repo 裡。

pnpm + Turborepo 快取加速

CI 最大的成本是時間。兩層快取可以大幅加速:

第一層:pnpm store 快取

actions/setup-nodecache: 'pnpm' 已經處理了 pnpm store 的快取。第二次 pnpm install 不需要重新下載 package。

第二層:Turborepo remote cache

- name: Build
  run: pnpm turbo run build
  env:
    TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
    TURBO_TEAM: ${{ secrets.TURBO_TEAM }}

設定 TURBO_TOKENTURBO_TEAM 環境變數後,Turborepo 會自動使用 Vercel 的 remote cache。如果某個 package 的 input 沒有變,build 結果直接從 cache 拉,不用重新編譯。

實際效果:一個 3 app + 5 package 的 monorepo,完整 build 需要 4 分鐘,啟用 remote cache 後只改一個 app 的 build 時間降到 40 秒。

常見錯誤

1. pnpm 版本不一致

CI 的 pnpm 版本和本地不同,lockfile 格式可能不相容。確保 package.json 裡有 packageManager 欄位:

{
  "packageManager": "pnpm@10.28.2"
}

pnpm/action-setup@v4 會自動讀這個欄位安裝對應版本。

2. Node.js 版本不一致

本地用 Node 22,CI 用 Node 20,某些語法不支援。建議在 package.jsonengines

{
  "engines": {
    "node": ">=20"
  }
}

3. 環境變數漏設

Build 時需要的環境變數沒設到 Secrets 裡,拿到 undefined。build 不會報錯但 runtime 會壞。先在本地用 env | grep NEXT 列出所有需要的變數,確認都加到了 Secrets。

4. Workflow 觸發條件太寬

on:
  push:
    branches: [main]
    paths-ignore:
      - '**.md'
      - 'docs/**'

paths-ignore 避免改文件就觸發 build。改 README 不需要跑 CI。

5. Job 跑太久

GitHub Actions 的 job 上限是 6 小時,但你不會想等那麼久。如果 build 超過 10 分鐘,先檢查是不是缺了快取設定,再考慮把 job 拆成平行的 sub-jobs。

Debug 技巧

Workflow 失敗時:

  1. 點進失敗的 step,看完整 log
  2. 在 step 裡加 run: env 印出所有環境變數(不要印 secrets)
  3. workflow_dispatch 手動重跑,不用重新推 commit
  4. 本地用 act(GitHub Actions 的本地模擬器)跑 workflow,省去推 commit 等 CI 的來回

最有效的 debug 方式是讓 workflow 盡量簡單。一個 workflow 做一件事,失敗時一眼就知道問題在哪。


想看完整的 monorepo CI/CD 設定,包括 Turborepo remote cache、preview deployment 和自動化 release?到 Docs 查看我們的 DevOps 實作指南。