在前端工程化日益成熟的今天,企业级 Vue 项目的架构设计直接决定了项目的可维护性、可扩展性和团队协作效率。不同于中小型项目的 “快速开发” 思路,企业级项目需要从目录结构、模块化拆分、工程化规范等维度进行系统化设计,本文将聚焦目录结构设计与模块化方案两大核心,结合 Vue 3 + Vite 生态,给出一套可落地的企业级架构方案。
一、架构设计的核心原则
在开始具体设计前,先明确企业级 Vue 项目架构的核心原则,所有设计都应围绕这些原则展开:
- 高内聚低耦合:功能模块内部逻辑聚合,模块间依赖清晰、减少耦合;
- 可维护性:目录结构清晰,代码规范统一,新人能快速上手;
- 可扩展性:支持业务模块横向扩展、功能纵向迭代,适配多环境 / 多端;
- 复用性:抽离通用组件、工具、逻辑,降低重复开发成本;
- 可测试性:模块化拆分便于单元测试、集成测试落地。
二、标准化目录结构设计
基于 Vue 3 + Vite + TypeScript(企业级项目推荐 TS),结合社区最佳实践,设计如下目录结构(注释说明核心目录用途):
src/ ├── api/ # 接口请求层:统一管理接口请求 │ ├── modules/ # 按业务模块拆分接口 │ │ ├── user.ts # 用户模块接口 │ │ ├── order.ts # 订单模块接口 │ │ └── product.ts # 商品模块接口 │ ├── request.ts # 请求拦截、响应拦截、axios封装 │ └── index.ts # 接口统一导出入口 ├── assets/ # 静态资源:全局样式、图片、字体等 │ ├── icons/ # 图标资源(svg/png) │ ├── images/ # 图片资源 │ ├── styles/ # 全局样式 │ │ ├── reset.scss # 样式重置 │ │ ├── variables.scss # 全局样式变量 │ │ └── global.scss # 全局通用样式 │ └── fonts/ # 字体文件 ├── components/ # 通用组件:全局复用的基础组件/业务组件 │ ├── base/ # 基础组件(无业务逻辑):Button、Input、Table等 │ ├── business/ # 业务通用组件:OrderCard、UserInfo等 │ └── index.ts # 组件全局注册入口(可选) ├── composables/ # 组合式函数:抽离通用业务逻辑(Vue 3 Composition API) │ ├── useAuth.ts # 权限相关逻辑 │ ├── usePagination.ts # 分页通用逻辑 │ └── useRequest.ts # 接口请求封装逻辑 ├── config/ # 全局配置:环境变量映射、常量、枚举等 │ ├── env.ts # 环境变量统一导出 │ ├── constants.ts # 业务常量(如订单状态、支付方式) │ └── enums.ts # TypeScript枚举(如OrderStatusEnum) ├── directives/ # 自定义指令:权限指令、防抖指令等 │ ├── permission.ts # 按钮/页面权限指令 │ └── index.ts # 指令全局注册入口 ├── hooks/ # 基础hooks:与业务无关的通用hooks(区别于composables) │ ├── useDebounce.ts # 防抖hook │ └── useThrottle.ts # 节流hook ├── layouts/ # 布局组件:全局布局、分模块布局 │ ├── BasicLayout.vue # 基础布局(侧边栏+头部+内容区) │ ├── BlankLayout.vue # 空白布局(无侧边栏/头部) │ └── index.ts # 布局导出入口 ├── locales/ # 国际化:多语言配置 │ ├── en/ # 英文配置 │ ├── zh-CN/ # 中文配置 │ └── index.ts # 国际化初始化 ├── router/ # 路由:路由配置、守卫 │ ├── modules/ # 按业务模块拆分路由 │ │ ├── user.ts │ │ ├── order.ts │ │ └── product.ts │ ├── guards.ts # 路由守卫(全局前置/后置/权限守卫) │ └── index.ts # 路由初始化 ├── store/ # 状态管理:Pinia(替代Vuex) │ ├── modules/ # 按业务模块拆分store │ │ ├── user.ts │ │ ├── order.ts │ │ └── product.ts │ └── index.ts # Pinia初始化 ├── types/ # TypeScript类型声明:全局类型、接口 │ ├── api.ts # 接口返回值类型 │ ├── business.ts # 业务模型类型 │ └── global.ts # 全局类型(如Window扩展) ├── utils/ # 工具函数:通用工具、业务工具 │ ├── format.ts # 格式化工具(时间、金额) │ ├── storage.ts # 本地存储工具(localStorage/sessionStorage) │ └── validate.ts # 校验工具(表单校验) ├── views/ # 页面视图:按业务模块拆分 │ ├── user/ # 用户模块页面 │ │ ├── list.vue │ │ └── detail.vue │ ├── order/ # 订单模块页面 │ └── product/ # 商品模块页面 ├── App.vue # 根组件 ├── main.ts # 项目入口文件 └── vite-env.d.ts # Vite类型声明核心目录设计说明
- api 层:统一封装 axios,按业务模块拆分接口,避免接口散落在页面中,便于接口管理和 mock 替换;
- composables vs hooks:
hooks存放纯通用工具型 hook(如防抖、节流),composables存放和业务相关的组合式函数(如权限逻辑、分页逻辑),区分通用逻辑和业务逻辑; - layouts:支持多布局切换(如后台管理系统的基础布局、登录页的空白布局),适配不同页面的布局需求;
- router/store 模块化:按业务模块拆分路由和状态管理,避免单个文件过大,便于团队分工维护;
- types 目录:集中管理 TS 类型,避免类型分散,提升类型复用性和代码提示效率;
- utils 目录:抽离通用工具函数,避免重复造轮子,同时按功能分类(格式化、存储、校验),便于查找。
三、模块化方案设计
企业级项目的模块化核心是按业务域拆分+分层解耦,同时兼顾模块的独立性和复用性,具体方案如下:
1. 业务模块拆分原则
以 “业务域” 为核心拆分模块,而非按 “功能类型” 拆分。例如:
- 正确拆分:用户模块(user)、订单模块(order)、商品模块(product);
- 错误拆分:表单模块、列表模块、详情模块(按 UI 功能拆分,易导致耦合)。
每个业务模块需包含完整的 “视图 - 路由 - 接口 - store - 类型” 闭环,模块内高内聚,模块间通过约定的接口通信(如 Pinia、事件总线、路由参数)。
2. 模块分层架构(从下到上)
基础层(utils/hooks/types)→ 核心层(api/store/composables)→ 组件层(components)→ 页面层(views)→ 路由层(router)- 基础层:提供通用工具、类型、基础 hooks,不依赖上层模块;
- 核心层:封装业务逻辑、接口、状态管理,依赖基础层,不依赖页面 / 组件;
- 组件层:复用组件,依赖核心层,不直接依赖页面;
- 页面层:组装组件和核心逻辑,实现业务功能;
- 路由层:管理页面路由,控制页面访问权限。
3. 模块间通信规范
模块间通信需遵循 “最小依赖” 原则,避免直接引用:
| 通信场景 | 推荐方案 | 注意事项 |
|---|---|---|
| 父子组件 | Props + Emits / v-model | 避免使用parent/children |
| 跨层级组件 | Provide + Inject | 仅用于全局通用数据(如主题、权限) |
| 模块间状态共享 | Pinia | 避免单例 store 过大,按模块拆分 |
| 页面跳转传参 | 路由参数 / Pinia | 复杂参数优先用 Pinia,避免路由参数过长 |
| 非父子组件事件 | EventBus(如 mitt) | 仅用于临时事件,避免全局事件泛滥 |
4. 模块化复用策略
(1)通用组件复用
- 基础组件(Button、Input):封装成通用 UI 组件库,发布到 npm 私有仓库;
- 业务通用组件(OrderCard):放在
components/business目录,通过 props 配置不同场景。
(2)业务逻辑复用
- 通用逻辑(分页、权限):抽离为
composables函数,如usePagination; - 跨模块逻辑:封装成独立的工具函数或 Pinia 模块,避免重复开发。
(3)接口复用
- 通用接口(如用户信息查询):放在 api 公共模块,供多个业务模块调用;
- 接口参数 / 返回值类型:在
types/api.ts中定义,确保类型统一。
5. 模块隔离与按需加载
企业级项目需避免 “一次性加载所有模块”,提升首屏加载速度:
1. 路由按需加载:使用 Vite 的动态导入,拆分路由 chunk:
// router/modules/order.ts const OrderList = () => import('@/views/order/list.vue') const OrderDetail = () => import('@/views/order/detail.vue') export default [ { path: '/order/list', name: 'OrderList', component: OrderList, meta: { title: '订单列表' } }, { path: '/order/detail/:id', name: 'OrderDetail', component: OrderDetail, meta: { title: '订单详情' } } ]2.组件按需加载:非首屏核心组件使用动态导入:
<template> <AsyncComponent v-if="show" /> </template> <script setup lang="ts"> const AsyncComponent = defineAsyncComponent(() => import('@/components/business/OrderCard.vue')) const show = ref(false) </script>3. 模块样式隔离:使用 Vue 的 Scoped CSS 或 CSS Modules,避免样式污染:
<style scoped> /* 仅作用于当前组件 */ .order-card { padding: 16px; } </style>四、架构落地的配套规范
好的架构需要配套规范支撑,否则容易出现 “架构设计与实际开发脱节”:
- 命名规范:
- 文件命名:组件 / 页面使用 PascalCase(如 OrderList.vue),工具函数 / 接口使用 camelCase(如 usePagination.ts);
- 模块命名:统一使用小写 + 短横线(如 user-center),避免中文 / 特殊字符;
- 代码规范:
- 使用 ESLint + Prettier 统一代码风格,配置 Vue/TypeScript 规则;
- 组件 props 必须声明类型,事件必须声明参数类型;
- 提交规范:使用 Commitlint 约束 Git 提交信息(如 feat: 新增订单列表模块);
- 版本规范:遵循 SemVer 语义化版本(主版本。次版本。补丁版本);
- 权限规范:模块权限统一在路由 meta 中声明,通过路由守卫校验,避免权限逻辑散落在页面中。
五、架构演进与扩展
企业级项目的架构并非一成不变,需根据业务规模演进:
- 中小型企业项目:可简化目录(如去掉 locales、layouts,合并 hooks/composables);
- 大型微前端项目:基于上述架构,拆分为多个子应用,通过 qiankun 等微前端框架集成;
- 多端适配项目:在
layouts/components中增加端判断逻辑,或使用 Unocss/Tailwind CSS 适配多端样式; - 跨团队协作项目:将通用组件 / 工具发布为私有 npm 包,实现跨项目复用。
总结
企业级 Vue 项目的架构设计,核心是 “标准化目录结构” 和 “模块化拆分”,既要满足当前业务需求,也要为未来扩展预留空间。本文给出的架构方案,结合了 Vue 3 生态的最佳实践,兼顾了可维护性、可扩展性和复用性,可根据实际业务场景调整落地。
架构的价值不在于 “设计多完美”,而在于 “团队能落地、能持续维护”。建议团队在落地前统一共识,制定配套规范,并在迭代中持续优化架构,避免 “过度设计” 或 “无架构混乱开发”。