Files
opencode/skill/gitea/workflow-templates/nodejs-frontend.md
Voson 5a05d5ab53 chore: 重构 OpenCode 命令和技能文档体系
- 新增:统一的 git 命令文档(add/commit/push/pull 等)
- 新增:整合的 Gitea 技能文档(API、运行器、工作流等)
- 新增:工作流模板(Android、Go、Node.js 等)
- 移除:已弃用的旧命令脚本和发布脚本
- 改进:.gitignore 添加敏感文件保护规则
- 改进:AGENTS.md 完善了开发规范和示例

此次重组统一了命令和技能的文档结构,便于后续维护和扩展。
2026-01-13 00:27:21 +08:00

9.8 KiB
Raw Blame History

Node.js 前端 Workflow 模板

适用于 Node.js 前端项目的 CI/CD workflow支持 React、Vue、Vite、Next.js 等框架。

适用场景

  • React / Vue / Angular 前端项目
  • Vite / Webpack 构建的 SPA
  • Next.js / Nuxt.js SSR 应用
  • 需要构建 Docker 镜像的前端项目

环境要求

依赖 Runner 要求
Node.js 20+ Runner 主机已安装
pnpm / npm Runner 主机已安装或动态安装
Docker Runner 主机已安装

Workflow 骨架模板

name: Web Frontend - Build & Publish

on:
  push:
    paths:
      - 'web/**'                            # 修改为实际目录
      - '.gitea/workflows/web.yml'
    tags:
      - 'web-*'                             # 修改为实际 tag 前缀

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  SERVICE_PREFIX: web                       # 修改为实际服务名
  SERVICE_DIR: web                          # 修改为实际目录名
  NPM_REGISTRY: https://registry.npmmirror.com

jobs:
  build-and-publish:
    name: Build & Publish
    runs-on: darwin-arm64
    permissions:
      contents: read
      packages: write
    
    outputs:
      git_tag: ${{ steps.vars.outputs.git_tag }}
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Verify Node.js environment
        run: |
          node --version
          npm --version

      - name: Set up pnpm
        run: |
          npm config set registry ${{ env.NPM_REGISTRY }}
          npm install -g pnpm@latest-10

      - name: Get pnpm-hashfiles
        id: hash-pnpm
        working-directory: ${{ env.SERVICE_DIR }}
        run: |
          HASH=$(sha256sum package.json pnpm-lock.yaml 2>/dev/null | sha256sum | awk '{print $1}' | head -c 16)
          echo "hash=${HASH}" >> $GITHUB_OUTPUT

      - name: Cache pnpm modules
        uses: https://github.com/actions/cache@v3
        with:
          path: |
            ~/.local/share/pnpm/store
            ~/.pnpm-store
            ${{ env.SERVICE_DIR }}/node_modules
          key: pnpm-${{ env.SERVICE_PREFIX }}-${{ steps.hash-pnpm.outputs.hash }}
          restore-keys: pnpm-${{ env.SERVICE_PREFIX }}-

      - name: Set variables
        id: vars
        run: |
          git_tag=$(git describe --tags --abbrev=0 --always)
          registry=$(echo ${{ github.server_url }} | cut -d '/' -f 3)
          image_repo="${{ github.event.repository.name }}"
          
          {
            echo "git_tag=${git_tag}"
            echo "registry=${registry}"
            echo "image_repo=${image_repo}"
            echo "latest_tag=${{ env.SERVICE_PREFIX }}-latest"
          } >> $GITHUB_ENV
          
          echo "git_tag=${git_tag}" >> $GITHUB_OUTPUT

      - name: Install & Build
        working-directory: ${{ env.SERVICE_DIR }}
        env:
          NODE_ENV: production
          # ============================================
          # 用户自定义环境变量(按项目需求修改)
          # ============================================
          # VITE_API_URL: https://api.example.com
          # VITE_APP_TITLE: My App
          # NEXT_PUBLIC_API_URL: https://api.example.com
        run: |
          # 安装依赖
          pnpm install --frozen-lockfile
          
          # ============================================
          # 用户自定义构建步骤(按项目需求修改)
          # ============================================
          
          # 类型检查(按需启用)
          # pnpm run typecheck
          # pnpm run lint
          
          # 构建(必须)
          pnpm run build

      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: ${{ env.SERVICE_PREFIX }}-dist
          path: ${{ env.SERVICE_DIR }}/dist

      - name: Docker - Login
        uses: docker/login-action@v3
        with:
          registry: ${{ env.registry }}
          username: ${{ vars.REGISTRY_USERNAME }}
          password: ${{ secrets.REGISTRY_PASSWORD }}

      - name: Docker - Setup Buildx
        uses: docker/setup-buildx-action@v3

      - name: Docker - Build & Push
        uses: docker/build-push-action@v6
        with:
          context: ./${{ env.SERVICE_DIR }}
          file: ./${{ env.SERVICE_DIR }}/Dockerfile
          push: true
          platforms: linux/amd64
          tags: |
            ${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.latest_tag }}
            ${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.git_tag }}
          cache-from: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache
          cache-to: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache,mode=max

      - name: Notify
        if: always()
        continue-on-error: true
        env:
          WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
        run: |
          status="${{ job.status }}"
          [ "$status" = "success" ] && status_text="Build Success" || status_text="Build Failed"
          
          curl -s -H "Content-Type: application/json" -X POST -d \
            "{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.image_repo }}-${{ env.SERVICE_PREFIX }} ${status_text}\"}}" \
            "$WEBHOOK_URL" || true

  release:
    name: Create Release
    runs-on: darwin-arm64
    needs: build-and-publish
    if: startsWith(github.ref, 'refs/tags/')
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Download artifact
        uses: actions/download-artifact@v3
        with:
          name: ${{ env.SERVICE_PREFIX }}-dist
          path: dist

      - name: Create Release
        env:
          GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
        run: |
          git_tag=$(git describe --tags --abbrev=0)
          api_url="${{ github.server_url }}/api/v1"
          repo="${{ github.repository }}"
          
          # 打包构建产物
          cd dist
          zip -r "${{ env.SERVICE_PREFIX }}-dist.zip" .
          sha256sum "${{ env.SERVICE_PREFIX }}-dist.zip" > "${{ env.SERVICE_PREFIX }}-dist.zip.sha256"
          cd ..
          
          # 创建 Release
          release_id=$(curl -s -X POST \
            -H "Authorization: token $GITEA_TOKEN" \
            -H "Content-Type: application/json" \
            -d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag}\"}" \
            "${api_url}/repos/${repo}/releases" | jq -r '.id')
          
          # 上传附件
          curl -s -X POST \
            -H "Authorization: token $GITEA_TOKEN" \
            -F "attachment=@dist/${{ env.SERVICE_PREFIX }}-dist.zip" \
            "${api_url}/repos/${repo}/releases/${release_id}/assets"

Dockerfile 模板

静态文件部署Nginx

FROM nginx:alpine

# 复制构建产物
COPY dist /usr/share/nginx/html

# 复制 nginx 配置(可选)
# COPY nginx.conf /etc/nginx/conf.d/default.conf

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1

EXPOSE 80

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

SPA 路由配置nginx.conf

server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # SPA 路由支持
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 静态资源缓存
    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-store, no-cache, must-revalidate";
    }
}

缓存配置

pnpm 缓存路径

path: |
  ~/.local/share/pnpm/store    # pnpm 全局存储
  ~/.pnpm-store                # 备选路径
  web/node_modules             # 项目依赖

npm 缓存路径

path: |
  ~/.npm
  web/node_modules

Key 计算

# pnpm
HASH=$(sha256sum package.json pnpm-lock.yaml | sha256sum | awk '{print $1}' | head -c 16)

# npm
HASH=$(sha256sum package.json package-lock.json | sha256sum | awk '{print $1}' | head -c 16)

包管理器选择

pnpm推荐

- name: Set up pnpm
  run: |
    npm install -g pnpm@latest-10
    
- name: Install dependencies
  run: pnpm install --frozen-lockfile

npm

- name: Install dependencies
  run: npm ci

yarn

- name: Set up yarn
  run: npm install -g yarn

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

环境变量注入

Vite

env:
  VITE_API_URL: https://api.example.com
  VITE_APP_TITLE: My App

Next.js

env:
  NEXT_PUBLIC_API_URL: https://api.example.com

Vue CLI / CRA

env:
  VUE_APP_API_URL: https://api.example.com
  REACT_APP_API_URL: https://api.example.com

Secrets 配置

Secret 用途
REGISTRY_PASSWORD Docker Registry 密码
RELEASE_TOKEN Gitea API 令牌(创建 Release

常见构建命令

根据项目使用的框架,在 Build 步骤中添加相应的命令:

框架 构建命令
Vite pnpm run build
Next.js pnpm run build
Nuxt.js pnpm run generatepnpm run build
Vue CLI pnpm run build
CRA npm run build

使用步骤

  1. 复制上方 workflow 模板到 .gitea/workflows/web.yml
  2. 修改 SERVICE_PREFIXSERVICE_DIR 为实际值
  3. 修改 pathstags 触发条件
  4. 根据项目需求配置环境变量
  5. 创建 Dockerfile 文件
  6. 配置 Secrets
  7. 推送代码触发 workflow

版本发布

# 创建并推送 tag
git tag web-1.0.0
git push origin web-1.0.0