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

398 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 骨架模板
```yaml
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
```dockerfile
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
```nginx
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 缓存路径
```yaml
path: |
~/.local/share/pnpm/store # pnpm 全局存储
~/.pnpm-store # 备选路径
web/node_modules # 项目依赖
```
### npm 缓存路径
```yaml
path: |
~/.npm
web/node_modules
```
### Key 计算
```bash
# 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推荐
```yaml
- name: Set up pnpm
run: |
npm install -g pnpm@latest-10
- name: Install dependencies
run: pnpm install --frozen-lockfile
```
### npm
```yaml
- name: Install dependencies
run: npm ci
```
### yarn
```yaml
- name: Set up yarn
run: npm install -g yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
```
---
## 环境变量注入
### Vite
```yaml
env:
VITE_API_URL: https://api.example.com
VITE_APP_TITLE: My App
```
### Next.js
```yaml
env:
NEXT_PUBLIC_API_URL: https://api.example.com
```
### Vue CLI / CRA
```yaml
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 generate``pnpm run build` |
| Vue CLI | `pnpm run build` |
| CRA | `npm run build` |
---
## 使用步骤
1. 复制上方 workflow 模板到 `.gitea/workflows/web.yml`
2. 修改 `SERVICE_PREFIX``SERVICE_DIR` 为实际值
3. 修改 `paths``tags` 触发条件
4. 根据项目需求配置环境变量
5. 创建 `Dockerfile` 文件
6. 配置 Secrets
7. 推送代码触发 workflow
---
## 版本发布
```bash
# 创建并推送 tag
git tag web-1.0.0
git push origin web-1.0.0
```