白嫖 GitHub 当流水线

前言

前段时间,笔者有个桌面端产品进入了快速迭代期,更新频率突然高了起来。

每次发版,我都得当"人肉流水线":

  1. 先在 Windows 电脑上跑一遍构建,打个 .exe 包。
  2. 然后再滚到 Mac 电脑上,再跑一遍,打个.dmg 包。
  3. 最后再吭哧吭哧手动传到服务器。

频繁更新几次后,我逐渐感到不对劲了:"都什么年代了,还在这儿玩'纯手工'?"

作为一个有追求的开发者,我意识到这样下去不行,至少 也得引入自动化构建, 不然每次构建十几二十分钟就浪费了。

我第一个想到的,就是 GitHub Actions。

为什么是 GitHub Actions ?

众所周知,GitHub 是赛博大善人。

任何仓库内都提供了强大的自动化构建功能,它能够直接提供多种系统的虚拟机作为运行环境,而且笔者的项目代码正好托管在 GitHub 上,这简直是最佳选择!

更重要的是,这个功能对公开和私有仓库都非常友好:对公开仓库是免费的,私有仓库也配有 2000 分钟的免费时长限额(帐号共享)。

它直接提供了三种系统的虚拟机:Ubuntu、windows、macOS

这非常适合我的需求(Windows 和 macOS 打包)。

别急着抄,先搞懂这 3 个"灵魂"配置

光会复制粘贴 AI 代码是不够的,你炼丹不得知道丹方的作用吗?代码也是,你最好知道每个重要配置项是什么作用的。

重点 1:strategy: matrix (并行构建)

YML 复制代码
strategy:
      fail-fast: false
      matrix:
        os: [macos-latest, windows-latest]

这是节省 Actions 资源的重要配置,因为 GitHub 是按虚拟机运行时间来计费的。

matrix: { os: [...] }:这是官方提供的"矩阵构建"。GitHub 看到这个,会同时启动两台虚拟机(一台 Mac,一台 Win),并行跑下面的所有 steps。

fail-fast: false:"防翻车"配置。 默认是 true,意思是一旦 Mac 挂了,Windows 也会被"连坐"干掉。改成 false 后,Mac 翻车了,Windows 照样跑它的,互不干扰。

重点 2:actions/cache@v4 (提速核心)

YML 复制代码
      - name: Cache npm and node_modules (macOS)
        if: matrix.os == 'macos-latest'
        uses: actions/cache@v4
        with:
          path: |
            ~/.npm
            node_modules
          key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json', 'bun.lock', 'bun.lockb') }}
          restore-keys: |
            ${{ runner.os }}-npm-

GitHub 虚拟机每次运行 Action 都是全新的,npm install 能慢死人。 actions/cache@v4 就是官方提供的缓存包,能把 node_modules 和 npm 缓存(~/.npm)打包存起来。

key 是"钥匙",用 lock 文件 的哈希值生成。

下次跑,如果 key 就一样,直接把缓存解压出来,npm ci 就能直接读缓存了 ⚡

重点 3:Upload Artifact (分包上传)

YML 复制代码
- name: Upload macOS ARM64 artifact
        if: matrix.os == 'macos-latest'
        uses: actions/upload-artifact@v4
        with:
          name: macos-arm64-dmg
          path: dist/electron/*-arm64.dmg

这是 Electron 项目的刚需。Mac 现在必须分 arm64(M 芯片)和 x64(Intel)。 我们用 path 通配符 *-arm64.dmg 来精确匹配,把它们分成不同的产物(Artifacts)上传,方便单独下载。

放一下笔者目前在用的配置

说实话,这玩意儿的配置项又多又杂。AI 写的也不一定好使,都得微调。(不过如果你对配置项很熟,可以在第一次 prompt 的时候就描述清楚关键词,这样后面改的工作量就少些)

笔者这里直接把我在用的 YAML 贴出来。这套配置改过几版,目前基本能用,**集成了"并行构建"、"防翻车"、"缓存提速"、"分包上传"**等玩意儿。

yml 复制代码
# 1. 'name': 这个 Action 在 GitHub UI 上显示的名字
name: 跨平台构建(macOS + Windows)

# 2. 'on': 触发这个 Action 的事件
on:
  # 2.0 自动触发:当 package.json 或任何锁文件变更时,在 main 分支上触发
  push:
    branches:
      - master  # 确保这是你要构建代码的分支
    paths:
      - 'package.json'
      - 'bun.lock'
  # 2.1 'workflow_dispatch': 允许你"手动"在 GitHub 网页上点按钮触发
  workflow_dispatch:
    # 2.1.1 'inputs': 定义手动触发时可以输入的参数
    inputs:
      # 2.1.1.1 'build_message': 定义一个叫 "build_message" 的输入框
      build_message:
        # 'description': 输入框旁边的提示文字
        description: "构建说明(可选)"
        # 'required': 是否必须填写 (false = 不必须)
        required: false
        # 'default': 留空时的默认值
        default: "手动触发跨平台构建"

# 3. 'jobs': 定义这个 Action 要跑的所有"任务" (可以有多个 job)
jobs:
  # 3.1 'build': 定义一个叫 "build" 的 job
  build:
    # 3.2 'strategy': 定义这个 job 的"策略" (比如并行、矩阵)
    strategy:
      # 3.2.1 'fail-fast': 关键配置!false = "防翻车"
      # 意思是,一个平台(Mac)挂了,另一个(Win)继续跑,别"连坐"
      fail-fast: false
      # 3.2.2 'matrix': "矩阵",核心。让 job 并行跑多次
      matrix:
        # 3.2.2.1 'os': 定义一个叫 'os' 的变量,它有两个值
        os: [macos-latest, windows-latest] # 这会导致 job 跑两次

    # 3.3 'runs-on': 指定 job 跑在哪台虚拟机上
    # '${{ matrix.os }}' 会动态读取矩阵里的值 (第一次是 macos, 第二次是 windows)
    runs-on: ${{ matrix.os }}

    # 3.4 'steps': 这个 job 要执行的"步骤" (按顺序执行)
    steps:
      # 3.4.1 'name': 步骤 1: "拉取代码" (UI上显示的名字)
      - name: Checkout code
        # 'uses': 使用一个"现成的" Action 插件 (来自市场)
        uses: actions/checkout@v4 # v4 是版本号

      # 3.4.2 'name': 步骤 2: "安装 Node.js 环境"
      - name: Setup Node.js
        # 'uses': 使用安装 Node.js 的插件
        uses: actions/setup-node@v4
        # 'with': 传给这个插件的参数
        with:
          # 'node-version': 指定 Node.js 的版本号 (锁死版本是好习惯)
          node-version: "20"

      # --- 缓存 node_modules (注释行,方便阅读) ---
      # 3.4.3 'name': 步骤 3: "缓存 (Mac)" (提速核心)
      - name: Cache npm and node_modules (macOS)
        # 'if': 条件判断,只在 'os' 变量是 'macos-latest' 时才跑这一步
        if: matrix.os == 'macos-latest'
        # 'uses': 使用缓存插件
        uses: actions/cache@v4
        with:
          # 'path': 要缓存的"路径" (Mac的npm缓存在 ~/.npm)
          path: |
            ~/.npm
            node_modules
          # 'key': 缓存的"钥匙" (用系统名+lock文件哈希值)
          key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
          # 'restore-keys': "备用钥匙",key 没命中时,会尝试捞最近的缓存
          restore-keys: |
            ${{ runner.os }}-npm-

      # 3.4.4 'name': 步骤 4: "缓存 (Windows)"
      - name: Cache npm and node_modules (Windows)
        # 'if': 只在 Windows 虚拟机上跑
        if: matrix.os == 'windows-latest'
        uses: actions/cache@v4
        with:
          # 'path': Windows 的 npm 缓存路径不一样,得分开写
          path: |
            ~\AppData\Roaming\npm-cache
            node_modules
          # 'key': 钥匙 (同上)
          key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
          # 'restore-keys': 备用钥匙 (同上)
          restore-keys: |
            ${{ runner.os }}-npm-

      # 3.4.5 'name': 步骤 5: "显示构建信息" (打日志,方便追溯)
      - name: Show build info
        # 'run': 自己跑 shell 命令
        run: |
          echo "🚀 触发平台 - ${{ matrix.os }}"
          echo "📝 构建说明: ${{ github.event.inputs.build_message }}" # 读取手动输入的 'build_message'
        # 'shell': 指定用哪个 shell 跑 (bash 通用性好)
        shell: bash

      # 3.4.6 'name': 步骤 6: "创建 .env 文件" (如果构建需要)
      - name: Create .env file (if needed)
        run: echo "NODE_ENV=production" > .env
        shell: bash

      # --- 使用 npm ci (注释行) ---
      # 3.4.7 'name': 步骤 7: "安装依赖" (专业姿势)
      - name: Install dependencies (npm)
        run: |
          # 'if': 检查 lock 文件在不在
          if [ -f "package-lock.json" ]; then
            # 'npm ci': 严格按 lock 文件安装 (CI环境首选,防灵异事件)
            npm ci --include=dev # '--include=dev' 顺便装 devDependencies
          else
            # 'npm install': 备用方案
            npm install
          fi
        shell: bash

      # 3.4.8 'name': 步骤 8: "执行构建"
      - name: Build application
        # 'run': 跑 package.json 里的 "build:ci" 脚本
        run: npm run build:ci
        # 'env': 注入"环境变量"
        env:
          NODE_ENV: production # 告诉脚本,这是生产环境
          CI: true # 告诉脚本,这是在 CI 里跑的

      # --- 检查构建产物 (注释行) ---
      # 3.4.9 'name': 步骤 9: "检查产物 (Mac)" (Debug神器)
      - name: List build output and check sizes (macOS)
        if: matrix.os == 'macos-latest'
        run: |
          # 'ls': 看看 'dist/electron' 目录里有啥 (|| echo... 是为了防止目录不存在时报错)
          echo "=== Build output (dist/electron) ==="
          ls -la dist/electron/ || echo "dist/electron/ not found"
          # 'find': 找找有没有超过 500MB 的"胖"文件 (防止把不该打的打进去了)
          find dist/ -type f -size +500M -exec ls -lh {} \; 2>/dev/null || echo "No oversized files found"
        shell: bash

      # 3.4.10 'name': 步骤 10: "检查产物 (Windows)"
      - name: List build output and check sizes (Windows)
        if: matrix.os == 'windows-latest'
        run: |
          echo "=== Build output (dist/electron) ==="
          ls -la dist/electron/ || echo "dist/electron/ not found"
          find dist/ -type f -size +500M -exec ls -lh {} \; 2>/dev/null || echo "No oversized files found"
        shell: bash

      # --- 分包上传 (注释行) ---
      # 3.4.11 'name': 步骤 11: "上传 Mac ARM64 包" (Electron 刚需)
      - name: Upload macOS ARM64 artifact
        if: matrix.os == 'macos-latest'
        # 'uses': 使用"上传产物"插件
        uses: actions/upload-artifact@v4
        with:
          # 'name': 上传后,在 UI 上显示的名字 (M 芯片)
          name: macos-arm64-dmg
          # 'path': 要上传的文件的路径 (用通配符 *)
          path: dist/electron/*-arm64.dmg
          # 'retention-days': 产物保留 7 天 (别占人家便宜太久)
          retention-days: 7

      # 3.4.12 'name': 步骤 12: "上传 Mac Intel 包"
      - name: Upload macOS Intel artifact
        if: matrix.os == 'macos-latest'
        uses: actions/upload-artifact@v4
        with:
          # 'name': Intel 芯片的包
          name: macos-intel-dmg
          path: dist/electron/*-x64.dmg
          retention-days: 7

      # 3.4.13 'name': 步骤 13: "上传 Windows 包"
      - name: Upload Windows artifacts
        if: matrix.os == 'windows-latest'
        uses: actions/upload-artifact@v4
        with:
          # 'name': Windows 的安装包
          name: windows-setup
          path: |
            dist/electron/*.exe
            dist/electron/*.exe.blockmap # blockmap 是增量更新用的,顺便传
          retention-days: 7

也可以看官方的快速启动教程

最后

从"人肉流水线"到"一键触发",其实就是一份 YAML 文件的距离。

对于有频繁构建烦恼、又不想掏钱买高额虚拟机的开发者来说,GitHub Actions 绝对是"赛博大善人"。

你可能会说,这 YAML 一百多行,谁记得住?

你不需要记住。

在 AI 时代,你只需要知道**"我需要一个带缓存、能防翻车、可以并行跑 Mac 和 Win 的 CI"**,然后把这个需求丢给 AI,让它给你出第一版配置。

我们的工作,已经从"埋头写"变成了"Review(审查)"。 理解上面那几个"灵魂"配置项,你就能轻松审查 AI 给你的 YAML 到底靠不靠谱。

快去试试吧,别再浪费时间"手动打包"啦!

相关推荐
用户90443816324604 小时前
《零代码基础也能 AI 创作?GPT+DALL・E 实战教程,10 分钟上手》
前端·github
Java陈序员5 小时前
完全开源!一款基于 SpringBoot + Vue 构建的社区平台!
vue.js·spring boot·github·社区
Empty_7778 小时前
Keepalived双机热备
linux·git·github
ada7_19 小时前
GitHub使用技巧——上传本地项目
github
yaocheng的ai分身21 小时前
Octoverse:AI 推动 TypeScript 登顶 #1,每秒都有新开发者加入 GitHub
llm·github
逛逛GitHub1 天前
3 天就斩获 20000 星!这个 GitHub 开源项目凭啥?
github
我们没有完整的家1 天前
技术速递|Playwright MCP 调试 Web 应用时,GitHub Copilot 生成断言脚本的实用方法
前端·github·copilot
ZYMFZ1 天前
Redis主从复制与哨兵集群
前端·git·github
Determined_man1 天前
本地idea项目push到GitHub失败
github