Nuxt: CI/CD
最后更新:2026-08-26
Bob 每次手动部署都出错——忘记跑迁移、环境变量配错、代码没过测试就上线。Charlie 需要自动化 CI/CD:代码推送自动测试、PR 自动预览、main 自动部署生产,零人工干预。
1. 你将学到
- GitHub Actions 工作流:lint → test → build → deploy
- 代码质量门禁:ESLint + Prettier + TypeCheck + Vitest 覆盖率
- 环境管理:development → staging → production
- 部署策略:蓝绿部署 + 滚动更新 + 回滚
- MegaShop PR 自动预览 + main 自动部署
2. 一个管理员的真实故事
(1) 痛点:手动部署频繁出错
Bob 手动部署 MegaShop,步骤:1) 拉代码 2) npm install 3) 跑测试(忘了)4) 构建 5) 上传 6) 跑迁移(忘了)7) 重启服务。漏一步就出问题,平均每月 2 次部署事故。
(2) GitHub Actions CI/CD 的解法
每次 push 自动执行完整流程:
YAML
# .github/workflows/deploy.yml
on: push
jobs:
test: → lint + typecheck + vitest
build: → npm run build
deploy: → docker compose up -d
(3) 收益:零人工 + 零事故
代码推送后全自动测试/构建/部署,PR 自动生成预览环境,main 合并自动上线,部署事故降到零。
3. GitHub Actions 工作流
(1) CI/CD 流水线阶段
flowchart LR
A[Push / PR] --> B[Lint + TypeCheck]
B --> C[Unit Tests]
C --> D[Build]
D --> E{Branch?}
E -->|PR| F[Preview Deploy]
E -->|main| G[Staging Deploy]
G --> H[Smoke Test]
H --> I[Production Deploy]
I --> J[Health Check]
J --> K[Done ✅]
▶ 示例:完整的 CI 工作流
YAML
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
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
- run: npx nuxi typecheck
test:
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: megashop_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
DATABASE_URL: postgresql://test:test@localhost:5432/megashop_test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx prisma migrate deploy
- run: npm run test:coverage
- name: Upload coverage
uses: codecov/codecov-action@v4
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx prisma generate
- run: npm run build
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: nuxt-build
path: .output/
输出:
TEXT
📖 仅展示
CI/CD pipeline loaded
Pipeline status: passed
Tests: 12 passed, 0 failed
4. 代码质量门禁
(1) 质量门禁配置
▶ 示例:ESLint + Prettier 配置
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/eslint'],
eslint: {
config: {
stylistic: {
indent: 2,
quotes: 'single',
semi: false
}
}
}
})
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:package.json 脚本
JSON
{
"scripts": {
"dev": "nuxi dev",
"build": "nuxi build",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"typecheck": "nuxi typecheck",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"validate": "npm run lint && npm run typecheck && npm run test"
}
}
输出:
JSON
{
"scripts": {
"dev": "nuxi dev",
"build": "nuxi build",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"typecheck": "nuxi typecheck",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"validate": "npm run lint && npm run typecheck && npm run test"
}
}
(2) 质量门禁指标
| 指标 | 工具 | 门禁阈值 | 说明 |
|---|---|---|---|
| 代码风格 | ESLint | 0 errors | 统一代码风格 |
| 格式化 | Prettier | 0 warnings | 自动格式化 |
| 类型检查 | vue-tsc | 0 errors | TypeScript 类型安全 |
| 单元测试 | Vitest | ≥ 80% coverage | 核心逻辑覆盖 |
| E2E 测试 | Playwright | 全部通过 | 关键流程验证 |
| Bundle 大小 | rollup-plugin | < 200KB gzip | 防止体积膨胀 |
5. 多环境管理
▶ 示例:环境配置文件
TEXT
📖 仅展示
# .env.development
DATABASE_URL=postgresql://dev:dev@localhost:5432/megashop_dev
REDIS_URL=redis://localhost:6379
JWT_ACCESS_SECRET=dev-access-secret
# .env.staging
DATABASE_URL=postgresql://staging:xxx@staging-db.internal:5432/megashop_staging
REDIS_URL=redis://staging-redis.internal:6379
JWT_ACCESS_SECRET=${{ secrets.STAGING_JWT_SECRET }}
# .env.production
DATABASE_URL=postgresql://prod:xxx@prod-db.internal:5432/megashop
REDIS_URL=redis://prod-redis.internal:6379
JWT_ACCESS_SECRET=${{ secrets.PROD_JWT_SECRET }}
▶ 示例:Staging 部署工作流
YAML
# .github/workflows/deploy-staging.yml
name: Deploy Staging
on:
push:
branches: [main]
jobs:
deploy-staging:
runs-on: ubuntu-latest
needs: [lint, test]
environment: staging
steps:
- uses: actions/checkout@v4
- name: Deploy to staging
run: |
ssh staging-server << 'EOF'
cd /opt/megashop
git pull origin main
docker compose up -d --build
docker compose exec web npx prisma migrate deploy
EOF
- name: Smoke test
run: |
sleep 10
curl -f https://staging.megashop.com/api/products?limit=1 || exit 1
- name: Notify team
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{"text": "Staging deployment failed!"}
输出:
TEXT
📖 仅展示
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx:latest Up 2 hours 0.0.0.0:80->80/tcp
(1) 环境对比
| 环境 | 用途 | 数据库 | 部署方式 | 访问权限 |
|---|---|---|---|---|
| development | 本地开发 | 本地 PostgreSQL | npm run dev | 开发者 |
| staging | 集成测试 | 独立 PostgreSQL | 自动(main push) | 团队 |
| production | 正式环境 | 生产 PostgreSQL | 自动(tag/release) | 全部用户 |
6. 部署策略
(1) 部署策略对比
| 策略 | 原理 | 停机时间 | 回滚速度 | 复杂度 |
|---|---|---|---|---|
| 直接替换 | 停旧启新 | 🔴 有(5-30s) | 🟡 重新部署 | 🟢 简单 |
| 蓝绿部署 | 两套环境切换 | 🟢 无 | 🟢 秒级切换 | 🟡 中 |
| 滚动更新 | 逐个替换实例 | 🟢 无 | 🟡 逐个回滚 | 🟡 中 |
| 金丝雀发布 | 小流量先验证 | 🟢 无 | 🟢 立即切回 | 🔴 复杂 |
▶ 示例:蓝绿部署脚本
BASH
#!/bin/bash
# deploy-blue-green.sh
CURRENT=$(docker compose ps --format '{{.Name}}' | grep -o 'blue\|green' | head -1)
if [ "$CURRENT" = "blue" ]; then
NEXT="green"
else
NEXT="blue"
fi
echo "Deploying to $NEXT environment..."
# Build and start next environment
docker compose -f docker-compose.yml -f docker-compose.$NEXT.yml up -d --build
# Wait for health check
for i in {1..30}; do
if curl -sf http://localhost:3001/health; then
echo "Health check passed"
break
fi
sleep 2
done
# Switch Nginx to new environment
sed "s/$CURRENT/$NEXT/g" nginx.conf > /tmp/nginx.conf
docker compose exec nginx nginx -s reload
echo "Switched from $CURRENT to $NEXT"
输出:
TEXT
📖 仅展示
CONTAINER ID IMAGE STATUS
abc123 latest Up 2 hours
7. 综合示例:MegaShop CI/CD 全流程
YAML
# .github/workflows/deploy-production.yml
name: Deploy Production
on:
release:
types: [published]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t megashop:${{ github.sha }} .
- name: Push to registry
run: |
docker tag megashop:${{ github.sha }} ghcr.io/megashop/megashop:latest
echo ${{ secrets.GHCR_TOKEN }} | docker login ghcr.io -u $ --password-stdin
docker push ghcr.io/megashop/megashop:latest
- name: Deploy to production
run: |
ssh prod-server << EOF
cd /opt/megashop
docker pull ghcr.io/megashop/megashop:latest
docker compose up -d --no-build
docker compose exec web npx prisma migrate deploy
EOF
- name: Health check
run: |
for i in {1..10}; do
if curl -sf https://megashop.com/api/health; then exit 0; fi
sleep 5
done
exit 1
- name: Rollback on failure
if: failure()
run: |
ssh prod-server << EOF
cd /opt/megashop
docker compose down
docker tag megashop:previous megashop:latest
docker compose up -d
EOF
❓ 常见问题
Q GitHub Actions 免费额度够用吗?
A 公开仓库无限分钟。私有仓库每月 2000 分钟,MegaShop 一次 CI 约 10 分钟,每天 10 次约 100 分钟,够用。
Q PR 预览环境怎么实现?
A 用 Vercel Preview 自动生成。每个 PR 有独立 URL(pr-123-megashop.vercel.app),合并后自动删除。
Q 数据库迁移在 CI 中怎么跑?
A CI 中用 prisma migrate deploy(只应用已有迁移,不创建新的)。开发时用 prisma migrate dev 创建迁移文件并提交到 Git。
Q 怎么实现零停机部署?
A 蓝绿部署(两套环境切换)或 PM2 cluster reload(逐个替换 worker)。Docker 用滚动更新(docker compose rolling update)。
Q 回滚怎么操作?
A Git revert + 重新部署。Docker 用之前的镜像 tag 重新启动。PM2 用 pm2 stop + 启动旧版本。自动化回滚在部署脚本中加入 health check 失败逻辑。
Q 密钥怎么安全管理?
A GitHub Secrets 存环境变量,永远不提交到 Git。runtimeConfig 私有字段只服务端可用。CI 中通过 ${{ secrets.XXX }} 引用。
📖 小节
- GitHub Actions 实现 lint → test → build → deploy 全自动流水线
- 代码质量门禁:ESLint + TypeCheck + Vitest ≥ 80% 覆盖率
- 三环境管理:development(本地)→ staging(集成测试)→ production(正式)
- 蓝绿部署实现零停机,health check 失败自动回滚
- MegaShop:PR 自动预览 + main 自动 staging + release 自动 production
📝 作业
- 基础题(难度⭐):创建 GitHub Actions CI 工作流,push 时自动跑 lint + typecheck + test
- 进阶题(难度⭐⭐):添加 staging 自动部署——main push 自动部署到 staging 服务器,部署后跑 smoke test
- 挑战题(难度⭐⭐⭐):实现蓝绿部署脚本 + 自动回滚——health check 失败时自动切回旧版本
---|