你把 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:
- 到 repo 的 Settings → Secrets and variables → Actions
- 點 New repository secret
- 在 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-node 的 cache: '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_TOKEN 和 TURBO_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.json 加 engines:
{
"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 失敗時:
- 點進失敗的 step,看完整 log
- 在 step 裡加
run: env印出所有環境變數(不要印 secrets) - 用
workflow_dispatch手動重跑,不用重新推 commit - 本地用
act(GitHub Actions 的本地模擬器)跑 workflow,省去推 commit 等 CI 的來回
最有效的 debug 方式是讓 workflow 盡量簡單。一個 workflow 做一件事,失敗時一眼就知道問題在哪。
想看完整的 monorepo CI/CD 設定,包括 Turborepo remote cache、preview deployment 和自動化 release?到 Docs 查看我們的 DevOps 實作指南。