> 技术文档 > 自动化篇:用GitHub Actions打造你的“私人前端CI/CD流水线”

自动化篇:用GitHub Actions打造你的“私人前端CI/CD流水线”


自动化篇:用GitHub Actions打造你的“私人前端CI/CD流水线”

引子:那个让你成为“机器人”的重复性工作

作为工程师,我们热爱创造,热爱解决复杂的问题。但日常工作中,有相当一部分时间,却被一些高度重复、毫无创造性的“机器人”工作所占据:

  • 每次提交代码前,都得记得在本地运行一遍linttest,确保没有引入低级错误。
  • 当一个功能开发完成,准备发布时,你需要手动执行build命令,然后手动将产物上传到服务器,或者手动发布到NPM。
  • 在Code Review时,你无法确定同事提交的代码,是否真的能在干净的环境中跑通所有测试。

这些手动操作,不仅繁琐、耗时,更是错误的温床。你可能会忘记运行测试,可能会在上传文件时操作失误,可能会因为本地环境与线上环境的差异而导致部署失败。

我们需要一个真正的“机器人”,一个不知疲倦、绝对忠诚、严格执行指令的“自动化助理”,来把我们从这些重复性劳动中解放出来。这个“机器人”,就是CI/CD(持续集成/持续部署)

而在当今的开源世界,尤其是对于托管在GitHub上的项目来说,实现CI/CD的最佳工具,无疑就是GitHub Actions

GitHub Actions是GitHub官方推出的、深度集成在代码仓库中的自动化工作流服务。它允许你通过在仓库中添加一个简单的YAML配置文件,来响应各种GitHub事件(如push, pull_request),并在GitHub提供的虚拟服务器上,执行你预设的一系列命令。

今天,我们将一起动手,为我们之前在Monorepo中构建的项目,打造一条专属的、功能完备的CI/CD流水线。这条流水线将成为我们项目的“质量门卫”和“自动化发布官”。


第一幕:CI/CD的核心理念

在动手之前,我们先要理解CI/CD这两个词的含义。

  • 持续集成(Continuous Integration, CI)
    CI的核心思想是:频繁地、自动化地将所有开发者的代码变更,集成到主干分支中。
    每一次集成,都会自动触发构建和测试。这能让我们尽早地发现代码冲突和集成错误,避免问题被隐藏到项目后期,导致修复成本剧增。一个良好的CI流程,能确保主干分支的代码,在任何时候都处于一个“基本可用”的状态。

  • 持续部署(Continuous Deployment, CD)
    CD是CI的延伸。它的核心思想是:将通过了所有自动化测试的代码变更,自动地、安全地部署到生产环境。
    这意味着,从git push到代码上线,整个过程可以是完全自动化的,无需人工干预。这极大地加快了价值交付的速度,实现了真正的“小步快跑,快速迭代”。

我们今天的目标,是先完美地实现CI,并为CD打下基础。


第二幕:GitHub Actions的核心概念

要使用GitHub Actions,你需要了解几个核心概念。它们都在一个.yml文件中定义。

  • Workflow(工作流): 整个自动化过程的蓝图。一个仓库可以有多个工作流。每个工作流对应一个.yml文件。
  • Event(事件): 触发工作流运行的条件。比如on: [push, pull_request]就表示当有代码push或创建pull_request时,触发该工作流。
  • Job(任务): 一个工作流由一个或多个任务组成。一个任务是一系列在同一个虚拟环境(Runner)中运行的步骤。默认情况下,多个任务是并行执行的。
  • Runner(运行器): 执行任务的虚拟服务器。GitHub提供了多种预装好常用软件的虚拟环境(如ubuntu-latest, windows-latest, macos-latest)。
  • Step(步骤): 任务中的最小执行单元。一个步骤可以是一个shell命令(run: npm install),也可以是引用一个预设好的“动作”(uses: actions/checkout@v3)。
  • Action(动作): 一个可复用的、独立的代码单元,用来执行常见的、标准化的任务。比如actions/checkout这个动作,专门用来拉取你的仓库代码到虚拟环境中;actions/setup-node则专门用来安装指定版本的Node.js。

理解了这些,我们就可以开始编写我们的第一个Workflow文件了。


第三幕:实战!编写我们的CI流水线

我们的目标是创建一个CI流水线,它能在每次向main分支推送代码,或创建指向main分支的Pull Request时,自动完成以下检查:

  1. 拉取最新代码。
  2. 安装指定版本的Node.js和pnpm。
  3. 安装项目所有依赖。
  4. 运行代码风格检查(Lint)。
  5. 运行所有自动化测试。

步骤一:创建Workflow文件

在你的项目根目录下,创建.github/workflows/文件夹。然后,在其中创建一个名为ci.yml的文件。

.github/workflows/ci.yml

# 工作流的名称,会显示在GitHub的Actions页面name: CSDN Invisible App CI# 触发工作流的事件on: # 当向main分支push代码时触发 push: branches: [ main ] # 当创建或更新一个指向main分支的Pull Request时触发 pull_request: branches: [ main ]# 定义工作流中的所有任务jobs: # 我们定义一个名为\'build-and-test\'的任务 build-and-test: # 指定运行此任务的虚拟环境 runs-on: ubuntu-latest # 定义此任务的一系列步骤 steps: # 第一步:检出代码 # 使用官方的actions/checkout@v3动作,将仓库代码拉取到Runner中 - name: Checkout repository uses: actions/checkout@v3 # 第二步:安装pnpm # 使用官方的pnpm/action-setup动作 - name: Setup pnpm uses: pnpm/action-setup@v2 with: version: 8 # 指定pnpm版本 # 第三步:安装Node.js # 使用官方的actions/setup-node@v3动作 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: \'18\' # 指定Node.js版本 cache: \'pnpm\' # 关键!让pnpm的依赖被缓存,后续运行会更快 # 第四步:安装依赖 # \'run\'关键字用于执行shell命令 - name: Install dependencies run: pnpm install # 第五步:运行Lint检查 # 我们需要在根package.json中预先定义好\"lint\"脚本 - name: Run Lint run: pnpm lint # 第六步:运行测试 # 我们需要在根package.json中预先定义好\"test\"脚本 - name: Run Tests run: pnpm test

步骤二:在package.json中添加脚本

确保你的根package.json中,包含了CI流程需要用到的脚本:

// 根目录 /package.json{ \"scripts\": { \"lint\": \"eslint . --ext .ts,.tsx\", // 假设你配置了ESLint \"test\": \"vitest run\" // 使用\'vitest run\'而不是\'vitest\',确保在CI环境中能自动退出 }}

步骤三:提交并观察

现在,将.github/workflows/ci.yml和修改后的package.json提交到你的GitHub仓库。

然后,尝试创建一个新的分支,修改一些代码,再创建一个指向main分支的Pull Request。

神奇的事情发生了!

你会看到在你的Pull Request页面下方,出现了一个“Checks”区域。GitHub Actions已经自动检测到了你的ci.yml文件,并开始运行你定义的工作流。

你可以点击“Details”链接,实时地查看每一步的执行日志。

  • 如果所有步骤都成功执行(命令退出码为0),整个Job会成功,PR页面上会显示一个醒目的绿色对勾
  • 如果任何一步失败(比如Lint不通过,或某个测试用例失败),该步骤会立即中止,整个Job会失败,PR页面上会显示一个红色大叉

这条CI流水线,现在成为了你项目代码质量的“忠诚守卫”。任何不符合规范、破坏了既有功能的代码,都休想在无人察觉的情况下,被合并到主分支中。

第四幕:展望CD - 自动化部署

有了CI作为基础,实现CD就水到渠成了。我们可以再定义一个deploy.yml工作流,或者在ci.yml中增加一个新的deploy任务。

这个任务可以这样设计:

# 在ci.yml中增加一个deploy任务jobs: build-and-test: # ... 省略 ... deploy: # \'needs\'关键字表示,此任务必须在\'build-and-test\'成功后才能开始 needs: build-and-test runs-on: ubuntu-latest # \'if\'条件表示,仅当事件是向main分支push时才运行此任务 # (我们不希望每次PR都触发部署) if: github.event_name == \'push\' && github.ref == \'refs/heads/main\' steps: - name: Checkout repository uses: actions/checkout@v3 # ... 安装Node.js和pnpm的步骤 ... - name: Build all packages run: pnpm --recursive build - name: Publish to NPM # 这里会使用一个专门的action来发布到NPM # 需要配置NPM的认证token uses: JS-DevTools/npm-publish@v1 with: token: ${{ secrets.NPM_TOKEN }} # 从仓库的Secrets中读取token - name: Deploy to Server # 这里会使用一个action(如appleboy/ssh-action) # 通过SSH连接到你的服务器,并执行部署脚本 uses: appleboy/ssh-action@master with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USERNAME }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /var/www/my-app git pull pm2 restart my-app

这个deploy任务演示了如何在代码合并到主分支后,自动地构建项目、发布到NPM,并通过SSH连接到服务器来完成最终的部署。通过配置secrets,我们可以安全地管理各种敏感的认证信息。

结论:让机器人做机器人该做的事

GitHub Actions是一个极其强大的工具,它将复杂的CI/CD流程,简化为了编写一个声明式的YAML文件。

通过为我们的项目配置CI/CD流水线,我们获得了:

  1. 质量保证的自动化:每一次代码提交,都经过了严格的、一致的质量检查。
  2. 开发效率的提升:将开发者从重复的、易错的手动操作中解放出来,专注于创造性的工作。
  3. 更快的反馈循环:在代码合入主干前,就能发现潜在的问题,极大地降低了修复成本。
  4. 团队协作的规范化:CI/CD流程成为了团队统一的开发规范和质量基线。

掌握CI/CD和GitHub Actions,是每一位现代工程师必备的核心技能。它标志着你开始从一个只关心“代码实现”的开发者,向一个关注“软件交付全周期”的工程化专家转变。

在下一章,也是本系列的终章,我们将进行最后一次思想的升华。我们将探讨技术之外,那些真正决定一个工程师能走多远的终极软技能:编写“可被理解”的代码