React: 部署与 CI/CD

最后更新:2026-08-26

Tom 的博客在本地跑得好好的,但部署到线上后遇到了各种问题:图片加载不出来、API 地址写死成 localhost、每次手动 SSH 上传代码又慢又容易出错。他需要一套自动化的部署流水线,让代码从 push 到上线变成全自动流程。

本课将带你走完从"本地开发"到"生产上线"的完整路径。你将学会使用 Vercel 一键部署、配置 GitHub Actions 自动化流水线、管理多环境变量,以及优化构建产物以提升页面加载速度。这些部署技能是前端工程师从"会写代码"到"会交付产品"的关键一步。


1. 你将学到



2. 概念图解

Tom 设计了一条完整的 CI/CD 流水线:开发者 push 代码到 GitHub 后,自动触发构建和测试流程,通过后自动部署到预览环境供审核,审核通过合并到主分支后自动部署到生产环境。

流水线的核心是自动化和标准化。所有检查步骤(lint、type-check、test)都在 CI 环境中自动执行,不需要人工干预。这样任何代码质量问题都能在合并前被发现,确保生产环境只部署经过验证的代码。Vercel 的 Preview Deployment 会自动为每个分支生成独立的预览 URL,方便产品经理和测试人员直接点击查看效果。

100%
flowchart LR
    A[开发者 Push 代码] --> B[GitHub 接收]
    B --> C[GitHub Actions 触发]
    C --> D{运行 CI 流程}
    D --> E[安装依赖<br/>npm ci]
    E --> F[代码检查<br/>lint / type-check]
    F --> G[运行测试<br/>jest / playwright]
    G --> H[构建<br/>next build]
    H --> I{部署目标}
    I -->|Feature 分支| J[Vercel Preview<br/>预览环境]
    I -->|Main 分支| K[Vercel Production<br/>生产环境]
    J --> L[Preview URL 自动生成]
    K --> M[CDN 分发<br/>全球加速]


3. 一个真实场景

部署方案 构建方式 ISR 支持 运维成本 适用场景
Vercel 自动(Git push) ✅ 原生 极低 Next.js 项目、个人/小团队
Netlify 自动(Git push) ⚠️ 需配置 静态站点、Gatsby
Docker + Nginx 手动/CI ❌ 需自建 私有部署、需要完全控制
AWS Amplify 自动 ⚠️ 有限 AWS 生态项目
传统服务器 PM2 手动 复杂定制需求

Tom 的博客部署问题清单越来越长:每次更新文章都要 SSH 登录服务器、手动运行 git pullnpm run buildpm2 restart,整个过程至少 10 分钟。如果忘了备份数据库,一失手就全没了。更头疼的是,团队其他成员的修改经常覆盖他的代码。

他决定采用 Vercel + GitHub Actions 的现代部署方案。第一步将代码从 FTP 迁移到 GitHub 仓库;第二步连接 Vercel 实现自动部署;第三步配置 GitHub Actions 添加代码检查和测试流程。改造完成后,每次 push 代码到 main 分支,Vercel 自动构建部署,整个流程不到 2 分钟。

Tom 还对比了几种部署方案的优劣:Vercel 适合 Next.js 项目,配置最简单;Netlify 也支持 Next.js 但部分高级特性(ISR、Middleware)需要额外配置;Docker 部署适合需要完全控制服务器环境的场景;传统服务器部署(Nginx + PM2)灵活度最高但运维成本最大。对于个人博客和小型项目,Vercel 是毫无疑问的最佳选择。

(1) Vercel 自动部署

Vercel 是 Next.js 的创建者 Vercel 公司提供的 Serverless 部署平台。它与 Next.js 深度集成,支持自动检测框架、Serverless Functions、Edge Functions、ISR、Middleware 等所有 Next.js 特性。Vercel 的自动部署机制基于 Git 集成——连接 GitHub/GitLab/Bitbucket 仓库后,每次 push 自动触发构建和部署。

Vercel 提供三个环境:Production(生产环境,绑定自定义域名)、Preview(预览环境,每个分支自动生成独立 URL)、Development(本地开发环境)。Preview 环境特别适合团队协作——每次 PR 自动生成预览 URL,方便 Reviewer 在真实环境中查看效果。

Vercel 部署步骤(GUI 方式)

  1. 在 Vercel Dashboard 点击 Add New -> Project
  2. 选择 GitHub 仓库并授权 Vercel 访问
  3. Vercel 自动检测框架为 Next.js,使用默认配置
  4. 在 Environment Variables 中添加必要的环境变量
  5. 点击 Deploy,等待约 1-2 分钟完成部署
  6. 部署完成后,Vercel 自动生成 .vercel.app 域名
  7. 在 Settings -> Domains 中添加自定义域名

Vercel 部署步骤(CLI 方式)

BASH
# 1. 全局安装 Vercel CLI
npm install -g vercel

# 2. 登录 Vercel 账号
vercel login

# 3. 在项目根目录执行部署
# 首次运行会引导配置项目设置
vercel

# 4. 部署到生产环境
vercel --prod

▶ 示例 1:Vercel 部署配置与 CLI

BASH
# 1. 安装 Vercel CLI
npm install -g vercel

# 2. 项目根目录登录
vercel login

# 3. 项目根目录部署到预览环境
vercel

# 4. 部署到生产环境
vercel --prod

# 5. 查看当前部署状态
vercel ls

# 6. 查看部署日志
vercel logs --all
TS
// next.config.ts - Vercel 自动读取此配置
import type { NextConfig } from 'next'

const config: NextConfig = {
  // 图片优化配置 - 允许远程图片域名
  images: {
    remotePatterns: [
      { protocol: 'https', hostname: 'images.example.com' },
      { protocol: 'https', hostname: '**.cloudfront.net' },
    ],
  },

  // HTTP 压缩
  compress: true,

  // 移除 X-Powered-By 头(安全考虑)
  poweredByHeader: false,

  // 自定义构建目录(可选)
  distDir: '.next',

  // 启用严格模式
  reactStrictMode: true,
}

export default config
JSON
// vercel.json - Vercel 项目配置(可选,大多数项目不需要)
{
  "framework": "nextjs",
  "buildCommand": "npm run build",
  "outputDirectory": ".next",
  "regions": ["hnd1", "iad1"],
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "X-Frame-Options", "value": "DENY" }
      ]
    }
  ]
}

(2) GitHub Actions CI/CD

GitHub Actions 是 GitHub 提供的 CI/CD 服务,通过 YAML 配置文件定义工作流。每次 push 或 PR 时自动触发指定的 job 序列。Tom 配置了三个 job:第一个在 push 到任何分支时运行 lint 和类型检查;第二个在 push 到 main 分支时运行全量测试和构建;第三个在发布新版本时自动部署到预览环境。

工作流文件放在 .github/workflows/ 目录下,文件名自定义。每个工作流可以包含多个 job,job 之间可以设置依赖关系。GitHub 提供了丰富的 marketplace action,可以直接复用社区构建好的步骤。

GitHub Actions 的核心概念包括:on 定义触发事件(push、pull_request、schedule 等)、jobs 定义要执行的任务、steps 定义每个任务的执行步骤、actions/ 是社区贡献的可复用模块。Tom 的工作流中使用了 actions/checkout@v4(检出代码)、actions/setup-node@v4(配置 Node.js 环境)、actions/upload-artifact@v4(上传构建产物)三个社区 action。

▶ 示例 2:完整的 GitHub Actions 工作流

YAML
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

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

jobs:
  # Job 1:代码质量和类型检查
  quality:
    name: Code Quality Check
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: TypeScript type check
        run: npx tsc --noEmit

      - name: Lint check
        run: npm run lint

  # Job 2:运行测试 + 构建
  test-and-build:
    name: Test & Build
    needs: quality  # 依赖 quality 任务成功
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run unit tests
        run: npm test
        env:
          CI: true

      - name: Build project
        run: npm run build
        env:
          NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: next-build
          path: .next/

  # Job 3:自动部署到 Vercel
  deploy:
    name: Deploy to Vercel
    needs: test-and-build
    runs-on: ubuntu-latest
    # 只在 main 分支部署
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

      - 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'

(3) 构建优化策略

部署不仅仅是将代码上传到服务器。一个优化良好的构建配置可以大幅提升页面加载速度、降低带宽成本。Tom 在部署优化上投入了不少精力,主要优化了三个方面:包体积分析、图片优化、缓存策略。

包体积分析使用 @next/bundle-analyzer 插件,可以可视化地查看每个模块的大小,找出体积异常的依赖。Tom 发现他的项目中 moment.js 占了 85KB,换成 dayjs(6KB)后首屏 JS 减少了 28%。他还发现一个从未使用的组件被全局导入,通过 Tree Shaking 移除了它。

图片优化通过 Next.js 内置的 next/image 组件实现,自动生成 WebP/AVIF 格式、响应式尺寸、懒加载。Tom 的博客文章中有大量图片,使用 next/image 后,图片加载时间从平均 1.2 秒降到 0.3 秒。

缓存策略通过配置 CDN 的 Cache-Control 头实现。静态资源(JS、CSS、图片)设置一年缓存(max-age=31536000),HTML 页面设置较短缓存(max-age=60)配合 ISR 自动更新。这样用户第一次访问后,后续的静态资源直接从浏览器缓存加载,无需重新请求。

其他部署方案速查

方案 配置复杂度 Next.js 兼容性 适用场景
Vercel 极低 完美 Next.js 首选部署平台
Netlify 良好(部分高级特性受限) 小型静态站点
Docker 良好 需要环境一致性的团队项目
传统 Nginx 需要手动配置 SSR 企业自建服务器
AWS Amplify 良好 AWS 生态项目

▶ 示例 3:构建优化配置

TS
// next.config.ts - 完整优化配置
import type { NextConfig } from 'next'

// 包体积分析(按需启用)
const withBundleAnalyzer = process.env.ANALYZE === 'true'
  ? require('@next/bundle-analyzer')({ enabled: true })
  : (config: any) => config

const config: NextConfig = {
  // === 图片优化 ===
  images: {
    // 允许的远程图片域名
    remotePatterns: [
      { protocol: 'https', hostname: 'images.example.com' },
      { protocol: 'https', hostname: 'cdn.example.com' },
    ],
    // 图片格式(默认已支持 WebP)
    formats: ['image/avif', 'image/webp'],
    // 设备断点(根据设计稿配置)
    deviceSizes: [640, 768, 1024, 1280, 1536],
  },

  // === 安全与性能 ===
  compress: true,
  poweredByHeader: false,
  reactStrictMode: true,

  // === CDN 配置 ===
  // 如果使用自定义 CDN,设置 assetPrefix
  // assetPrefix: 'https://cdn.example.com',

  // === 实验性功能 ===
  experimental: {
    // 优化 CSS 体积
    optimizePackageImports: ['antd', '@ant-design/icons', 'lodash-es'],
  },
}

export default withBundleAnalyzer(config)

// vercel.json - 缓存与安全头配置
// {
//   "headers": [
//     {
//       "source": "/static/(.*)",
//       "headers": [
//         { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
//       ]
//     },
//     {
//       "source": "/_next/image(.*)",
//       "headers": [
//         { "key": "Cache-Control", "value": "public, max-age=86400, stale-while-revalidate=2592000" }
//       ]
//     }
//   ]
// }
▶ 试一试
BASH
# 包体积分析命令
ANALYZE=true npm run build

# 该命令会生成两个 HTML 报告:
# - .next/analyze/client.html (客户端代码分析)
# - .next/analyze/server.html (服务端代码分析)

# 打开浏览器查看报告后,可以找出体积过大的依赖并优化
# 常见优化手段:
# 1. 动态导入: const HeavyComponent = dynamic(() => import('./HeavyComponent'))
# 2. 替换大体积库: moment → dayjs(缩小 95%)
# 3. Tree Shaking: import { Button } from 'antd' 代替 import { Button } from 'antd/es/button'

优化前后对比示例

指标 优化前 优化后 提升
首屏 JS 体积 285 KB 168 KB 减少 41%
Lighthouse 性能分 62 94 提升 32 分
TTFB(首字节时间) 420ms 180ms 减少 57%
构建时间 3m 12s 1m 45s 减少 45%
CDN 命中率 52% 95% 提升 43%

▶ 示例 4:GitHub Actions CI 流水线配置

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

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

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20]
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck
      - run: npm test -- --coverage
      - name: Upload coverage
        if: matrix.node-version == 20
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/

  build:
    needs: lint-and-test
    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 build
      - name: Check bundle size
        run: |
          SIZE=$(du -sk .next/static | cut -f1)
          echo "Bundle size: ${SIZE}KB"
          if [ "$SIZE" -gt 500 ]; then
            echo "⚠️ Bundle exceeds 500KB threshold"
          fi

▶ 示例 5:综合——Next.js 生产部署完整配置

YAML
# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

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

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

      - name: Install dependencies
        run: npm ci

      - name: Run linter
        run: npm run lint

      - name: Type check
        run: npx tsc --noEmit

      - name: Run tests
        run: npm test

      - name: Build application
        run: npm run build
        env:
          NEXT_PUBLIC_API_URL: ${{ vars.NEXT_PUBLIC_API_URL }}
          DATABASE_URL: ${{ secrets.DATABASE_URL }}

      - name: Run Lighthouse audit
        uses: treosh/lighthouse-ci-action@v12
        with:
          urls: |
            http://localhost:3000
          uploadArtifacts: true
          budgetPath: ./lighthouse-budget.json

      - 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'
          working-directory: ./

      - name: Notify deployment
        if: always()
        run: |
          STATUS="${{ job.status }}"
          curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
            -H 'Content-type: application/json' \
            -d "{\"text\":\"Deploy $STATUS on $(date -u +%Y-%m-%dT%H:%MZ)\"}"
JSON
// lighthouse-budget.json
[
  {
    "path": "/*",
    "options": { "first-contentful-paint": { "maxNumericValue": 2000 } },
    "budgets": [
      { "resourceSizes": [{ "resourceType": "script", "budget": 200 }, { "resourceType": "stylesheet", "budget": 50 }, { "resourceType": "image", "budget": 300 }, { "resourceType": "total", "budget": 600 }] }
    ]
  }
]

❓ 常见问题

Q Vercel 和传统服务器部署有什么区别?
A Vercel 是 Serverless 平台——不需要管理服务器,自动扩缩容,按请求计费,全球 CDN 加速,支持 Preview 部署。传统部署需要自己买服务器、配 Nginx、管理 SSL 证书、配置负载均衡。Vercel 更适合前端和全栈项目,传统部署适合需要自定义后端配置的场景。Vercel 的免费额度对个人项目完全够用。
Q 环境变量怎么在 Vercel 中配置?
A 在 Vercel Dashboard 中选择项目 -> Settings -> Environment Variables,可以按环境(Production/Preview/Development)分别配置。NEXT_PUBLIC_ 前缀的变量会被打包到浏览器端 JS 中,无前缀的变量只在服务端可用。在 GitHub Actions 中通过 secrets 传递敏感变量,工作流中通过 ${{ secrets.XXX }} 引用。
Q CI/CD 流程中测试失败了怎么处理?
A GitHub Actions 默认在测试失败时会终止后续 Job(deploy 不会执行)。可以在 PR 中查看 Actions 的运行日志排查失败原因。常见问题包括:测试环境变量缺失、Node.js 版本不一致、依赖安装失败。建议在本地先运行 npm test 确认通过后再 push。也可以配置 continue-on-error: true 让某些 Job 失败时继续执行。
Q 构建优化主要看哪些指标?
A 关注三个核心指标:首屏 JS 体积(<200KB 为佳)、Lighthouse 性能评分(>90 为佳)、TTFB 首字节时间(<200ms 为佳)。使用 @next/bundle-analyzer 分析每个依赖的打包体积,找出可以替换或动态导入的大体积库。图片优化通常是最容易见效的优化点——使用 next/image 自动生成 WebP 格式和响应式尺寸。
Q Vercel 免费额度够用吗?有限制吗?
A Hobby 计划免费额度:100GB 带宽/月、Serverless Function 执行时间 10s/次、1000 次/月的构建时长。个人博客和小项目完全够用。主要限制:Serverless Function 超时 10s(Pro 计划 60s)、不支持 ISR 按需刷新的批量操作、Preview 部署链接有效期 30 天。商业项目建议升级 Pro 计划($20/月)。

📖 小节


📝 作业

  1. 将你的 Next.js 项目推送到 GitHub 仓库,然后在 Vercel 中导入该项目(Import Git Repository)。观察自动部署流程,验证部署后的 Preview URL 和 Production URL 是否正确。在 Vercel Dashboard 中查看部署日志,理解构建过程的每个步骤。配置自定义域名(可选)并开启 HTTPS。
  2. 在项目中创建 .github/workflows/ci.yml,配置一个 CI 工作流:push 到任意分支时自动运行 npm ci -> npm run lint -> npm test -> npm run build。故意引入一个 lint 错误或测试失败,push 后观察 CI 是否失败并显示错误信息,然后修复错误确认 CI 通过。
  3. 为项目配置构建优化:使用 @next/bundle-analyzer 分析当前项目的包体积,找出体积最大的前 3 个依赖。对其中一个大体积组件实现动态导入(dynamic(() => import(...))),对比优化前后的 JS 体积变化。在 next.config.ts 中启用图片优化(配置 remotePatterns)和压缩配置。最后用 Chrome DevTools 的 Lighthouse 测试优化前后的性能分数,记录首屏 JS 体积和性能评分的提升幅度。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏