CI/CD 与自动化发布

前端工程化三部曲:CI/CD 与自动化发布

代码写完只是开始,自动构建、测试、部署才是工程化的终点。这篇带你打通从 Git 提交到线上发布的完整流水线。


一、导读

这篇解决什么问题

当你遇到以下情况时,这篇文章能帮你建立系统化的解决方案:

  • 每次发版手动打包、上传、改配置,耗时耗力还容易出错
  • 团队成员代码风格不统一,Code Review 时还在争论分号问题
  • 测试环境部署频繁,但总是漏掉某个步骤导致环境不一致
  • 生产环境出问题了,却不知道当前线上跑的是哪次提交的代码
  • 想引入自动化测试,但不知道在 CI 流程中放在哪个环节

本文专注于 前端 CI/CD 的完整流水线设计,从 Git 工作流、自动化检查、构建部署到发布策略,带你从「手动发布」升级到「一键上线」。


二、CI/CD 核心概念

1 什么是 CI/CD

复制代码
┌─────────────────────────────────────────────────────────┐
│                    CI/CD 流水线全景                      │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  开发者推送代码                                          │
│       │                                                 │
│       ↓                                                 │
│  ┌─────────────────────────────────────────────────┐    │
│  │  CI(持续集成)                                  │    │
│  │  • 代码拉取 → 依赖安装 → 代码检查 → 单元测试     │    │
│  │  • 构建打包 → 产物上传 → 触发通知                │    │
│  └─────────────────────────────────────────────────┘    │
│       │                                                 │
│       ↓  构建成功                                       │
│  ┌─────────────────────────────────────────────────┐    │
│  │  CD(持续部署/交付)                             │    │
│  │  • 部署到测试环境 → 集成测试 → 人工验收          │    │
│  │  • 部署到预发布环境 → 灰度发布 → 全量发布        │    │
│  └─────────────────────────────────────────────────┘    │
│       │                                                 │
│       ↓                                                 │
│  线上环境自动更新                                        │
│                                                         │
└─────────────────────────────────────────────────────────┘

CI(Continuous Integration):持续集成,强调频繁地将代码合并到主干,并通过自动化验证确保合并质量。

CD 有两种理解

  • Continuous Delivery(持续交付):代码自动构建、测试,但发布到生产环境需要人工审批
  • Continuous Deployment(持续部署):代码通过所有检查后自动发布到生产环境,无需人工干预

2 前端 CI/CD 的独特性

特性 前端 后端
构建产物 静态文件(HTML/CSS/JS) 可执行程序/容器镜像
部署目标 CDN / 静态服务器 / OSS 应用服务器 / K8s
缓存策略 文件名哈希 + 长期缓存 通常不依赖客户端缓存
环境差异 构建时注入环境变量 运行时读取配置
回滚方式 切换 CDN 路径或回退版本 重启服务或切换容器

三、Git 工作流:CI/CD 的触发源头

1 主流分支模型对比

复制代码
┌─────────────────────────────────────────────────────────┐
│              Git Flow(适合版本化发布)                   │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   main ─────●────────●────────●────────●─────►         │
│            1.0     1.1     1.2     1.3                │
│              ↑       ↑       ↑       ↑                  │
│   develop ──●──●──●──●──●──●──●──●──●──●──►           │
│                ↘   ↗   ↘   ↗                          │
│   feature/a      feature/b    hotfix/1.2.1            │
│                                                         │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│           GitHub Flow(适合持续部署)                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   main ─────●────────●────────●────────●─────►         │
│              ↑       ↑       ↑       ↑                  │
│   feature/a  feature/b  feature/c  feature/d            │
│   (PR → Review → Merge → Auto Deploy)                  │
│                                                         │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│           Trunk-Based(适合高频发布)                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   main ─────●─●─●─●─●─●─●─●─●─●─●─●─●─●─●─●─●─►       │
│   (所有提交直接进主干,用 Feature Flag 控制功能开关)       │
│                                                         │
└─────────────────────────────────────────────────────────┘

选型建议

  • Git Flow:有明确版本号的产品(如桌面应用、需要版本回退的 B 端系统)
  • GitHub Flow:Web 应用、SaaS 产品、追求快速迭代
  • Trunk-Based:大型团队、每日多次发布、配合 Feature Flag 使用

2 提交规范:自动化的基础

复制代码
<type>(<scope>): <subject>

<body>

<footer>

常用 type

类型 含义 是否触发版本升级
feat 新功能 minor
fix 修复 bug patch
docs 文档更新
style 代码格式(不影响功能)
refactor 重构 patch
perf 性能优化 patch
test 测试相关
chore 构建/工具链变动

示例

bash 复制代码
feat(auth): 添加 OAuth2.0 登录支持

- 支持 GitHub、Google 第三方登录
- 添加登录状态持久化
- 更新相关单元测试

Closes #123

3 自动化版本管理

javascript 复制代码
// package.json
{
  "version": "1.2.3",
  // 主版本.次版本.修订号
  // 1.0.0 → 1.1.0 (feat)
  // 1.1.0 → 1.1.1 (fix)
  // 1.1.1 → 2.0.0 (BREAKING CHANGE)
}

工具推荐

  • standard-version:基于 Angular 提交规范自动生成 CHANGELOG 和版本号
  • semantic-release:全自动版本管理和发布,与 CI 深度集成

四、CI 流水线设计

1 流水线阶段划分

复制代码
┌─────────────────────────────────────────────────────────┐
│                   前端 CI 流水线                         │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Stage 1: 环境准备                                       │
│  ┌─────────────────────────────────────────────────┐    │
│  │  • 检出代码                                      │    │
│  │  • 设置 Node.js 版本                             │    │
│  │  • 安装依赖(利用缓存加速)                       │    │
│  └─────────────────────────────────────────────────┘    │
│                         ↓                               │
│  Stage 2: 代码质量检查                                   │
│  ┌─────────────────────────────────────────────────┐    │
│  │  • ESLint / Prettier 检查                        │    │
│  │  • TypeScript 类型检查                           │    │
│  │  • 提交信息规范检查(commitlint)                 │    │
│  └─────────────────────────────────────────────────┘    │
│                         ↓                               │
│  Stage 3: 测试                                          │
│  ┌─────────────────────────────────────────────────┐    │
│  │  • 单元测试(Vitest / Jest)                     │    │
│  │  • 组件测试(Vue Test Utils / React Testing Lib)│    │
│  │  • E2E 测试(Playwright / Cypress)              │    │
│  └─────────────────────────────────────────────────┘    │
│                         ↓                               │
│  Stage 4: 构建                                          │
│  ┌─────────────────────────────────────────────────┐    │
│  │  • 生产环境构建                                  │    │
│  │  • 产物分析(包体积检查)                         │    │
│  │  • Source Map 生成(按需)                        │    │
│  └─────────────────────────────────────────────────┘    │
│                         ↓                               │
│  Stage 5: 产物处理                                       │
│  ┌─────────────────────────────────────────────────┐    │
│  │  • 上传构建产物到存储(OSS / S3)                 │    │
│  │  • 生成部署配置                                  │    │
│  │  • 触发部署流水线                                │    │
│  └─────────────────────────────────────────────────┘    │
│                                                         │
└─────────────────────────────────────────────────────────┘

2 依赖安装优化

yaml 复制代码
# GitHub Actions 示例:缓存 pnpm 依赖
- name: Setup pnpm
  uses: pnpm/action-setup@v2
  with:
    version: 8

- name: Setup Node.js
  uses: actions/setup-node@v3
  with:
    node-version: 18
    cache: 'pnpm'  # 自动缓存 pnpm store

- name: Install dependencies
  run: pnpm install --frozen-lockfile

关键优化点

  • 使用 --frozen-lockfile 确保依赖版本一致性
  • 利用 CI 平台缓存机制加速 node_modules 恢复
  • 考虑使用 pnpm 的依赖复用能力减少安装时间

3 代码检查并行化

yaml 复制代码
# 并行执行独立检查任务
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
      - run: pnpm install
      - run: pnpm lint        # ESLint + Prettier

  type-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
      - run: pnpm install
      - run: pnpm type-check  # tsc --noEmit

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
      - run: pnpm install
      - run: pnpm test        # 单元测试

4 构建产物分析

javascript 复制代码
// vite.config.ts - 集成 rollup-plugin-visualizer
import { defineConfig } from 'vite';
import { visualizer } from 'rollup-plugin-visualizer';

export default defineConfig({
  plugins: [
    // ...其他插件
    process.env.ANALYZE && visualizer({
      open: false,
      gzipSize: true,
      brotliSize: true,
      filename: 'dist/stats.html'
    })
  ]
});

构建检查清单

  • 包体积是否超过阈值(如首屏 JS > 200KB)
  • 是否有重复依赖(lodash vs lodash-es)
  • Source Map 是否正确生成
  • 环境变量是否正确注入

五、GitHub Actions 实战

1 完整工作流示例

yaml 复制代码
# .github/workflows/ci.yml
name: CI

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

jobs:
  # 阶段 1:代码质量检查
  quality:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Lint
        run: pnpm lint

      - name: Type check
        run: pnpm type-check

  # 阶段 2:测试
  test:
    runs-on: ubuntu-latest
    needs: quality  # 质量检查通过后执行
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm test:unit
      - run: pnpm test:e2e

  # 阶段 3:构建
  build:
    runs-on: ubuntu-latest
    needs: [quality, test]
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v3
        with:
          name: dist
          path: dist/

  # 阶段 4:部署到测试环境(develop 分支)
  deploy-staging:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/develop'
    steps:
      - name: Download build artifacts
        uses: actions/download-artifact@v3
        with:
          name: dist
          path: dist/

      - name: Deploy to staging
        run: |
          # 上传到测试环境 CDN 或服务器
          aws s3 sync dist/ s3://staging-bucket/

2 环境变量管理

yaml 复制代码
# 不同环境使用不同变量
jobs:
  build:
    steps:
      - name: Build for staging
        if: github.ref == 'refs/heads/develop'
        run: pnpm build
        env:
          VITE_API_URL: https://api-staging.example.com
          VITE_APP_ENV: staging

      - name: Build for production
        if: github.ref == 'refs/heads/main'
        run: pnpm build
        env:
          VITE_API_URL: https://api.example.com
          VITE_APP_ENV: production

安全注意事项

  • 敏感信息使用 GitHub Secrets:${``{ secrets.API_KEY }}
  • 避免在代码中硬密钥
  • 生产环境变量与测试环境隔离

3 条件执行与矩阵构建

yaml 复制代码
# 矩阵构建:多 Node 版本、多操作系统测试
jobs:
  test:
    strategy:
      matrix:
        node-version: [16, 18, 20]
        os: [ubuntu-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
      # ...测试步骤

六、Docker 容器化部署

1 前端项目的 Dockerfile

dockerfile 复制代码
# 多阶段构建:减小最终镜像体积

# 阶段 1:构建
FROM node:18-alpine AS builder

WORKDIR /app

# 先复制依赖文件,利用缓存层
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile

# 复制源码并构建
COPY . .
RUN pnpm build

# 阶段 2:运行(使用 Nginx 托管静态文件)
FROM nginx:alpine

# 复制构建产物到 Nginx 目录
COPY --from=builder /app/dist /usr/share/nginx/html

# 复制自定义 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

2 Nginx 配置优化

nginx 复制代码
server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # Gzip 压缩
    gzip on;
    gzip_types text/plain text/css application/json application/javascript;

    # 静态资源长期缓存(因为文件名有哈希)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # HTML 文件不缓存(确保总是获取最新版本)
    location ~* \.html$ {
        expires -1;
        add_header Cache-Control "no-cache";
    }

    # 前端路由支持(单页应用)
    location / {
        try_files $uri $uri/ /index.html;
    }
}

3 Docker 构建与推送

yaml 复制代码
# GitHub Actions 中构建并推送 Docker 镜像
jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: |
            ${{ secrets.DOCKER_USERNAME }}/app:${{ github.sha }}
            ${{ secrets.DOCKER_USERNAME }}/app:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

七、部署策略

1 部署方式对比

方式 适用场景 优点 缺点
CDN 部署 纯静态站点 全球加速、成本低 需要处理缓存刷新
对象存储 静态资源托管 高可用、自动扩容 需要配合 CDN 使用
Docker + K8s 微服务架构 环境一致、易于回滚 运维成本高
Serverless 低频访问站点 按需付费、免运维 冷启动延迟

2 蓝绿部署与滚动部署

复制代码
┌─────────────────────────────────────────────────────────┐
│                     蓝绿部署                             │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  用户流量 ──────┐                                       │
│                 ↓                                       │
│            ┌─────────┐                                 │
│            │ 负载均衡 │                                 │
│            └────┬────┘                                 │
│                 │                                       │
│        ┌────────┴────────┐                             │
│        ↓                 ↓                             │
│   ┌─────────┐      ┌─────────┐                         │
│   │  蓝环境  │      │  绿环境  │                         │
│   │ (v1.0)  │      │ (v2.0)  │                         │
│   │  运行中  │      │  待切换  │                         │
│   └─────────┘      └─────────┘                         │
│                                                         │
│  切换时:负载均衡瞬间指向绿环境,蓝环境保留用于回滚       │
│                                                         │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│                     滚动部署                             │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  用户流量 ───────────────────────────────►             │
│                                                         │
│  实例 1: [v1.0] → [v2.0]                              │
│  实例 2: [v1.0] → [v1.0] → [v2.0]                     │
│  实例 3: [v1.0] → [v1.0] → [v1.0] → [v2.0]           │
│                                                         │
│  特点:逐步替换实例,期间新旧版本共存                     │
│                                                         │
└─────────────────────────────────────────────────────────┘

3 前端灰度发布实践

javascript 复制代码
// 基于用户 ID 的灰度策略
function isGrayRelease(userId, grayPercent = 10) {
  // 将用户 ID 哈希为数字,取模判断是否命中灰度
  const hash = userId.split('').reduce((acc, char) => {
    return acc + char.charCodeAt(0);
  }, 0);
  return hash % 100 < grayPercent;
}

// 应用加载时决定使用哪个版本
const scriptSrc = isGrayRelease(currentUser.id, 20)
  ? 'https://cdn.example.com/app/v2.0/main.js'
  : 'https://cdn.example.com/app/v1.0/main.js';

八、自动化测试集成

1 测试金字塔在前端的应用

复制代码
                    ┌─────────┐
                    │  E2E    │  ← 用户视角,覆盖核心流程
                    │  少量   │     Playwright / Cypress
                    ├─────────┤
                    │  集成   │  ← 组件组合测试
                    │  中等   │     Vue Test Utils / React Testing Lib
                    ├─────────┤
                    │  单元   │  ← 函数/工具类测试
                    │  大量   │     Vitest / Jest
                    └─────────┘

2 CI 中的测试策略

yaml 复制代码
jobs:
  unit-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: pnpm install
      - run: pnpm test:unit --coverage
      - name: Upload coverage
        uses: codecov/codecov-action@v3

  e2e-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: pnpm install
      - run: pnpm build
      - name: Run E2E tests
        run: pnpm test:e2e
        env:
          CI: true

3 视觉回归测试

yaml 复制代码
# 使用 Chromatic 或 Percy 进行 UI 回归测试
- name: Publish to Chromatic
  uses: chromaui/action@v1
  with:
    projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}

九、监控与回滚

1 部署后健康检查

yaml 复制代码
jobs:
  deploy:
    steps:
      - name: Deploy
        run: ./deploy.sh

      - name: Health check
        run: |
          for i in {1..5}; do
            curl -f https://app.example.com/health && exit 0
            sleep 10
          done
          exit 1

2 错误监控集成

javascript 复制代码
// 生产环境集成 Sentry
import * as Sentry from '@sentry/vue';

Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,
  environment: import.meta.env.VITE_APP_ENV,
  release: import.meta.env.VITE_APP_VERSION, // 关联版本号
  integrations: [
    Sentry.browserTracingIntegration(),
    Sentry.replayIntegration()
  ]
});

3 快速回滚策略

bash 复制代码
# 基于 Docker 镜像的回滚
# 1. 查看历史版本
docker images | grep my-app

# 2. 快速切换到上一个版本
docker stop app-current
docker run -d --name app-rollback -p 80:80 my-app:previous-tag

# 基于 CDN 的回滚
# 1. 将 CDN 回源路径指向上一个版本目录
# 2. 刷新 CDN 缓存

十、完整流水线示例

一个现代化的前端 CI/CD 配置

yaml 复制代码
# .github/workflows/main.yml
name: Build and Deploy

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

env:
  NODE_VERSION: 18

jobs:
  # ========== 质量门禁 ==========
  lint-and-type:
    name: Lint & Type Check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm type-check

  # ========== 测试 ==========
  test:
    name: Test
    runs-on: ubuntu-latest
    needs: lint-and-type
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm test:unit --coverage
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3

  # ========== 构建 ==========
  build:
    name: Build
    runs-on: ubuntu-latest
    needs: test
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm build
      - name: Analyze bundle size
        run: pnpm analyze
      - name: Upload dist
        uses: actions/upload-artifact@v3
        with:
          name: dist
          path: dist/

  # ========== 部署到预发布环境 ==========
  deploy-staging:
    name: Deploy to Staging
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/develop'
    environment:
      name: staging
      url: https://staging.example.com
    steps:
      - name: Download dist
        uses: actions/download-artifact@v3
        with:
          name: dist
      - name: Deploy to S3
        run: aws s3 sync . s3://staging-bucket/ --delete
      - name: Invalidate CDN
        run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CF_DIST_ID }} --paths "/*"

  # ========== 部署到生产环境 ==========
  deploy-production:
    name: Deploy to Production
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    environment:
      name: production
      url: https://example.com
    steps:
      - name: Download dist
        uses: actions/download-artifact@v3
        with:
          name: dist
      - name: Deploy to S3
        run: aws s3 sync . s3://production-bucket/ --delete
      - name: Invalidate CDN
        run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CF_PROD_DIST_ID }} --paths "/*"
      - name: Notify Slack
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "✅ 生产环境部署成功: ${{ github.sha }}"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

十一、最佳实践总结

CI/CD checklist

  • Git 规范:提交信息规范、分支保护、Code Review 强制要求
  • 自动化检查:Lint、Type Check、单元测试必须在合并前通过
  • 构建可复现:lock 文件提交、Node 版本锁定、依赖缓存
  • 环境隔离:开发/测试/生产环境配置分离,敏感信息用 Secrets
  • 产物管理:构建产物版本化、Source Map 按需生成
  • 部署策略:蓝绿部署或灰度发布,支持快速回滚
  • 监控告警:部署后健康检查、错误监控、性能监控
  • 文档化:流水线配置、环境变量说明、回滚操作手册

常见陷阱

陷阱 后果 解决方案
不锁依赖版本 构建结果不一致 使用 lock 文件 + --frozen-lockfile
在 CI 中运行开发服务器 流程卡住 只执行构建命令,不启动 dev server
忽略 CI 缓存 每次全量安装依赖 配置 actions/cachesetup-node 的 cache
生产环境构建无 Source Map 线上错误无法定位 生成 hidden-source-map,不上传至服务器
环境变量硬编码 安全风险 使用 CI Secrets + 构建时注入
缺少回滚方案 故障恢复慢 保留历史版本、准备快速回滚脚本

十二、延伸阅读与工具

工具/平台 用途
GitHub Actions CI/CD 工作流编排
GitLab CI 替代方案,与 GitLab 深度集成
CircleCI 云端 CI 服务,配置简洁
Jenkins 自托管 CI 服务器,高度可定制
Docker 容器化打包与部署
Kubernetes 容器编排,适合大规模部署
Vercel / Netlify 前端托管平台,零配置 CI/CD
Sentry 错误监控与性能追踪
Codecov 测试覆盖率报告
semantic-release 自动化版本管理与发布


十三、前端安全:CI/CD 中的安全左移

1 依赖安全检查

bash 复制代码
# 使用 npm audit 检查已知漏洞
npm audit

# 使用 Snyk 进行深度扫描
npx snyk test

# 在 CI 中阻断高危漏洞
npm audit --audit-level=high

CI 集成

yaml 复制代码
- name: Security audit
  run: |
    pnpm audit --audit-level high
    if [ $? -ne 0 ]; then
      echo "发现高危安全漏洞,请修复后重试"
      exit 1
    fi

2 代码扫描与 Secret 检测

yaml 复制代码
# 使用 GitLeaks 检测代码中的密钥泄露
- name: Detect secrets
  uses: zricethezav/gitleaks-action@master
  with:
    config-path: .gitleaks.toml

常见泄露场景

  • 硬编码的 API Key、数据库密码
  • .env 文件误提交到仓库
  • 测试代码中的真实凭证

3 供应链安全

bash 复制代码
# 锁定依赖版本,防止恶意更新
# package.json 中使用精确版本
"lodash": "4.17.21"  # 而非 "^4.17.21"

# 使用 lock 文件确保一致性
pnpm-lock.yaml
package-lock.json
yarn.lock

安全实践

  • 定期更新依赖,及时修复漏洞
  • 使用私有 registry(如 Verdaccio)管控内部包
  • 审查新引入依赖的维护状态和安全记录

十四、性能预算与构建优化

1 性能预算定义

javascript 复制代码
// budgets.config.js
module.exports = {
  budgets: [
    {
      type: 'bundle',
      name: 'main',
      maximumWarning: '150kb',
      maximumError: '200kb'
    },
    {
      type: 'bundle',
      name: 'vendor',
      maximumWarning: '250kb',
      maximumError: '300kb'
    },
    {
      type: 'asset',
      name: '*.jpg',
      maximumWarning: '100kb',
      maximumError: '200kb'
    }
  ]
};

2 CI 中的性能检查

yaml 复制代码
- name: Build with budget check
  run: pnpm build

- name: Check bundle size
  run: |
    BUNDLE_SIZE=$(du -k dist/assets/main.*.js | cut -f1)
    if [ $BUNDLE_SIZE -gt 200 ]; then
      echo "错误: main bundle 超过 200KB (当前: ${BUNDLE_SIZE}KB)"
      exit 1
    fi

3 构建产物优化清单

优化项 工具/方法 预期效果
代码分割 Vite/Rollup manualChunks 减少首屏加载
Tree Shaking ESM + 副作用标记 移除未使用代码
Gzip/Brotli 构建时生成压缩文件 减少传输体积
图片优化 vite-plugin-imagemin 图片体积减少 50%+
字体子集化 fontmin / subset-font 只打包使用的字符
懒加载路由 React.lazy() / defineAsyncComponent 按需加载页面

十五、多环境配置管理

1 环境配置分层

复制代码
config/
├── default.json      # 默认配置(所有环境共享)
├── development.json  # 开发环境覆盖
├── staging.json      # 测试环境覆盖
└── production.json   # 生产环境覆盖
javascript 复制代码
// 配置加载逻辑
import defaultConfig from './config/default.json';
import devConfig from './config/development.json';
import prodConfig from './config/production.json';

const env = import.meta.env.VITE_APP_ENV || 'development';
const envConfig = {
  development: devConfig,
  staging: stagingConfig,
  production: prodConfig
}[env];

export const config = { ...defaultConfig, ...envConfig };

2 环境变量命名规范

bash 复制代码
# 公开变量(构建时注入,客户端可见)
VITE_API_URL=https://api.example.com
VITE_APP_NAME=MyApp

# 私有变量(仅服务端/CI 使用)
API_SECRET_KEY=xxx
DEPLOY_TOKEN=xxx

Vite 环境变量规则

  • 只有以 VITE_ 开头的变量才会暴露给客户端代码
  • 其他变量仅在 Node.js 环境中可用

3 动态配置(无需重新构建)

javascript 复制代码
// 运行时获取配置,避免每次改配置都要重新构建
async function loadRuntimeConfig() {
  const response = await fetch('/config.json');
  return response.json();
}

// 应用启动时加载
const runtimeConfig = await loadRuntimeConfig();
// 后续使用 runtimeConfig.apiUrl 等

十六、团队协作与 Code Review 自动化

1 PR 模板与检查清单

markdown 复制代码
<!-- .github/pull_request_template.md -->
## 变更描述

## 检查清单

- [ ] 代码通过 ESLint 检查
- [ ] 单元测试全部通过
- [ ] 手动测试核心流程
- [ ] 更新相关文档
- [ ] 添加/更新 CHANGELOG

## 截图(如适用)

## 关联 Issue

Closes #

2 自动化 PR 检查

yaml 复制代码
# .github/workflows/pr.yml
name: PR Checks

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  pr-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0  # 需要完整历史检查提交信息

      - name: Check commit messages
        run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose

      - name: Check PR title
        run: |
          echo "${{ github.event.pull_request.title }}" | npx commitlint

      - name: Label PR by files changed
        uses: actions/labeler@v4
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}

3 代码覆盖率门禁

yaml 复制代码
- name: Check coverage
  uses: codecov/codecov-action@v3
  with:
    fail_ci_if_error: true
    verbose: true

覆盖率策略

  • 新代码覆盖率不低于 80%
  • 整体覆盖率不低于 60%
  • 核心模块覆盖率不低于 90%

十七、故障排查与 CI 调试技巧

1 本地模拟 CI 环境

bash 复制代码
# 使用 act 工具本地运行 GitHub Actions
# 安装
brew install act

# 运行完整工作流
act

# 运行特定 job
act -j build

# 使用特定事件触发
act pull_request

2 CI 故障排查清单

现象 可能原因 解决方案
依赖安装失败 lock 文件与 package.json 不一致 删除 lock 文件重新生成
构建内存溢出 Node.js 内存限制 NODE_OPTIONS=--max-old-space-size=4096
测试随机失败 时序问题、未清理状态 添加 beforeEach 清理,使用 waitFor
权限 denied Secrets 未配置或名称错误 检查 Repository Settings → Secrets
缓存未命中 缓存 key 配置错误 检查 actions/cache 的 key 和 path
部署后 404 路由配置问题 检查 Nginx/服务器 rewrite 规则

3 调试技巧

yaml 复制代码
# 在 CI 中启用调试输出
- name: Debug info
  run: |
    echo "Node version: $(node -v)"
    echo "NPM version: $(npm -v)"
    echo "Working directory: $(pwd)"
    echo "Directory contents:"
    ls -la
    echo "Environment variables:"
    env | grep VITE_
bash 复制代码
# SSH 连接到运行中的 CI 实例(GitHub Actions)
- name: Setup tmate session
  uses: mxschmitt/action-tmate@v3
  if: ${{ failure() }}

十八、未来趋势与展望

1 前端部署的演进方向

阶段 特点 代表
手动 FTP 上传 无版本控制、易出错 早期个人站点
脚本化部署 脚本代替手动操作 Shell / Python 脚本
CI/CD 流水线 自动化、可追踪 GitHub Actions / Jenkins
平台化部署 零配置、边缘部署 Vercel / Netlify / Cloudflare Pages
基础设施即代码 声明式、可复现 Terraform / Pulumi

2 边缘计算与前端

javascript 复制代码
// Cloudflare Workers 边缘函数
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);

    // A/B 测试在边缘层实现
    const variant = Math.random() < 0.5 ? 'a' : 'b';
    url.pathname = `/variant-${variant}${url.pathname}`;

    return fetch(url);
  }
};

边缘部署优势

  • 全球低延迟(就近响应)
  • 减少源站压力
  • 动态内容在边缘处理
相关推荐
星星在线4 小时前
MusicFree:一个「All in One」的个人音乐服务器,让听歌回归简单
前端·后端
IT_陈寒4 小时前
Redis的SETNX并发问题让我加了三天班
前端·人工智能·后端
demo007x5 小时前
Docling 文档转换以及技术架构分析
前端·后端·程序员
京东云开发者5 小时前
京东市民服务又“上新”!这次是黑龙江“龙易办”
前端
袋鱼不重6 小时前
我的神奇同事,AI 用多了居然写了个 Open In Codex
前端·后端·ai编程
大树886 小时前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠6 小时前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
Fireworks7 小时前
深入vue3源码解读 -- 1、响应式的基础概念
前端
程序员黑豆7 小时前
JDK 下载安装与配置详细教程
java·前端·ai编程
hunterandroid7 小时前
文件存储:内部存储与外部存储
前端