# Monorepo架构技术设计文档
## 架构概览
本设计文档详细描述了DeotalandAi项目从分散的独立项目向Monorepo架构迁移的技术实施方案。
## 技术选型分析
### 包管理器选择: pnpm vs Yarn vs npm
#### 选择: pnpm
**原因:**
- **磁盘空间优化**: 硬链接和符号链接减少80%磁盘占用
- **速度快**: 并行安装,比npm快2-3倍
- **工作空间支持**: 原生Monorepo支持,配置简洁
- **依赖隔离**: 每个包独立node_modules,避免依赖污染
- **严格模式**: 防止"吊死依赖"问题
#### 对比分析:
```
pnpm:
✅ 安装速度快
✅ 磁盘占用少
✅ 工作空间原生支持
✅ 依赖严格模式
❌ 相对较新,生态还在完善
Yarn Workspaces:
✅ 成熟稳定
✅ 社区支持好
❌ 安装速度中等
❌ 磁盘占用大
npm Workspaces:
✅ Node.js原生支持
❌ 功能相对简单
❌ 性能不如pnpm
```
### 构建工具选择: Turborepo vs Lerna vs Nx
#### 选择: Turborepo
**原因:**
- **任务管道**: 声明式任务依赖图,易于理解
- **缓存机制**: 本地和远程缓存,显著提升构建速度
- **增量构建**: 只重新构建变更的包
- **简单配置**: JSON配置,学习成本低
- **Vercel支持**: 来自Vercel,现代化工具链
#### 任务管道设计:
```json
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "build/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": []
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
}
}
}
```
## 项目结构设计
### 目录结构详解
```
DeotalandAi/
├── package.json # 根级别项目配置
├── pnpm-workspace.yaml # pnpm工作空间定义
├── turbo.json # Turborepo任务配置
├── .npmrc # npm配置(使用pnpm时)
├── .eslintrc.base.json # 基础ESLint配置
├── .prettierrc # Prettier配置
├── .prettierrc # Prettier配置
├── .gitignore # Git忽略规则
├── README.md # 项目总体说明
├── CHANGELOG.md # 版本变更记录
├── apps/ # 应用程序
│ ├── frontend/ # 主前端应用
│ │ ├── package.json
│ │ ├── vite.config.js
│ │ ├── index.html
│ │ └── src/
│ │ ├── main.ts
│ │ ├── App.vue
│ │ ├── components/
│ │ ├── views/
│ │ ├── stores/
│ │ └── router/
│ └── designer/ # 设计器应用
│ ├── package.json
│ │ ├── vite.config.js
│ │ ├── index.html
│ │ └── src/
├── packages/ # 共享包
│ ├── ui/ # UI组件库
│ │ ├── package.json
│ │ ├── vite.config.js
│ │ ├── src/
│ │ │ ├── index.js # 统一导出
│ │ │ ├── components/ # Vue组件
│ │ │ ├── styles/ # 样式文件
│ │ │ └── composables/ # 组合式函数
│ │ └── stories/ # Storybook文档
│ ├── utils/ # 工具库
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ ├── api/ # API相关工具
│ │ │ ├── format/ # 格式化工具
│ │ │ ├── validate/ # 验证工具
│ │ │ └── storage/ # 存储工具
│ │ └── tests/
│ └── config/ # 配置文件包
│ ├── package.json
│ ├── src/
│ │ ├── index.js
│ │ ├── vite.js # Vite配置
│ │ └── eslint.js # ESLint配置
├── scripts/ # 构建和部署脚本
│ ├── build.js
│ ├── dev.js
│ ├── deploy.js
│ └── utils.js
└── docs/ # 项目文档
├── architecture.md
├── contributing.md
└── guides/
```
### 工作空间配置详解
#### pnpm-workspace.yaml
```yaml
packages:
- 'apps/*'
- 'packages/*'
- '!apps/*/dist/**'
- '!apps/*/.vite/**'
```
#### package.json (根级别)
```json
{
"name": "deotalandai-monorepo",
"private": true,
"version": "1.0.0",
"description": "DeotalandAI Monorepo with Vue3, Element Plus, and shared components",
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build",
"lint": "turbo run lint",
"test": "turbo run test",
"clean": "turbo run clean && rimraf node_modules",
"type-check": "turbo run type-check",
"storybook": "turbo run storybook",
"deploy": "turbo run deploy"
},
"devDependencies": {
"turbo": "^1.10.0",
"concurrently": "^8.2.0",
"rimraf": "^5.0.0",
"eslint": "^8.45.0",
"prettier": "^3.0.0",
"@vitejs/plugin-vue": "^6.0.1",
"vite": "^7.2.2"
},
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.0.0"
}
}
```
## 共享组件设计
### UI组件库架构
#### 组件分类体系
```
packages/ui/src/components/
├── base/ # 基础组件
│ ├── Button/
│ ├── Input/
│ ├── Card/
│ ├── Modal/
│ └── Loading/
├── layout/ # 布局组件
│ ├── Header/
│ ├── Sidebar/
│ ├── Footer/
│ └── Container/
├── business/ # 业务组件
│ ├── AgentCard/
│ ├── OrderCard/
│ ├── Gallery/
│ └── PurchaseModal/
└── form/ # 表单组件
├── Form/
├── FormItem/
├── Upload/
└── Select/
```
#### 主题系统设计
```typescript
// packages/ui/src/styles/theme.ts
export const theme = {
colors: {
primary: '#6B46C1',
secondary: '#8B5CF6',
success: '#10B981',
warning: '#F59E0B',
error: '#EF4444',
info: '#3B82F6'
},
spacing: {
xs: '4px',
sm: '8px',
md: '16px',
lg: '24px',
xl: '32px'
},
borderRadius: {
sm: '4px',
md: '8px',
lg: '12px',
full: '9999px'
},
typography: {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace']
},
fontSize: {
xs: '12px',
sm: '14px',
md: '16px',
lg: '18px',
xl: '20px',
'2xl': '24px'
}
}
}
```
#### 组件使用示例
```vue
{{ agent.description }}
{{ $t('common.select') }}
```
### 工具库设计
#### API工具模块
```javascript
// packages/utils/src/api/request.js
import axios from 'axios'
export class ApiClient {
constructor(config) {
this.instance = axios.create(config)
this.setupInterceptors()
}
setupInterceptors() {
this.instance.interceptors.request.use(
(config) => {
// 添加认证token
const token = localStorage.getItem('auth_token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => Promise.reject(error)
)
this.instance.interceptors.response.use(
(response) => response.data,
(error) => {
// 统一错误处理
return Promise.reject(this.handleError(error))
}
)
}
handleError(error) {
if (error.response) {
const { status, data } = error.response
return {
status,
message: data.message || '请求失败',
code: data.code
}
}
return {
status: 0,
message: error.message || '网络错误',
code: -1
}
}
async get(url, params) {
return this.instance.get(url, { params })
}
async post(url, data) {
return this.instance.post(url, data)
}
async put(url, data) {
return this.instance.put(url, data)
}
async delete(url) {
return this.instance.delete(url)
}
}
export const createApiClient = (baseURL) => {
return new ApiClient({ baseURL })
}
```
#### 国际化工具
```typescript
// packages/utils/src/i18n/index.ts
import { createI18n } from 'vue-i18n'
import type { App } from 'vue'
export const setupI18n = (app: App, locale: string, messages: Record) => {
const i18n = createI18n({
legacy: false,
locale,
fallbackLocale: 'en',
messages
})
app.use(i18n)
return i18n
}
export const formatDate = (date: Date, locale: string = 'zh-CN') => {
return new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(date)
}
export const formatCurrency = (amount: number, currency: string = 'CNY', locale: string = 'zh-CN') => {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency
}).format(amount)
}
```
### 类型定义设计
#### API类型定义
```typescript
// packages/types/src/api.ts
export interface ApiResponse {
code: number
message: string
data: T
success: boolean
}
export interface PaginatedResponse extends ApiResponse {
pagination: {
page: number
pageSize: number
total: number
totalPages: number
}
}
export interface Agent {
id: string
name: string
description: string
avatar: string
category: string
tags: string[]
created_at: string
updatedAt: string
}
export interface Order {
id: string
agentId: string
userId: string
status: 'pending' | 'processing' | 'completed' | 'failed'
amount: number
currency: string
created_at: string
updatedAt: string
}
```
#### 组件Props类型
```typescript
// packages/types/src/components.ts
import type { Agent, Order } from './api'
export interface ButtonProps {
variant?: 'primary' | 'secondary' | 'outline' | 'ghost'
size?: 'sm' | 'md' | 'lg'
disabled?: boolean
loading?: boolean
block?: boolean
}
export interface CardProps {
shadow?: 'none' | 'sm' | 'md' | 'lg'
border?: boolean
padding?: 'none' | 'sm' | 'md' | 'lg'
}
export interface AgentCardProps {
agent: Agent
selectable?: boolean
showActions?: boolean
}
export interface ModalProps {
visible: boolean
title?: string
width?: string | number
confirmText?: string
cancelText?: string
maskClosable?: boolean
}
```
## 开发工具配置
### VS Code工作区配置
```json
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"typescript.preferences.importModuleSpecifier": "relative",
"emmet.includeLanguages": {
"vue": "html"
},
"files.associations": {
"*.vue": "vue"
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/build": true,
"**/.turbo": true
}
}
```
### 调试配置
```json
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Frontend Dev",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/.bin/vite",
"args": ["--config", "apps/frontend/vite.config.ts"],
"cwd": "${workspaceFolder}/apps/frontend",
"console": "integratedTerminal"
}
]
}
```
## 性能优化策略
### 构建优化
1. **依赖预构建**: 使用vite的依赖预构建
2. **代码分割**: 每个应用独立打包
3. **Tree Shaking**: 消除未使用的代码
4. **缓存策略**: 利用Turborepo缓存
### 开发优化
1. **热模块替换**: 跨包的热更新
2. **增量构建**: 只构建变更的包
3. **并行开发**: 同时启动多个应用
4. **类型检查**: 增量TypeScript检查
### 部署优化
1. **CDN分发**: 静态资源CDN部署
2. **压缩优化**: Gzip/Brotli压缩
3. **缓存头**: 合理的缓存策略
4. **域名分片**: 多个域名提升加载速度
## 迁移风险与缓解
### 技术风险
1. **构建复杂度**: 复杂的工作空间依赖图
- **缓解**: 使用Turborepo简化配置
2. **依赖冲突**: 不同包的依赖版本冲突
- **缓解**: 使用pnpm的严格模式
3. **构建时间**: 大型Monorepo构建时间长
- **缓解**: 利用Turborepo缓存和增量构建
### 团队风险
1. **学习成本**: 团队需要学习新的工作方式
- **缓解**: 提供详细的文档和培训
2. **工具兼容性**: 现有工具可能不支持Monorepo
- **缓解**: 选择兼容性好的工具
3. **CI/CD复杂性**: 流水线配置更复杂
- **缓解**: 提供完整的CI/CD模板
---
**设计版本**: 1.0
**创建时间**: 2025-11-18
**技术负责人**:
**审核状态**: 待审核