ui-architecture.md 12 KB

D8D Starter 前端架构文档

版本信息

版本 日期 描述 作者
1.0 2025-09-15 初始前端架构文档 Winston

1. 模板和框架选择

现有技术栈分析

项目已经使用了现代化的React全栈技术栈:

核心框架:

  • React 19.1.0 - 最新版本,支持并发特性
  • TypeScript 5.8.3 - 类型安全,编译时错误检测

构建工具:

  • Vite 7.0.0 - 快速冷启动,热重载支持
  • Tailwind CSS 4.1.11 - 原子化CSS,实用优先

UI组件库:

  • shadcn/ui - 基于Radix UI的无障碍组件库
  • Radix UI Primitives - 无障碍基础组件

状态管理:

  • React Query 5.83.0 - 服务端状态管理,数据同步
  • React Hook Form 7.61.1 - 表单管理和验证

路由系统:

  • React Router 7.7.0 - 声明式客户端路由
  • 双路由架构 - 管理后台(/admin/)和用户前台(/)分离

API集成:

  • Hono RPC 4.8.5 - 端到端类型安全API调用
  • 自定义axios适配器 - 统一的错误处理

技术决策依据

  • 选择React Query而非Redux: 专注于服务端状态管理,减少客户端状态复杂度
  • Hono RPC而非传统REST: 提供前后端统一的类型安全,减少接口不一致问题
  • Tailwind CSS v4: 采用新的运行时配置,简化构建流程
  • shadcn/ui而非Ant Design: 更现代的设计语言,更好的无障碍支持

2. 前端技术栈

类别 技术 版本 用途 决策依据
框架 React 19.1.0 用户界面构建 最新版本,并发特性支持
UI库 shadcn/ui - 组件库和设计系统 基于Radix UI,无障碍支持
状态管理 React Query 5.83.0 服务端状态管理 数据同步、缓存、自动重试
路由 React Router 7.7.0 客户端路由 声明式路由,数据加载支持
构建工具 Vite 7.0.0 开发服务器和构建 快速冷启动,热重载支持
样式方案 Tailwind CSS 4.1.11 原子化CSS框架 实用优先,设计一致性
类型安全 TypeScript 5.8.3 类型检查 编译时错误检测
API客户端 Hono RPC 4.8.5 类型安全API调用 前后端统一类型定义
表单处理 React Hook Form 7.61.1 表单管理和验证 高性能,最小重渲染
图标库 Lucide React 0.536.0 图标系统 简洁一致的图标设计
测试框架 Jest + Testing Library - 组件测试 行业标准测试工具

3. 项目结构

d8d-starter/
├── src/
│   ├── client/                 # 前端代码根目录
│   │   ├── admin/              # 管理后台界面
│   │   │   ├── components/     # 管理后台专属组件
│   │   │   ├── pages/          # 管理页面
│   │   │   ├── layouts/        # 管理后台布局
│   │   │   └── hooks/          # 管理后台专属hooks
│   │   ├── home/               # 用户主页界面
│   │   │   ├── components/     # 主页专属组件
│   │   │   ├── pages/          # 主页页面
│   │   │   └── hooks/          # 主页专属hooks
│   │   ├── components/         # 共享UI组件
│   │   │   ├── ui/             # 基础UI组件 (shadcn/ui)
│   │   │   │   ├── button.tsx
│   │   │   │   ├── input.tsx
│   │   │   │   └── ...
│   │   │   ├── forms/          # 表单组件
│   │   │   ├── layout/         # 布局组件
│   │   │   └── shared/         # 业务共享组件
│   │   ├── hooks/              # 共享React Hooks
│   │   │   ├── use-api.ts      # API调用hook
│   │   │   ├── use-auth.ts     # 认证hook
│   │   │   └── use-query.ts    # React Query封装
│   │   ├── lib/                # 工具库
│   │   │   ├── utils.ts        # 通用工具函数
│   │   │   ├── cn.ts           # className工具
│   │   │   └── validators.ts   # 表单验证器
│   │   ├── types/              # 前端类型定义
│   │   │   ├── api.ts          # API响应类型
│   │   │   ├── forms.ts        # 表单数据类型
│   │   │   └── index.ts        # 类型导出
│   │   ├── styles/             # 样式文件
│   │   │   ├── globals.css     # 全局样式
│   │   │   └── components.css  # 组件样式
│   │   └── utils/              # 工具函数
│   │       ├── api.ts          # API客户端配置
│   │       ├── error-handler.ts # 错误处理
│   │       └── constants.ts    # 常量定义
│   ├── server/                 # 后端代码
│   └── shared/                 # 前后端共享代码
├── public/                     # 静态资源
├── dist/                       # 构建输出
└── docs/                       # 文档

4. 组件标准

组件模板

import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/client/lib/utils"

const componentVariants = cva(
  "base-styles transition-all duration-200",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground",
        secondary: "bg-secondary text-secondary-foreground",
        destructive: "bg-destructive text-destructive-foreground",
        outline: "border border-input bg-background",
        ghost: "hover:bg-accent hover:text-accent-foreground",
      },
      size: {
        default: "h-9 px-4 py-2",
        sm: "h-8 rounded-md px-3 text-xs",
        lg: "h-10 rounded-md px-8",
        icon: "size-9",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

export interface ComponentProps
  extends React.HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof componentVariants> {
  isLoading?: boolean
  disabled?: boolean
}

const Component = React.forwardRef<HTMLDivElement, ComponentProps>(
  ({ className, variant, size, isLoading = false, disabled = false, ...props }, ref) => {
    return (
      <div
        ref={ref}
        className={cn(
          componentVariants({ variant, size, className }),
          isLoading && "opacity-50 cursor-not-allowed",
          disabled && "pointer-events-none opacity-50"
        )}
        aria-disabled={disabled || isLoading}
        {...props}
      />
    )
  }
)
Component.displayName = "Component"

export { Component, componentVariants }

命名约定

文件命名:

  • 组件文件: PascalCase.tsx (如: UserProfile.tsx)
  • 工具文件: camelCase.ts (如: formatDate.ts)
  • Hook文件: useCamelCase.ts (如: useUserData.ts)
  • 类型文件: camelCase.ts (如: apiTypes.ts)

组件命名:

  • 组件: PascalCase (如: UserCard)
  • Props接口: ComponentProps (如: ButtonProps)
  • 变体类型: ComponentVariants (如: ButtonVariants)

5. 状态管理

Store结构

src/
├── client/
│   ├── hooks/
│   │   ├── use-api.ts          # API调用封装
│   │   ├── use-auth.ts         # 认证状态
│   │   ├── use-users.ts        # 用户数据
│   │   ├── use-roles.ts        # 角色数据
│   │   └── index.ts            # hooks导出
│   ├── lib/
│   │   ├── query-client.ts     # React Query配置
│   │   └── query-keys.ts       # 查询键常量
│   └── providers/
│       └── query-provider.tsx  # QueryClientProvider

React Query配置

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000, // 5分钟
      gcTime: 10 * 60 * 1000, // 10分钟
      retry: 1,
      refetchOnWindowFocus: false,
    },
    mutations: {
      retry: 1,
    },
  },
})

6. API集成

Hono RPC集成模式

// 创建axios适配器用于Hono RPC
const axiosFetch = async (url: RequestInfo | URL, init?: RequestInit) => {
  const requestHeaders: Record<string, string> = {};

  if (init?.headers instanceof Headers) {
    init.headers.forEach((value, key) => {
      requestHeaders[key] = value;
    })
  }

  const response = await axios.request({
    url: url.toString(),
    method: init?.method || 'GET',
    headers: requestHeaders,
    data: init?.body,
  }).catch((error) => {
    if (isAxiosError(error)) {
      return {
        status: error.response?.status,
        statusText: error.response?.statusText,
        data: error.response?.data,
        headers: error.response?.headers
      }
    }
    throw error;
  })

  return new Response(
    JSON.stringify(response.data),
    {
      status: response.status,
      statusText: response.statusText,
      headers: response.headers
    }
  )
}

// Hono客户端实例
export const userClient = hc<UserRoutes>('/', {
  fetch: axiosFetch,
}).api.v1.users;

7. 路由配置

当前路由架构

双路由系统:

  • 管理后台路由: /admin/* (位于 src/client/admin/routes.tsx)
  • 用户前台路由: /* (位于 src/client/home/routes.tsx)

路由结构:

// 管理后台路由
- /admin/login      → 登录页面
- /admin            → 重定向到仪表板 (保护路由)
- /admin/dashboard  → 仪表板页面 (保护路由)
- /admin/users      → 用户管理页面 (保护路由)

// 用户前台路由
- /          → 首页
- /login     → 登录页面
- /register  → 注册页面
- /member    → 会员页面 (保护路由)

认证保护

export const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
  const { isAuthenticated, isLoading } = useAuth();
  const navigate = useNavigate();

  useEffect(() => {
    if (!isLoading && !isAuthenticated) {
      navigate('/admin/login', { replace: true });
    }
  }, [isAuthenticated, isLoading, navigate]);

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return null;
  }

  return children;
};

8. 样式指南

主题系统

基于CSS自定义属性的主题系统:

:root {
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  /* ... 更多设计token */
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --primary: oklch(0.985 0 0);
  /* ... 暗色主题变量 */
}

样式方法论

  • 原子化CSS: 使用Tailwind工具类构建UI
  • CSS变量: 通过CSS自定义属性实现主题切换
  • 设计系统: 基于shadcn/ui的组件设计规范
  • 响应式: 移动优先的响应式设计

9. 测试要求

测试策略

测试框架: Jest + Testing Library 测试位置: __tests__文件夹与源码并列 覆盖率目标: 核心组件80%+覆盖率

测试模板

describe('Button', () => {
  it('renders correctly with default variant', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByRole('button')).toHaveTextContent('Click me')
  })

  it('calls onClick handler when clicked', () => {
    const handleClick = jest.fn()
    render(<Button onClick={handleClick}>Click me</Button>)

    fireEvent.click(screen.getByRole('button'))
    expect(handleClick).toHaveBeenCalledTimes(1)
  })
})

10. 环境配置

环境变量

VITE_API_BASE_URL=http://localhost:8080
VITE_APP_NAME=D8D Starter
VITE_ENABLE_ANALYTICS=false

11. 前端开发标准

关键编码规则

  1. 类型安全: 全面使用TypeScript,避免any类型
  2. 组件设计: 遵循单一职责原则
  3. 性能优化: 使用React.memo、useCallback等优化手段
  4. 错误处理: 统一的错误边界和异常处理
  5. 可访问性: 支持ARIA属性和键盘导航

快速参考

常用命令:

npm run dev      # 启动开发服务器
npm run build    # 生产构建
npm run test     # 运行测试

文档状态: 正式版 下次评审: 2025-10-15 架构师: Winston 🏗️