CI/CD 集成 #

CI/CD 概述 #

Vercel 内置了 CI/CD 功能,也支持与外部 CI/CD 工具集成:

text
┌─────────────────────────────────────────┐
│        Vercel CI/CD 选项                │
├─────────────────────────────────────────┤
│  内置 CI/CD    →  自动构建部署           │
│  GitHub Actions →  自定义工作流          │
│  GitLab CI     →  GitLab 集成           │
│  其他工具      →  通过 API 集成          │
└─────────────────────────────────────────┘

Vercel 内置 CI/CD #

自动部署流程 #

text
Git Push → Vercel 检测 → 触发构建 → 自动部署
text
┌──────────────────────────────────────────────────────┐
│                                                      │
│  main 分支 push                                      │
│       │                                              │
│       ▼                                              │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐          │
│  │ 触发构建 │ ──▶│ 执行构建 │ ──▶│ 生产部署 │          │
│  └─────────┘    └─────────┘    └─────────┘          │
│                                                      │
│  PR 创建/更新                                        │
│       │                                              │
│       ▼                                              │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐          │
│  │ 触发构建 │ ──▶│ 执行构建 │ ──▶│ 预览部署 │          │
│  └─────────┘    └─────────┘    └─────────┘          │
│                                                      │
└──────────────────────────────────────────────────────┘

配置 Git 集成 #

text
Project Settings → Git
├── Production Branch    # 生产分支
├── Ignored Build Step   # 忽略构建条件
├── Auto Job Cancelation # 自动取消旧构建
└── Skipped Build Steps  # 跳过构建条件

生产分支配置 #

text
┌─────────────────────────────────────────┐
│  Production Branch                      │
├─────────────────────────────────────────┤
│  Branch: [main ▼]                       │
│                                         │
│  当此分支有新提交时,自动部署到生产环境   │
└─────────────────────────────────────────┘

忽略构建 #

忽略特定文件变更:

json
{
  "git": {
    "deploymentEnabled": {
      "exclude": [
        "README.md",
        "docs/**",
        ".vscode/**",
        "LICENSE"
      ]
    }
  }
}

自定义忽略命令:

text
Project Settings → Git → Ignored Build Step
bash
git diff --quiet HEAD^ HEAD ./src/

GitHub Actions 集成 #

创建 Vercel Token #

  1. 访问 vercel.com/account/tokens
  2. 点击 “Create Token”
  3. 设置名称和过期时间
  4. 复制 Token

配置 GitHub Secrets #

text
Repository → Settings → Secrets and variables → Actions

添加以下 Secrets:

Secret 说明
VERCEL_TOKEN Vercel API Token
VERCEL_ORG_ID 团队 ID
VERCEL_PROJECT_ID 项目 ID

获取 ID:

bash
vercel link

查看 .vercel/project.json

json
{
  "orgId": "team_xxx",
  "projectId": "prj_xxx"
}

基础工作流 #

yaml
name: Vercel Deployment

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

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

      - name: Install Vercel CLI
        run: npm install --global vercel@latest

      - name: Pull Vercel Environment Information
        run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}

      - name: Build Project Artifacts
        run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}

      - name: Deploy Project Artifacts to Vercel
        run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}

预览部署工作流 #

yaml
name: Preview Deployment

on:
  pull_request:
    branches: [main]

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

      - name: Install Vercel CLI
        run: npm install --global vercel@latest

      - name: Pull Vercel Environment Information
        run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}

      - name: Build Project Artifacts
        run: vercel build --token=${{ secrets.VERCEL_TOKEN }}

      - name: Deploy Project Artifacts to Vercel
        run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > deployment-url.txt

      - name: Comment PR with Deployment URL
        uses: actions/github-script@v6
        with:
          script: |
            const fs = require('fs');
            const url = fs.readFileSync('deployment-url.txt', 'utf8').trim();
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `🚀 Preview deployed to: ${url}`
            });

完整工作流示例 #

yaml
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
  VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    needs: lint
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run test

  deploy-preview:
    runs-on: ubuntu-latest
    needs: test
    if: github.event_name == 'pull_request'
    steps:
      - uses: actions/checkout@v4
      - run: npm install --global vercel@latest
      - run: vercel pull --yes --environment=preview --token=$VERCEL_TOKEN
      - run: vercel build --token=$VERCEL_TOKEN
      - run: vercel deploy --prebuilt --token=$VERCEL_TOKEN

  deploy-production:
    runs-on: ubuntu-latest
    needs: test
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - run: npm install --global vercel@latest
      - run: vercel pull --yes --environment=production --token=$VERCEL_TOKEN
      - run: vercel build --prod --token=$VERCEL_TOKEN
      - run: vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN

使用官方 Action #

yaml
- name: Deploy to Vercel
  uses: amondnet/vercel-action@v25
  with:
    vercel-token: ${{ secrets.VERCEL_TOKEN }}
    vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
    vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
    vercel-args: '--prod'

GitLab CI 集成 #

配置 GitLab Variables #

text
Settings → CI/CD → Variables
Variable 说明
VERCEL_TOKEN Vercel API Token
VERCEL_ORG_ID 团队 ID
VERCEL_PROJECT_ID 项目 ID

.gitlab-ci.yml #

yaml
stages:
  - test
  - deploy

variables:
  NODE_VERSION: '20'

.test_template:
  image: node:${NODE_VERSION}
  before_script:
    - npm ci
  cache:
    paths:
      - node_modules/

lint:
  extends: .test_template
  stage: test
  script:
    - npm run lint

test:
  extends: .test_template
  stage: test
  script:
    - npm run test

deploy_preview:
  stage: deploy
  image: node:${NODE_VERSION}
  rules:
    - if: $CI_MERGE_REQUEST_IID
  script:
    - npm install --global vercel@latest
    - vercel pull --yes --environment=preview --token=$VERCEL_TOKEN
    - vercel build --token=$VERCEL_TOKEN
    - vercel deploy --prebuilt --token=$VERCEL_TOKEN

deploy_production:
  stage: deploy
  image: node:${NODE_VERSION}
  rules:
    - if: $CI_COMMIT_BRANCH == 'main'
  script:
    - npm install --global vercel@latest
    - vercel pull --yes --environment=production --token=$VERCEL_TOKEN
    - vercel build --prod --token=$VERCEL_TOKEN
    - vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN

Vercel API 集成 #

创建部署 #

bash
curl -X POST "https://api.vercel.com/v13/deployments" \
  -H "Authorization: Bearer $VERCEL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-project",
    "gitSource": {
      "type": "github",
      "repo": "username/repo",
      "ref": "main"
    }
  }'

获取部署状态 #

bash
curl "https://api.vercel.com/v13/deployments/$DEPLOYMENT_ID" \
  -H "Authorization: Bearer $VERCEL_TOKEN"

列出部署 #

bash
curl "https://api.vercel.com/v6/deployments?projectId=$PROJECT_ID" \
  -H "Authorization: Bearer $VERCEL_TOKEN"

部署钩子 #

创建部署钩子 #

text
Project Settings → Git → Deploy Hooks
text
┌─────────────────────────────────────────┐
│  Create Deploy Hook                     │
├─────────────────────────────────────────┤
│  Name: [Deploy from CMS      ]          │
│  Branch: [main ▼]                       │
│                                         │
│  Hook URL:                              │
│  https://api.vercel.com/deploy...       │
│                                         │
│  [Create Hook]                          │
└─────────────────────────────────────────┘

触发部署 #

bash
curl -X POST "https://api.vercel.com/integrations/deploy/$HOOK_ID"

使用场景 #

text
┌─────────────────────────────────────────┐
│        部署钩子使用场景                  │
├─────────────────────────────────────────┤
│  CMS 更新    →  内容更新后自动部署       │
│  定时任务    →  定期重新部署             │
│  外部系统    →  第三方触发部署           │
│  Webhook    →  事件触发部署             │
└─────────────────────────────────────────┘

构建缓存 #

启用构建缓存 #

yaml
- name: Cache node modules
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

Vercel 缓存 #

Vercel 自动缓存以下内容:

  • node_modules
  • .next/cache
  • 构建输出

部署通知 #

Slack 通知 #

yaml
- name: Notify Slack
  if: always()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    fields: repo,message,commit,author
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

部署状态徽章 #

markdown
[![Deploy](https://vercel.com/button)](https://vercel.com)

最佳实践 #

分支策略 #

text
┌─────────────────────────────────────────┐
│        推荐分支策略                      │
├─────────────────────────────────────────┤
│  main       →  生产环境                 │
│  develop    →  预览环境                 │
│  feature/*  →  PR 预览                  │
│  hotfix/*   →  紧急修复                 │
└─────────────────────────────────────────┘

环境隔离 #

yaml
deploy-staging:
  environment: staging
  steps:
    - run: vercel deploy --env STAGE=staging

deploy-production:
  environment: production
  steps:
    - run: vercel deploy --prod

回滚机制 #

yaml
rollback:
  runs-on: ubuntu-latest
  steps:
    - name: Rollback to previous deployment
      run: |
        vercel rollback ${{ inputs.deployment-url }} --token=$VERCEL_TOKEN

下一步 #

掌握 CI/CD 集成后,接下来学习 域名绑定 配置自定义域名!

最后更新:2026-03-28