# Monorepo 多站点架构设计方案 ## 背景 当企业需要为多个产品/项目创建独立展示时,面临架构选择:**单独页面** vs **独立网站**。 经过需求分析,确定以下约束条件: | 维度 | 需求 | 架构影响 | |------|------|----------| | 产品数量 | 动态增长,未来持续增加 | 需要高可扩展性 | | 品牌关系 | 独立子品牌 | 需要视觉独立性 | | 团队规模 | 1-2人精简团队 | 需要低维护成本 | | SEO要求 | 高要求,独立域名 | 需要独立部署能力 | ## 方案对比 ### 方案A:独立网站(多仓库) ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 产品A (独立仓库) │ │ 产品B (独立仓库) │ │ 产品C (独立仓库) │ │ product-a.com │ │ product-b.com │ │ product-c.com │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` **优点**:完全独立、SEO最优、互不影响 **缺点**:❌ 维护成本极高、代码重复严重、安全更新繁琐 ### 方案B:单站内嵌页面 ``` ┌──────────────────────────────────────────────────────┐ │ novalon.cn (主站) │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │ │ /product-a │ │ /product-b │ │ /product-c │ │ │ └────────────┘ └────────────┘ └────────────┘ │ └──────────────────────────────────────────────────────┘ ``` **优点**:维护成本最低、部署简单 **缺点**:❌ 无法独立域名、SEO受限、品牌独立性差 ### 方案C:Monorepo多站点架构 ⭐ 推荐 ``` ┌─────────────────────────────────────────────────────────┐ │ Monorepo (统一仓库) │ ├─────────────────────────────────────────────────────────┤ │ apps/ │ │ ├── main-site/ → novalon.cn │ │ ├── product-a/ → product-a.com (独立域名) │ │ ├── product-b/ → product-b.com (独立域名) │ │ └── product-c/ → product-c.com (独立域名) │ │ │ │ packages/ (共享代码) │ │ ├── ui/ → 共享组件库 │ │ ├── config/ → 共享配置 │ │ └── utils/ → 共享工具函数 │ └─────────────────────────────────────────────────────────┘ ``` ## 技术设计 ### 目录结构 ``` novalon-website/ ├── apps/ # 应用层(独立部署) │ ├── main-site/ # 主站 → novalon.cn │ │ ├── src/ │ │ ├── next.config.ts │ │ └── package.json │ │ │ └── products/ # 产品站点集合 │ ├── [product-slug]/ # 产品模板(可复制) │ │ ├── src/ │ │ ├── public/ │ │ ├── next.config.ts │ │ └── package.json │ └── ... │ ├── packages/ # 共享层(不独立部署) │ ├── ui/ # 共享组件库 │ │ ├── components/ │ │ │ ├── base/ # 基础组件(Button、Card等) │ │ │ └── layout/ # 布局组件(Header、Footer等) │ │ └── package.json │ │ │ ├── config/ # 共享配置 │ │ ├── tailwind/ # Tailwind预设 │ │ ├── eslint/ # ESLint规则 │ │ └── typescript/ # TS配置 │ │ │ └── utils/ # 共享工具 │ ├── lib/ │ └── package.json │ ├── turbo.json # Turborepo配置 ├── pnpm-workspace.yaml # pnpm工作区配置 └── package.json # 根package.json ``` ### 共享组件库设计 ``` packages/ui/ ├── components/ │ ├── base/ # 基础组件(完全共享) │ │ ├── button/ │ │ ├── card/ │ │ ├── input/ │ │ └── ... │ │ │ └── themed/ # 主题化组件(可覆盖) │ ├── header/ │ └── footer/ │ ├── themes/ # 主题配置 │ ├── default.ts # 默认主题 │ ├── product-a.ts # 产品A主题 │ └── product-b.ts # 产品B主题 │ └── lib/ └── theme-context.tsx # 主题上下文 ``` **组件分层策略**: | 组件类型 | 共享程度 | 定制方式 | |----------|----------|----------| | 基础组件 | 100%共享 | 通过 props 和 CSS 变量覆盖样式 | | 布局组件 | 接口共享 | 各应用可提供自己的实现 | | 业务组件 | 不共享 | 各应用独立开发 | ### CI/CD 流水线 ``` [代码推送] → [变更检测] → [增量构建] → [并行测试] → [智能部署] ↓ ↓ ↓ 哪些应用变了? 只构建变的应用 只部署变的应用 ``` **部署策略**: | 场景 | 构建范围 | 部署范围 | |------|----------|----------| | 只改了 `apps/product-a` | 只构建 product-a | 只部署 product-a | | 改了 `packages/ui` | 构建所有应用 | 部署所有应用 | | 改了 `packages/config` | 构建所有应用 | 部署所有应用 | ### SEO优化策略 **独立域名架构**: ``` ┌─────────────────────────────────────────────────────────────┐ │ Nginx 反向代理 │ ├─────────────────────────────────────────────────────────────┤ │ novalon.cn → 主站容器 (localhost:3000) │ │ product-a.com → 产品A容器 (localhost:3001) │ │ product-b.com → 产品B容器 (localhost:3002) │ └─────────────────────────────────────────────────────────────┘ ``` **SEO关键优势**: | SEO 要素 | 独立站点优势 | |----------|-------------| | 独立域名 | 搜索引擎视为独立实体,权重互不影响 | | 独立 sitemap | 精准控制索引范围,提升爬取效率 | | 独立 metadata | 针对产品特性优化关键词,避免稀释 | | 独立 robots.txt | 灵活控制爬虫访问策略 | ## 迁移路径 ``` 阶段1: 基础设施搭建 (1-2天) ↓ 阶段2: 代码迁移与重构 (3-5天) ↓ 阶段3: 共享组件抽取 (2-3天) ↓ 阶段4: CI/CD 配置 (1-2天) ↓ 阶段5: 第一个产品站点 (2-3天) ``` ### 阶段1:基础设施搭建 ```bash # 1. 创建 Monorepo 根目录结构 mkdir -p apps packages # 2. 初始化 pnpm 工作区 cat > pnpm-workspace.yaml << EOF packages: - 'apps/*' - 'apps/products/*' - 'packages/*' EOF # 3. 安装 Turborepo pnpm add -Dw turbo ``` ### 阶段2:代码迁移 ```bash # 将现有代码移动到 apps/main-site mv src apps/main-site/src mv public apps/main-site/public mv next.config.ts apps/main-site/ ``` ### 阶段3:共享组件抽取 ```bash # 创建共享 UI 包 mkdir -p packages/ui/components # 抽取通用组件 mv apps/main-site/src/components/ui packages/ui/components/base ``` ### 阶段4:创建产品站点 ```bash # 复制主站作为模板 cp -r apps/main-site apps/products/product-template # 创建新产品站点 cp -r apps/products/product-template apps/products/product-a ``` ## 决策总结 | 评估维度 | 独立网站 | 单站内嵌页面 | Monorepo多站点 | |----------|----------|--------------|----------------| | 独立品牌支持 | ✅ 完美 | ❌ 差 | ✅ 完美 | | SEO独立性 | ✅ 最优 | ❌ 受限 | ✅ 最优 | | 维护成本 | ❌ 极高 | ✅ 最低 | ✅ 低 | | 代码复用 | ❌ 无 | ✅ 完全 | ✅ 高度复用 | | 扩展性 | ⚠️ 中等 | ❌ 差 | ✅ 优秀 | | 团队适配 | ❌ 不适合精简团队 | ⚠️ 不满足需求 | ✅ 完美适配 | ## 结论 针对**动态增长 + 独立子品牌 + 精简团队 + 高SEO要求**的场景,**Monorepo多站点架构**是最佳选择: - ✅ 品牌独立:每个产品独立应用、独立域名、独立视觉 - ✅ SEO最优:独立sitemap、独立metadata、独立域名权重 - ✅ 维护高效:共享代码库、统一依赖、一次更新全局生效 - ✅ 扩展简单:新增产品只需复制模板目录 - ✅ 智能CI/CD:增量构建、按需部署、自动化流水线