出处:掘金

原作者:金泽宸


模块化 + 领域分层 + 插件化目录,是大型项目的“骨架系统”

写在前面

项目越大,目录越乱,是所有前端架构师绕不过去的坑。我们常常见到这样的代码结构:

pages/
├── page1.vue
├── page2.vue
├── page3.vue
components/
├── common/
├── header.vue
├── dialog.vue
utils/
api/

很快你就发现:

今天这一篇,我们通过实战项目演示:如何设计清晰、高可维护、方便多人协作的大型项目结构

目录结构设计常见 3 种方式

模式 特点 适合场景
按功能划分(Flat) 易于上手、轻量 小项目、单人开发
按页面划分(Views) 页面结构清晰 中型项目、界面主导
按领域划分(Domain Oriented)✅ 高内聚、低耦合 大型项目、多人协作、可平台化发展

推荐目录结构(面向领域 + 插件化)

src/
├── modules/                  # 各个业务模块(重点)
│   ├── user/
│   │   ├── views/            # 页面(profile、login等)
│   │   ├── components/       # 业务组件
│   │   ├── api.ts            # 模块内接口
│   │   ├── store.ts          # 模块状态
│   │   └── index.ts          # 模块入口
│   ├── order/
│   └── dashboard/
├── shared/                   # 通用能力封装
│   ├── components/           # 通用组件(弹窗、表单)
│   ├── hooks/                # 通用 hooks(useDialog、useTable)
│   ├── utils/                # 工具函数
│   └── constants/            # 枚举/状态码
├── router/                   # 动态路由加载逻辑
├── store/                    # 全局状态,如用户/主题
├── assets/                   # 静态资源
├── services/                 # 和后端联动的接口封装
├── App.vue
└── main.ts

实战演示:一个“用户模块”的结构

modules/user/
├── views/
│   ├── Login.vue
│   ├── Profile.vue
├── components/
│   ├── UserAvatar.vue
│   ├── UserInfoCard.vue
├── api.ts
├── store.ts
└── index.ts

模块 API:

// modules/user/api.ts
import request from '@/shared/utils/request'

export const getUserInfo = () => request.get('/user/info')
export const login = (data) => request.post('/user/login', data)

好处:

模块化加载 + 路由动态挂载

步骤1:在模块中暴露路由配置:

// modules/user/index.ts
export default {
  routes: [
    {
      path: '/user/login',
      component: () => import('./views/Login.vue'),
    },
    {
      path: '/user/profile',
      component: () => import('./views/Profile.vue'),
    },
  ],
}

步骤2:在全局 router 中自动加载所有模块路由:

// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'

const modules = import.meta.glob('../modules/**/index.ts', { eager: true })
const routes = Object.values(modules)
  .map((m: any) => m.default.routes)
  .flat()

export const router = createRouter({
  history: createWebHistory(),
  routes,
})

优点:

组件设计的目录策略

目录位置 用途 示例组件
shared/components/ 通用组件 Dialog、Pagination、DatePicker
modules/user/components/ 业务组件 UserAvatar、UserStatsCard
pages/组件目录 页面私有组件 TableColumnRenderer.vue

建议:

复用策略:避免重复造轮子

  1. 通用模块统一收敛(Dialog、Form、Upload)
  2. 模块复用提炼成插件库
  3. 通过 props + slot 提高复用性
<!-- 通用组件 Dialog -->
<MyDialog :title="title" @confirm="handleConfirm">
  <template #default>
    <p>{{ description }}</p>
  </template>
</MyDialog>
<!-- 业务中使用 -->
<MyDialog title="删除用户" @confirm="deleteUser">
  <template #default>
    <p>是否确认删除该用户?</p>
  </template>
</MyDialog>