feat(web): 官网 ui_kits/website → Astro 纯静态 SSG 迁移 (tsk_acMYQ-Z-EIF_)

新建 web/website/(Astro 零 SSR):

- 组件迁移:交互块保留 .jsx 经 @astrojs/react(Header/AnnouncementBar/SignupForm/PricingPlans),纯展示块转 .astro 去运行时 JS;像素以原型为基准。
- 令牌同源:build-tokens.mjs 从 design/colors_and_type.css 生成 tokens.gen.css,仅剔除第三方 Google Fonts @import,数值不改。
- 字体自托管:@fontsource(Sora/Manrope/Noto Sans SC/JetBrains Mono),无第三方 CDN。
- 图标:Lucide 构建期内联 SVG(替代 unpkg CDN),零运行时、零 CDN。
- i18n:/(zh)与 /en/(en)双路由单显,语言切换组件;文案沿用 ui_kits 脱敏文案。
- 安全:public/_headers 严格 CSP(全 self + 自托管资源 + 内联片段 sha256,无 unsafe-inline)+ HSTS;无支付表单。
- CI:.gitea/workflows/website.yml 构建(红线扫描+lint+CSP 哈希)→ 同时发布 Cloudflare Pages 主站与镜像。
- 灾备:README 写明干净环境 npm ci && npm run build 可直接部署到任意静态托管;dist 指纹确定性,主站镜像一致。

测试:npm run lint(0 error)/ npm test(build+CSP 哈希注入+红线扫描 0 命中)/ 两次干净构建 dist 指纹一致。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 14:26:40 +08:00
parent 787151245e
commit 4df8dc6f87
37 changed files with 9390 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
name: website
# 官网 CI/CDpush web/website/** → 构建(红线词扫描 + lint + CSP 哈希)→ 同时发布主站与镜像。
# 与仓库根 .gitea/workflows/ci.yml 解耦:官网完全静态、与后端无依赖,可独立并行。
#
# 需在 Gitea 配置 Secrets
# CF_API_TOKEN Cloudflare API TokenPages:Edit 权限)
# CF_ACCOUNT_ID Cloudflare Account ID
# CF_PAGES_PROJECT_MAIN 主站 Pages 项目名
# CF_PAGES_PROJECT_MIRROR 镜像 Pages 项目名(≥1 个活跃镜像,应对主域名被墙)
# 并把 runs-on 改成实际 runner label。
on:
push:
paths:
- 'web/website/**'
- '.gitea/workflows/website.yml'
pull_request:
paths:
- 'web/website/**'
workflow_dispatch:
env:
# 主站 canonical 域名;镜像也用同一值 → canonical 指向主站 + 产物 hash 一致。
SITE_URL: https://pangolin.example
jobs:
# ── 构建 + 校验(红线 / lint / CSP / 指纹) ──────────────────────────────
build:
name: Build & Verify
runs-on: nas
defaults:
run:
working-directory: web/website
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install (clean, reproducible)
run: npm ci
- name: Type-check (lint)
run: npm run lint
- name: Build (含 token 同源 + CSP 哈希注入)
run: npm run build
- name: Redline scan (脱敏铁律 13)
run: npm run scan:redline
- name: CSP sanity (禁止 unsafe-inline)
run: grep -L "unsafe-inline" dist/_headers
- name: Fingerprint (主站/镜像一致性基线)
run: npm run hash:dist | tee dist.fingerprint
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: website-dist
path: web/website/dist
# ── 同时发布主站与镜像(同一份 dist,hash 必然一致) ─────────────────────
deploy:
name: Deploy main + mirror
needs: build
if: github.event_name == 'push'
runs-on: nas
defaults:
run:
working-directory: web/website
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install
run: npm ci
- name: Build
run: npm run build
- name: Deploy → 主站 (Cloudflare Pages)
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
run: npx wrangler pages deploy dist --project-name "${{ secrets.CF_PAGES_PROJECT_MAIN }}" --branch main
- name: Deploy → 镜像 (Cloudflare Pages)
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
run: npx wrangler pages deploy dist --project-name "${{ secrets.CF_PAGES_PROJECT_MIRROR }}" --branch main
- name: Verify main == mirror (内容一致性)
run: |
echo "主站与镜像部署的是同一份 dist,指纹:"
npm run --silent hash:dist