第 14 章:CI/CD (GitHub Actions & Vercel)
欢迎来到第六部分:DevOps 与质量保障。在前面的章节中,我们已经构建了一个功能完备的 SAAS 应用,涵盖了从数据库 (Drizzle)、认证 (better-auth)、支付 (Stripe) 到运营 (React Email) 的所有核心功能。现在,是时候确保我们能安全、可靠、快速地将这些功能交付给我们的...
第 14 章:CI/CD (GitHub Actions & Vercel)
欢迎来到第六部分:DevOps 与质量保障。在前面的章节中,我们已经构建了一个功能完备的 SAAS 应用,涵盖了从数据库 (Drizzle)、认证 (better-auth)、支付 (Stripe) 到运营 (React Email) 的所有核心功能。现在,是时候确保我们能安全、可靠、快速地将这些功能交付给我们的用户了。
对于来自 Python (Django/Flask) 背景的开发者来说,"部署"一词可能意味着一系列复杂的手动或半自动操作:配置 Nginx、Gunicorn/uWSGI、设置 systemd 服务、管理 VPS 上的环境变量、运行 manage.py collectstatic、手动执行数据库迁移…… 这是一个脆弱且耗时的过程。
Next.js 和 Vercel 生态将这个模型彻底颠覆了。本章,我们将探讨现代全栈应用的 DevOps 流程,并展示如何利用 Vercel 和 GitHub Actions 打造一个既能一键部署,又具备企业级质量保障的 CI/CD 流水线。
14.1. Vercel:从 Git 到全球部署
Vercel (Next.js 的母公司) 的核心价值主张是:为现代 Web 优化的、从 Git 开始的无缝部署体验。
你所需要做的就是:
- 在 Vercel 平台上创建一个新项目。
- 将其链接到你的 GitHub (或 GitLab/Bitbucket) 仓库。
完成!从这一刻起,Vercel 会自动为你处理一切:
- 自动构建与部署:当你
git push到main(或master) 分支时,Vercel 会自动拉取代码,检测到它是一个 Next.js 15+ 项目,执行pnpm build,并将其部署到其全球边缘网络 (Edge Network)。 - 全球 CDN:你的静态资产 (JS, CSS, 图片) 会自动缓存在全球 CDN 上,用户从最近的节点访问。
- Serverless Functions:你的 Server Actions 和 Route Handlers (API 路由) 会自动部署为 Serverless Functions (或 Vercel 的 Edge Functions),实现弹性伸缩。
- 数据缓存:Vercel 的基础架构与 Next.js 的数据缓存(Data Cache)深度集成。
- 预览部署 (Preview Deployments):这是 Vercel 的“杀手级功能”。当你就任何分支(例如
feat/new-dashboard)创建一个 Pull Request (PR) 时,Vercel 会自动为这个 PR 构建并部署一个独立的预览环境。你会得到一个唯一的 URL (例如my-saas-pr-123.vercel.app),你可以将其分享给团队成员、设计师、产品经理进行审查。这彻底消除了“在我机器上是好的”这一古老难题。
这种 "GitOps" 模式对于 Python 开发者来说是一种思维转变。你不再需要管理服务器,你只需要管理你的 Git 仓库。Vercel 处理了从代码到全球部署之间的所有繁杂工作。
14.2. [深度] 企业级 CI/CD 流水线
Vercel 的默认流程(main 分支 -> 生产)非常适合小型项目,但对于一个严肃的、有付费用户的 SAAS 应用来说,这还不够。我们不能允许任何未经验证的代码直接合并到 main 并立即部署到生产环境。
我们需要质量保障 (Quality Assurance)。我们需要一个部署门禁 (Deployment Gate)。
这就是 GitHub Actions (CI) 与 Vercel (CD) 协同工作的地方。
- CI (Continuous Integration - 持续集成):由 GitHub Actions 负责。其职责是验证代码质量。它在代码被_允许_部署_之前_运行。
- CD (Continuous Deployment - 持续部署):由 Vercel 负责。其职责是构建和交付应用。
一个企业级的 CI/CD 流水线如下所示:
- 开发 (Dev):开发者在本地创建一个新分支,例如
feat/improve-checkout。 - 推送 (Push):开发者向 GitHub 推送该分支。
- CI 运行 (Feature Branch):GitHub Actions 自动检测到推送,并在该分支上运行一个 CI 作业(见 14.3 节),该作业执行:
pnpm install(安装依赖)pnpm lint(使用 Biome 检查代码风格和错误)pnpm typecheck(使用 TypeScript 编译器检查类型)pnpm test(运行单元测试和集成测试)
- 拉取请求 (Pull Request):CI 通过后,开发者创建一个 PR,请求将
feat/improve-checkout合并到main。 - 预览部署 (Vercel CD):Vercel 立即检测到这个 PR,为
feat/improve-checkout分支构建一个预览部署,并在 PR 评论中发布一个可访问的 URL。 - CI 运行 (PR):GitHub Actions 再次在 PR 上下文中运行所有检查,并将“通过/失败”状态报告给 PR。这是合并的强制门禁。
- 审查 (Review):
- 代码审查:团队其他成员审查代码。
- 功能审查:产品经理和 QA(质量保障)人员点击 Vercel 提供的预览 URL,在真实环境中手动测试新功能。
- 合并 (Merge):所有检查通过、审查批准后,PR 被合并到
main分支。 - 生产部署 (Vercel CD):Vercel 检测到
main分支有新的提交,自动触发生产部署。 - 上线 (Live):几分钟后,你的新功能就在全球范围内上线了。
在这个流程中,GitHub Actions 充当了“守门员”,确保了只有高质量的代码才能进入 main 分支;而 Vercel 充当了“快递员”,负责将代码安全、快速地交付给用户(无论是预览环境还是生产环境)。
14.3. [代码解析]:配置 GitHub Actions
要实现 14.2 节中的 CI 流程,我们只需要在项目根目录中添加一个 .github/workflows/ci.yml 文件。
文件 1:.github/workflows/ci.yml
这个 YAML 文件定义了我们的“守门员”需要执行的所有步骤。
# .github/workflows/ci.yml
name: CI Checks # 工作流的名称
# 1. 触发条件
on:
# 在推送到任何分支时触发 (用于特性分支)
push:
branches:
- "**" # 匹配所有分支
- "!main" # 但排除 main, 因为 main 由 Vercel 处理
# 在创建或更新 Pull Request 时触发 (用于合并门禁)
pull_request:
branches:
- main # 只关心目标是 main 分支的 PR
# 2. 作业定义
jobs:
# 我们定义一个名为 'ci' 的作业
ci:
# 运行环境:使用最新的 Ubuntu
runs-on: ubuntu-latest
# 3. 步骤
steps:
# 第 1 步:检出代码
- name: Checkout code
uses: actions/checkout@v4
# 第 2 步:安装 pnpm
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8 # 指定 pnpm 版本
# 第 3 步:安装 Node.js (例如 20.x)
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm' # 自动为 pnpm 设置缓存,加快后续构建速度
# 第 4 步:安装依赖
# 使用 --frozen-lockfile 确保 CI 使用与 pnpm-lock.yaml 完全一致的依赖
- name: Install dependencies
run: pnpm install --frozen-lockfile
# 第 5 步:运行 Lint (使用 Biome)
# 检查代码格式和潜在错误
- name: Run Lint (Biome)
run: pnpm lint
# 第 6 步:运行类型检查 (TypeScript)
# --noEmit 只检查类型,不生成 JS 文件
- name: Run Typecheck (TypeScript)
run: pnpm typecheck
# 第 7 步:运行测试 (例如 Vitest)
# 你的 'test' 脚本应该配置为在 CI 模式下运行 (例如,非 watch 模式)
- name: Run Tests
run: pnpm test --ci配置解析:
on: [push, pull_request]:我们同时在push和pull_request时触发。push覆盖了所有特性分支的即时反馈,而pull_request是合并到main之前的最终门禁。uses: pnpm/action-setup@v3和uses: actions/setup-node@v4:这是配置 pnpm 和 Node.js 环境的最佳实践。cache: 'pnpm':这一行至关重要。它会自动缓存pnpm store,这意味着 GitHub Actions 无需在每次运行时都重新下载所有依赖包,大大加快了 CI 的执行速度(通常从几分钟缩短到 30 秒内)。pnpm lint,pnpm typecheck,pnpm test:这些命令对应我们package.json中定义的脚本。任何一个脚本如果失败(返回非零退出码),整个 CI 作业都会失败,GitHub 会阻止 PR 的合并(如果你在仓库设置中开启了“分支保护规则”)。
第 14 章总结
在本章中,我们为我们的 SAAS 应用构建了现代化的 DevOps 基础设施。
- 思维转变:我们告别了 Python 栈中复杂的手动部署,转向了 Vercel 提供的 GitOps 工作流。Vercel 将 Git 仓库作为“事实的单一来源”,自动处理从代码到全球部署的一切。
- 企业级流程:我们认识到 Vercel 的默认部署虽然简单,但缺乏质量保障。因此,我们设计了一个企业级 CI/CD 流水线,将 GitHub Actions 和 Vercel 的优势结合起来。
- CI/CD 协同:我们明确了职责分离:GitHub Actions (CI) 充当“守门员”,通过
lint、typecheck和test来保障代码质量;Vercel (CD) 充当“快递员”,负责构建和交付预览部署(用于审查)和生产部署(用于上线)。 - 代码实现:我们编写了一个
.github/workflows/ci.yml文件,它利用了 pnpm 缓存,高效地在每次提交和 PR 时运行我们的质量检查。
通过这个流程,我们实现了 Next.js/Vercel 承诺的“快速开发”,同时又增加了传统 DevOps 所要求的“安全与可靠”。
更多文章
第 22 章:总结:成为 Next.js 全栈架构师
如果你从第一章开始一路跟随,你已经完成了一次意义非凡的跨越:从一名经验丰富的 Python 后端开发者,转变为一名能够驾驭现代 JavaScript 生态的全栈架构师。
第 8 章:SAAS 认证:Auth 方案对比
在第 7 章中,我们选择了 ORM 路径,决定使用 Drizzle 来掌控我们的数据库。这个决定会直接影响我们的认证(Authentication)方案。
第 2 章:TypeScript:SAAS 项目的 "架构契约" (vs. Mypy)
在第一章中,我们了解了 Node.js 异步的““哲学””。现在,我们来谈谈 JavaScript 生态的““安全带””:TypeScript (TS)。