人人都会AI编程

2.2 项目目录结构规范与最佳实践

更新时间:2026-07-10

一个清晰、约定俗成的项目目录结构,是团队协作和长期维护的基石。React 本身不对目录组织做强制约束,但经过大量项目的沉淀,业内已经形成了一套高效且可伸缩的最佳实践。本节将介绍一个典型 Vite + React 项目的标准目录结构,并解释每个模块的职责与设计原则。

推荐的标准目录结构

以下是一个企业级项目中常见的目录组织方式:

my-react-app/
├── public/                 # 静态资源,不会经过构建工具处理
│   └── favicon.ico
├── src/                    # 项目源代码主目录
│   ├── assets/             # 需要经过构建的资源(图片、字体、全局样式等)
│   │   ├── images/
│   │   └── styles/
│   ├── components/         # 通用组件,可跨页面/模块复用
│   │   ├── Button/
│   │   │   ├── index.tsx
│   │   │   ├── Button.module.css
│   │   │   └── Button.test.tsx
│   │   ├── Modal/
│   │   └── ...
│   ├── pages/              # 页面级组件,通常与路由一一对应
│   │   ├── Home/
│   │   │   ├── index.tsx
│   │   │   └── components/  # 页面私有组件
│   │   └── About/
│   ├── hooks/              # 自定义 Hooks
│   │   ├── useAuth.ts
│   │   └── useFetch.ts
│   ├── services/           # API 请求层,封装后端接口调用
│   │   ├── api.ts          # Axios 实例与拦截器
│   │   └── userService.ts  # 按业务域拆分
│   ├── store/              # 全局状态管理(如 Redux、Zustand)
│   │   ├── index.ts
│   │   └── slices/
│   ├── utils/              # 工具函数、常量、辅助方法
│   │   ├── format.ts
│   │   └── constants.ts
│   ├── types/              # TypeScript 类型定义(可选,按模块拆分或集中管理)
│   │   └── user.ts
│   ├── router/             # 路由配置
│   │   └── index.tsx
│   ├── layouts/            # 布局组件(如侧边栏+头部+内容区的壳)
│   ├── App.tsx             # 根组件,通常只包含路由和全局 Provider
│   ├── main.tsx            # 应用入口,挂载 ReactDOM
│   └── vite-env.d.ts       # Vite 环境类型声明
├── .env                    # 环境变量(开发/生产)
├── .eslintrc.cjs           # ESLint 配置
├── .prettierrc             # Prettier 配置
├── tsconfig.json           # TypeScript 配置
├── vite.config.ts          # Vite 构建配置
└── package.json

目录职责详解

| 目录/文件 | 职责 | 注意事项 |
|-----------|------|----------|
| public/ | 存放不需要编译的静态文件,如图标、robots.txt 等,打包时直接拷贝到输出目录。 | 不要放大量图片或业务资源,避免构建体积膨胀。 |
| src/assets/ | 存放需要通过构建工具处理的资源,如 SVG 组件、全局样式、主题变量等。 | 使用别名(@/assets/)导入,避免深层相对路径。 |
| src/components/ | 全局通用的 UI 组件,如 ButtonInputModal 等。每个组件一个文件夹,包含组件代码、样式、测试。 | 组件应该无业务逻辑,只依赖 Props,便于跨项目复用。 |
| src/pages/ | 页面级组件,直接对应路由。每个页面一个文件夹,里面可以包含该页面私有的子组件(放在 components/ 子目录)。 | 页面组件负责组装通用组件和页面私有组件,处理数据加载和状态聚合。 |
| src/hooks/ | 封装可复用的逻辑,如数据请求、权限校验、防抖等。 | Hook 命名以 use 开头,如 useAuth,遵循 React 规范。 |
| src/services/ | 统一管理所有后端 API 请求,根据业务域(如用户、订单、商品)拆分成不同文件。 | 避免在组件中直接写 fetchaxios 调用,便于统一处理错误、鉴权和请求头。 |
| src/store/ | 全局状态管理代码(如 Redux Toolkit 的 store 配置、Slice)。 | 对于小型项目,可能简化为单一的 Context + useReducer,中等以上项目建议采用 Zustand 或 Redux Toolkit。 |
| src/utils/ | 与 UI 无关的纯工具函数,如日期格式化、数据校验、本地存储操作等。 | 坚持纯函数,可编写单元测试。 |
| src/router/ | 集中配置路由表,包含路径、页面组件、懒加载声明、路由守卫等。 | 推荐使用 React Router v6 的配置式路由。 |
| src/layouts/ | 应用的“外壳”布局,如后台管理系统的侧边栏+顶栏+内容区,可定义多种布局(如基础布局、空白布局)。 | 在路由配置中包裹页面组件,避免在每个页面重复布局代码。 |
| App.tsx | 应用的根组件,通常只做三件事:包裹全局 Provider(如路由、状态、主题)、渲染路由出口、设置错误边界。 | 保持极简,不要在这里写业务逻辑。 |
| main.tsx | 入口文件,创建 React 根节点并挂载 <App />,执行全局初始化(如配置、样式导入)。 | 这是 Webpack/Vite 的入口点,通常不做业务处理。 |

目录组织的最佳实践原则

  1. 按功能/路由拆分,而非按文件类型

老的实践中常见 components/containers/styles/ 等按文件类型分割的目录,维护起来需要来回跳转。现代推荐按业务功能或路由组织,相关文件就近放置。例如,一个用户模块的页面、服务、类型可以放在同一个 features/user/ 下(或继续使用 pages/ + services/ 混合模式,视项目规模而定)。

对于大型项目,可引入“功能模块”目录:

   src/
   └── features/
       ├── auth/
       │   ├── components/
       │   ├── hooks/
       │   ├── services/
       │   └── types/
       └── dashboard/
           ├── components/
           └── pages/
   

这种 Colocation(放在一起)模式大大降低了模块间的依赖追踪成本。

  1. 组件文件夹命名与导出约定

每个组件的文件夹使用 PascalCase 命名(如 UserCard),内部 index.tsx 作为组件的导出入口,这样导入时可以省略文件名:import UserCard from '@/components/UserCard'。同时隔离样式和测试文件,结构清晰。

  1. 公共资源与页面私有资源严格区分
  • 通用组件放在 components/,页面私有组件放在 pages/Home/components/
  • 如果一个组件被多个页面引用,应立即提升到 components/
  • Hooks、工具函数同理:只被一处使用的,可以先放在页面或组件附近,出现第二次复用时提升到公共目录。
  1. 使用路径别名简化导入

在 Vite 或 Webpack 中配置 @ 符号映射到 src/,避免出现 ../../../components/Button 这样的深层相对路径。配置示例:

   // vite.config.ts
   resolve: {
     alias: { '@': '/src' }
   }
   
  1. 保持应用入口文件精简

main.tsxApp.tsx 只做全局初始化和 Provider 包裹,将具体的 UI 组装交给路由和布局。这能让应用启动逻辑一目了然。

  1. 按环境分离配置

在根目录使用 .env.development.env.production 等文件管理不同环境的变量,不要将敏感信息硬编码在代码中。

  1. 测试文件与源文件就近放置

推荐将 *.test.tsx 放在被测试组件或模块的同一目录下,而不是独立的 tests 文件夹,这样在移动或重构目录时不会遗漏测试。

小型项目 vs 大型项目的目录策略

  • 小型项目(活动页、工具型单页):可以简化目录,甚至可以只保留 components/pages/hooks/utils/ 四个关键目录。过度设计反而增加负担。
  • 中型项目(后台管理、一般 SaaS):采用上述标准结构即可,重点是 services/store/ 的规范。
  • 大型项目(多团队协作、多业务线):强烈建议采用 features/ 模式,强制解耦,同时引入 packages/ 目录管理共享的内部包(通过 monorepo 工具如 Turborepo 或 Nx)。

一个好的目录结构就像一张清晰的城市地图,让新加入的开发者能快速定位代码、理解项目边界。在一开始就定下规范并写入团队的开发文档,会避免后期“意大利面条式”的目录混乱。