跳转至
MIGRATED

Xisound 前端构建与部署拓扑 v1.0

文档定位

  • 上游:D3-FE-ARCH-001 顶层架构 §3 Monorepo 结构 · §6.4 构建与发布
  • 本文范围:Monorepo 构建工具链 + CI/CD 流水线 + 6 apps 的部署拓扑 + 域名规划 + 环境变量管理
  • 目标读者:DevOps 工程师 / 前端工程 Leader / SRE
  • 约束强度:C-07(packages SemVer)· C-09(统一版本)· DQ-04(XiVST 域名与账号体系)· DQ-06(Monorepo 位置)

1. 构建工具链总览

1.1 技术栈

选型 角色
包管理 pnpm 9+ workspace + 高效硬链接 + 严格依赖
构建编排 Turborepo 2+ 增量构建缓存 + 并行任务 + 远程缓存(可选)
app 构建 Vite 5+ 每个 app 独立 build
packages 构建 tsup(基础 package) / Vite lib mode(@xi/ui-kit) 产出 CommonJS + ESM + TypeScript 类型
版本管理 changesets 2+ 自动语义化版本 + CHANGELOG
Node 版本 Node 20 LTS .nvmrc 锁定
包管理器锁定 packageManager in root package.json 防止 npm/yarn 误用

1.2 pnpm-workspace.yaml

packages:
  - "apps/*"
  - "packages/*"
  - "tools/*"

1.3 root package.json 关键字段

{
  "name": "xi-platform",
  "private": true,
  "packageManager": "pnpm@9.0.0",
  "engines": {
    "node": ">=20.0.0",
    "pnpm": ">=9.0.0"
  },
  "scripts": {
    "dev": "turbo run dev --parallel",
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test",
    "type-check": "turbo run type-check",
    "changeset": "changeset",
    "version-packages": "changeset version",
    "release": "turbo run build --filter='./packages/*' && changeset publish"
  },
  "devDependencies": {
    "turbo": "^2.0.0",
    "@changesets/cli": "^2.27.0",
    "typescript": "^5.3.0",
    "vitest": "^1.6.0",
    "@playwright/test": "^1.59.0"
  }
}

1.4 turbo.json(构建编排)

{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "build/**"],
      "cache": true
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {
      "outputs": []
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"],
      "cache": true
    },
    "type-check": {
      "dependsOn": ["^build"],
      "outputs": []
    },
    "e2e": {
      "dependsOn": ["build"],
      "outputs": ["playwright-report/**", "test-results/**"]
    }
  }
}

1.5 本地开发命令

# 全量依赖安装
pnpm install

# 启动 xi-studio(依赖 forge/vst 组件热更新 + 所有 @xi/* packages)
pnpm -F xi-studio dev

# 同时启动多个 app(并行)
pnpm -F xi-studio dev & pnpm -F xi-tune dev

# 仅 build 特定 app + 其依赖
pnpm -F xi-tune build

# 全部 build
pnpm build

# 跑 xi-studio 的 e2e
pnpm -F xi-studio e2e

# 跑所有 workspace 的单测
pnpm test

2. CI/CD 流水线

2.1 推荐平台

首选 GitHub Actions(Xisound 代码已在 GitHub),次选 Azure DevOps Pipelines(企业合规需要时)。

2.2 核心 Pipeline 阶段

graph LR
    Push[Push/PR] --> Setup[setup node + pnpm]
    Setup --> Cache[restore turbo cache]
    Cache --> Install[pnpm install --frozen-lockfile]
    Install --> Lint[pnpm lint]
    Install --> TypeCheck[pnpm type-check]
    Install --> UnitTest[pnpm test]
    Lint --> BuildPkg[build packages]
    TypeCheck --> BuildPkg
    UnitTest --> BuildPkg
    BuildPkg --> BuildApps[build changed apps]
    BuildApps --> E2E[e2e tests]
    E2E --> Deploy{branch?}
    Deploy -->|main| Prod[Deploy to prod]
    Deploy -->|staging| Staging[Deploy to staging]
    Deploy -->|PR| Preview[Deploy preview]

2.3 GitHub Actions 样例(核心工作流)

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, staging]
  pull_request:

env:
  TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
  TURBO_TEAM: xisound

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2  # Turborepo 需要 diff

      - uses: pnpm/action-setup@v3
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm

      - run: pnpm install --frozen-lockfile

      - run: pnpm lint
      - run: pnpm type-check
      - run: pnpm test

      - run: pnpm build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-${{ github.sha }}
          path: |
            apps/*/dist
            packages/*/dist
          retention-days: 7

2.4 增量构建优化(Turborepo)

# Turbo 自动按 git diff 判断哪些 package/app 需要重建
# 未变更的 app 直接复用缓存(秒级 build)

# 示例:只改了 packages/ui-kit 的一个组件
# → Turbo 判定受影响的下游:xi-studio / xi-forge / xi-tune / xi-test / xi-probe
# → 其他仍未变更的 package 走缓存(build 命中 cache HIT)

# 启用远程缓存(Turbo 官方或自建 Redis):
# .turbo/config.json
{
  "teamId": "xisound",
  "remoteCache": { "enabled": true, "signature": true }
}

2.5 PR Preview 部署(Vercel 风格)

对每个 PR 自动部署 preview 环境:

  • xi-studio PR #42 → pr-42-xi-studio.xi-preview.xisound.com
  • xi-tune PR #42 → pr-42-xi-tune.xi-preview.xisound.com

实现方式:Cloudflare Pages / Vercel / Netlify 都原生支持;自建可用 GitHub Actions + Nginx 动态子域名。


3. 部署拓扑

3.1 域名规划(权威 · 对齐 DQ-04)

App 生产域名 Staging 开发环境
xi-studio studio.xisound.com studio-staging.xisound.com localhost:5173
xi-tune tune.xisound.com tune-staging.xisound.com localhost:5175
xi-test test.xisound.com test-staging.xisound.com localhost:5176
xi-probe probe.xisound.com probe-staging.xisound.com localhost:5177
xi-vst (Marketplace) marketplace.xisound.com + xvst.dev(国际域名可选) marketplace-staging.xisound.com localhost:5178
xi-vst (embedded) 走 studio.xisound.com 子路径 /algo-library/xivst
xi-forge 无独立域名(内嵌 xi-studio 的 /forge 路由) localhost:5174(独立 dev server 仅开发用)
docs (MkDocs) docs.xisound.com(或 docs.joysnd.com · 当前规划)
品牌站 xisound.com
开发者文档 dev.xisound.com / xvst.dev/docs
graph TB
    SSO[auth.xisound.com<br/>统一登录]
    SSO -.cookie: .xisound.com.-> Studio[studio.xisound.com]
    SSO -.cookie: .xisound.com.-> Tune[tune.xisound.com]
    SSO -.cookie: .xisound.com.-> Test[test.xisound.com]
    SSO -.cookie: .xisound.com.-> Probe[probe.xisound.com]
    SSO -.cookie: .xisound.com.-> MP[marketplace.xisound.com]
    class SSO xyL3

约定:

  • SSO Cookie Domain=.xisound.com(跨所有子域名共享)
  • HttpOnly + Secure + SameSite=Lax 默认
  • Tool Token(deep-link 用)走 URL 参数 · 不用 Cookie(防止 CSRF)
  • 国际域名(xvst.dev)需要独立 SSO 或 OAuth 集成

3.3 部署架构(Cloudflare Pages + 自建 Backend 方案)

graph TB
    subgraph EdgeCDN["Cloudflare Edge (CDN + DDoS + TLS)"]
        CDN[静态资源 CDN<br/>JS/CSS/Images]
        WAF[WAF + Rate Limit]
    end

    subgraph FrontendHost["Cloudflare Pages / Netlify"]
        Studio[studio.xisound.com]
        Tune[tune.xisound.com]
        Test[test.xisound.com]
        Probe[probe.xisound.com]
        MP[marketplace.xisound.com]
    end

    subgraph BackendVPS["VPS / Azure / AliCloud"]
        API[api.xisound.com<br/>C# ASP.NET Core]
        WS[ws.xisound.com<br/>WebSocket 服务]
        AuthSvc[auth.xisound.com<br/>认证服务]
        AISvc[ai.xisound.com<br/>XiMind 后端]
    end

    subgraph Storage["对象存储"]
        S3[xisound-assets<br/>S3/OSS/COS<br/>presets/wav/reports]
        AlgoRepo[xisound-algo-repo<br/>私有算法仓库]
    end

    User[用户浏览器] --> CDN
    CDN --> FrontendHost
    FrontendHost -.API calls.-> API
    FrontendHost -.WebSocket.-> WS
    FrontendHost -.Login.-> AuthSvc
    FrontendHost -.Copilot.-> AISvc
    API --> S3
    API --> AlgoRepo

    class CDN,WAF xyL3
    class Studio,Tune,Test,Probe,MP xyL2
    class API,WS,AuthSvc,AISvc xyL4
    class S3,AlgoRepo xyL0
    class EdgeCDN xySgL0; class FrontendHost xySgL4; class BackendVPS xySgL3; class Storage xySgL1;

3.4 Nginx/Cloudflare 配置要点

SPA fallback(必需)

# /etc/nginx/sites-available/studio.xisound.com
server {
    server_name studio.xisound.com;
    root /var/www/xi-studio/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;   # SPA fallback · history mode 路由必需
    }

    # 静态资源长缓存(hash in filename)
    location /assets/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # index.html 不缓存
    location = /index.html {
        add_header Cache-Control "no-cache";
    }

    # API 反向代理(同域名避免 CORS)
    location /api/ {
        proxy_pass https://api.xisound.com/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # WebSocket 反向代理
    location /ws/ {
        proxy_pass https://ws.xisound.com/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600s;
    }
}

Cloudflare Page Rules(如果用 CF Pages)

  • studio.xisound.com/assets/* → Cache Level: Cache Everything · Edge TTL: 1 year
  • studio.xisound.com/* → Cache Level: Bypass(动态内容)
  • *.xisound.com/api/* → Cache Level: Bypass

3.5 XiVST Marketplace 特殊说明(SEO 需求)

问题:SPA 默认对 SEO 不友好(搜索引擎抓取到空 HTML)

方案:

  • Y1 方案:用 vite-ssg(静态预渲染)生成 Marketplace 页面的 HTML 快照
  • Y2 方案:如流量大且需动态 SEO,改用 Nuxt 3 做 SSR
  • Dev Docs(xvst.dev/docs):用 MkDocs MaterialVitePress 静态生成

实现要点(vite-ssg):

// apps/xi-vst/marketplace/vite.config.ts
import { defineConfig } from 'vite'
import { ViteSSG } from 'vite-ssg/plugin'

export default defineConfig({
  plugins: [ViteSSG({
    includedRoutes: (paths, routes) => {
      // 预渲染路由列表(landing + 热门 plugin 详情)
      return [...paths, ...topPlugins.map(p => `/plugin/${p.slug}`)]
    }
  })]
})

4. 环境变量与密钥管理

4.1 分层

xi-platform/
├── .env                      # 不提交 · 本地兜底
├── .env.example              # 提交 · 示例值
├── apps/
│   ├── xi-studio/
│   │   ├── .env.development  # 开发环境默认
│   │   ├── .env.staging      # Staging
│   │   └── .env.production   # 生产(CI 注入 · 不提交真实值)

4.2 变量命名规范

前缀 用途
VITE_XI_API_BASE 后端 API 地址(浏览器可见)
VITE_XI_WS_URL WebSocket 地址
VITE_XI_SSO_URL SSO 服务地址
VITE_XI_AI_ENDPOINT XiMind 后端
VITE_XI_SENTRY_DSN Sentry 错误上报(可选)
VITE_XI_FEATURE_FLAGS Feature toggle JSON

关键约束:

  • 所有浏览器运行时变量必须以 VITE_ 开头(Vite 要求)
  • 密钥(API Key / JWT Secret / Sentry Auth Token)必须在 CI 注入,禁止写入 repo
  • 使用 GitHub Secrets / Azure Key Vault / HashiCorp Vault 管理

4.3 密钥清单

密钥 存放位置 使用方
SSO_JWT_SECRET Backend Vault 后端签发 JWT
XIMIND_API_KEY Backend Vault 后端调用 AI 上游
CLOUDFLARE_API_TOKEN GitHub Secrets CI 部署
TURBO_TOKEN GitHub Secrets Turborepo 远程缓存
SENTRY_AUTH_TOKEN GitHub Secrets 上传 sourcemap
NPM_REGISTRY_TOKEN GitHub Secrets 私有 packages 发布(Y2+)

5. 版本发布流程

5.1 Packages 版本(@xi/* 内部库)

# 开发者修改 package 后
pnpm changeset
# → 交互式选择受影响 packages + 语义版本(major/minor/patch)+ 填写变更描述

# 提交 changeset 文件到 PR(不直接改版本号)
git add .changeset/*.md && git commit

# merge 到 main 后 CI 自动执行:
pnpm changeset version   # 根据积累的 changeset 汇总计算新版本 + 生成 CHANGELOG
pnpm build --filter='./packages/*'
pnpm changeset publish    # 发布到私有 npm(Y2+) 或仅本地滚动(Y1)

5.2 Apps 版本

  • 不发布到 npm(都是最终应用)
  • 每次 main 分支合并触发 CI 自动部署到 staging
  • 手动 tag v{app}-{version} 触发 prod 部署(如 v-xi-studio-1.0.0)

5.3 Apps 独立发布节奏

约束 说明
独立版本号 每个 app 维护独立 SemVer · xi-studio@1.0.0xi-tune@0.9.0 解耦
packages 通过 workspace:* 引用 app build 时会固化到具体版本
跨 app 破坏性变更 如 @xi/protocol 发 major 版本 · 所有依赖 app 同批次升级
回滚 每次 prod 部署生成不可变 snapshot · 支持秒级回滚

6. 监控与可观测

6.1 错误追踪(Sentry)

// apps/xi-studio/src/main.ts
import * as Sentry from '@sentry/vue'
import { app } from './App.vue'

if (import.meta.env.PROD) {
  Sentry.init({
    app,
    dsn: import.meta.env.VITE_XI_SENTRY_DSN,
    environment: import.meta.env.MODE,
    release: `xi-studio@${__APP_VERSION__}`,
    integrations: [new Sentry.BrowserTracing()],
    tracesSampleRate: 0.1,  // 采样率
  })
}

6.2 前端性能指标(Web Vitals)

上报到后端 /api/telemetry/vitals(聚合到 Prometheus/Grafana):

  • LCP(Largest Contentful Paint)< 2.5s
  • FID(First Input Delay)< 100ms
  • CLS(Cumulative Layout Shift)< 0.1
  • 自定义业务指标:LinkEditor 打开时间 / Signal Flow 渲染帧率 / Copilot 首字节

6.3 日志策略

  • 浏览器端仅 console.error 上报到 Sentry
  • 避免 console.log 在生产暴露敏感信息(PII)
  • CI 阶段用 ESLint 规则 no-console 限制(仅允许 warn/error)

7. DQ 清单

DQ 编号 问题 建议
DQ-DEPLOY-01 是否全部走 Cloudflare Pages,还是自建 Nginx + VPS 前端用 CF Pages(免运维)· 后端 API/WS 自建 VPS(已 M6.2 完成)
DQ-DEPLOY-02 海外用户加速(EMEA/US) CF CDN 天然覆盖 · 无需额外部署
DQ-DEPLOY-03 私有化部署包(Tier1 IT 合规要求) Y2 提供 Docker Compose 全栈镜像 · 文档单独出
DQ-DEPLOY-04 Tauri 桌面版的分发(XiProbe Y2) macOS 走 DMG + 自家签名 · Windows 走 MSIX + 代码签名 · 更新走 Tauri updater
DQ-DEPLOY-05 changesets 自动 release 是否启用 GitHub Action changesets/action 推荐启用 · 免手动 tag

8. 版本与变更记录

版本 日期 作者 说明
v1.0 2026-05-08 work-cline 初稿 · Monorepo 构建工具链 + CI/CD + 部署拓扑 + 域名规划 + 环境变量 + 监控

附录 A · 引用