Code前端首页关于Code前端联系我们

Vue3刚入门?项目目录结构到底该怎么搭?避坑实战指南来了

terry 6天前 阅读数 1050 #Vue

刚用Vue CLI或者Vite初始化Vue3项目的朋友,大概率会对着生成的一堆文件夹和文件犯懵:src里的components、assets是干嘛的?router和store为什么有时候分开有时候放一起?还有.env、.gitignore这些配置文件,改了会不会崩?甚至有些老手重构Vue2项目转Vue3时,也会纠结要不要沿用旧结构,还是换更符合Composition API和现代前端规范的组织方式,别慌,今天咱们就把Vue3目录结构的逻辑、推荐方案、踩过的坑、适配新兴开发场景的调整全说透,不管是小项目练手还是团队协作的中大型项目,都能找到合适的参考。

为什么要重视Vue3的目录结构?很多人一开始没意识到这点

目录结构看似是个“小事”,不影响功能实现,但实际上是项目的“骨架”——骨架搭得歪歪扭扭,后续加功能、找bug、换同事接手都会极其痛苦,比如我之前接触过一个外包转来的Vue2半完成项目,所有组件都堆在components根目录下,业务逻辑混在App.vue里,连router的守卫都写在main.js,结果光是梳理登录流程就花了3天,重构了一半才勉强能用。

Vue3带来了Composition API、Pinia替代Vuex(现在Vuex基本退出历史舞台了,新项目99%推荐用Pinia)、TypeScript支持更友好、Vite构建速度提升这些变化,对应的目录结构自然也要做调整,才能发挥Vue3的最大优势。

举个简单的例子:Vue2里我们习惯用.vue文件的script部分写逻辑,组件多了会有data、methods、computed、watch分散的问题,Vue3的Composition API可以用组合式函数(Composables)把相关逻辑抽离出来,如果没有专门的目录放这些函数,就会随便塞在components或者utils里,时间长了组合式函数比组件还难找。

再比如现在的Vue3项目很多是全栈分离的,前端会对接多个后端接口,如果没有统一管理接口的目录,每个页面都自己写axios请求,一旦接口路径或者参数改了,得搜遍整个项目改,效率极低还容易漏。

目录结构规范也是团队协作的“隐形规则”——不用每次都花时间跟新成员解释“这个文件该放哪里”“那个函数要怎么命名”,大家只要按规则来就行,开发效率会高很多。

先搞懂Vue CLI和Vite初始化的默认目录结构是怎么来的

不管你是用Vue CLI还是Vite初始化项目,生成的默认目录结构都不是拍脑袋想出来的,而是参考了Vue官方推荐的风格指南,结合社区的最佳实践定下来的,我们先分别看看这两个工具的默认结构,再分析哪些可以保留,哪些需要调整。

Vue CLI 5.x初始化的Vue3默认结构(假设项目名是my-vue3-cli)

my-vue3-cli/
├── node_modules/          # 第三方依赖包,千万不要手动改里面的文件
├── public/                # 静态资源目录,这里的文件不会被webpack处理
│   ├── favicon.ico        # 网站图标
│   └── index.html         # 入口HTML文件
├── src/                   # 核心源代码目录,99%的开发工作在这里完成
│   ├── assets/            # 需要被webpack处理的静态资源(比如图片、字体、CSS变量文件)
│   │   └── logo.png
│   ├── components/        # 通用组件目录
│   │   └── HelloWorld.vue
│   ├── App.vue            # 根组件,整个应用的入口组件
│   └── main.js            # 应用入口文件,初始化Vue应用实例
├── .gitignore             # Git忽略文件配置,告诉Git哪些文件不需要提交
├── babel.config.js        # Babel配置文件,把ES6+语法转成浏览器兼容的ES5语法
├── jsconfig.json          # VSCode等编辑器的JavaScript配置文件(如果用TypeScript是tsconfig.json)
├── package.json           # 项目依赖和脚本配置文件
├── package-lock.json      # 锁定依赖包版本的文件(npm生成的,yarn是yarn.lock)
└── README.md              # 项目说明文档

Vite 4.x/5.x初始化的Vue3默认结构(假设项目名是my-vue3-vite)

my-vue3-vite/
├── node_modules/
├── public/                # 和Vue CLI的public目录功能一样
│   ├── favicon.ico
│   └── vite.svg           # Vite的默认图标
├── src/
│   ├── assets/            # 需要被Vite处理的静态资源
│   │   └── vue.svg
│   ├── components/
│   │   └── HelloWorld.vue
│   ├── App.vue
│   └── main.js            # 或者main.ts(如果选了TypeScript)
├── .gitignore
├── index.html             # 入口HTML文件,Vite把它放在根目录下(和Vue CLI不一样!这点很重要,别乱移)
├── package.json
├── package-lock.json/yarn.lock/pnpm-lock.yaml # 不同包管理器的版本锁定文件
├── vite.config.js         # Vite配置文件(如果用TypeScript是vite.config.ts)
└── README.md

对比两个默认结构,注意3个核心差异

  1. 入口HTML文件的位置:Vue CLI放在public/下,Vite放在根目录下——Vite这么做是因为它的构建逻辑不一样,直接从根目录的index.html开始解析依赖,所以别随便把Vite的index.html移到public里,不然项目跑不起来。
  2. 构建配置文件的名称和位置:Vue CLI用vue.config.js(有时候初始化不会自动生成,需要手动创建),放在根目录下;Vite用vite.config.js/ts,也放在根目录下——两个配置文件的功能类似,但语法和插件生态完全不一样,这点新手别搞混。
  3. 默认的开发工具配置:Vue CLI默认生成jsconfig.json,Vite如果选了TypeScript会生成tsconfig.json和tsconfig.node.json(tsconfig.node.json是给Vite的Node.js部分配置的)——这两个文件都是为了让编辑器有更好的代码提示、跳转等功能,一定要保留。

小项目练手/个人博客:简化版Vue3目录结构,够用就行

如果你的项目是练手的TodoList、个人博客这种功能模块不超过5个的小项目,不用搞太复杂的结构,不然反而增加维护成本,我给大家推荐一个我自己练手时常用的简化版结构,只需要在默认结构的基础上加几个必要的目录就行。

简化版结构详解

my-vue3-simple/
├── node_modules/
├── public/
├── src/
│   ├── assets/
│   │   ├── images/         # 专门放图片,比如博客的封面图、头像
│   │   ├── fonts/          # 专门放自定义字体
│   │   └── styles/         # 专门放全局样式,比如reset.css、variables.css、global.css
│   ├── components/         # 通用组件,比如导航栏、页脚、标签、按钮
│   │   ├── NavBar.vue
│   │   ├── Footer.vue
│   │   └── CustomButton.vue
│   ├── views/              # 页面组件,比如首页、文章列表页、文章详情页、关于页
│   │   ├── HomeView.vue
│   │   ├── PostListView.vue
│   │   ├── PostDetailView.vue
│   │   └── AboutView.vue
│   ├── router/             # 路由配置目录,小项目可以只放一个index.js/ts
│   │   └── index.js/ts
│   ├── composables/        # 组合式函数目录,比如useLocalStorage、useTheme
│   │   ├── useLocalStorage.js/ts
│   │   └── useTheme.js/ts
│   ├── utils/              # 工具函数目录,比如日期格式化、字符串处理、防抖节流
│   │   ├── formatDate.js/ts
│   │   └── debounce.js/ts
│   ├── api/                # 接口请求目录,小项目可以只放一个index.js/ts
│   │   └── index.js/ts
│   ├── App.vue
│   └── main.js/ts
├── .env.development        # 开发环境变量配置
├── .env.production         # 生产环境变量配置
├── .gitignore
├── index.html/vite.config.js/ts  # 看用Vite还是Vue CLI
└── package.json

为什么加这几个目录?

  1. assets/styles/images/fonts:把不同类型的静态资源分开,找的时候更方便——比如你想换个全局背景色,直接去assets/styles/global.css里找就行,不用在一堆图片和字体里翻。
  2. views/:默认结构里没有views,通用组件和页面组件混在一起太乱——通用组件是可以在多个页面复用的,比如NavBar、CustomButton;页面组件是对应路由的,比如HomeView、PostDetailView,两者功能不一样,必须分开。
  3. router/:默认结构里没有router,小项目哪怕只有3个路由,单独建个目录放也比写在main.js里好——后续加路由守卫或者拆分路由模块(虽然小项目不用拆分)都方便。
  4. composables/:这是Vue3新增的组合式函数专属目录,一定要加——比如你写了一个切换主题的useTheme,可能在NavBar、AboutView里都要用,放在这里统一管理,不用每个页面都复制一遍逻辑。
  5. api/:默认结构里没有api,哪怕只有1个接口,单独建个目录放也比在页面组件里直接写axios好——后续接口改路径或者参数,只需要改api/index.js/ts里的一个地方。
  6. .env.development和.env.production:默认结构里没有环境变量配置,但小项目也可能用到——比如开发环境用本地接口http://localhost:3000,生产环境用线上接口https://api.myblog.com,这时候就需要用环境变量来区分,不用每次打包前手动改接口路径。

中大型团队协作项目:规范版Vue3目录结构,模块化才是核心

如果你的项目是电商平台、管理后台这种功能模块超过10个、有多人协作的中大型项目,简化版结构肯定不够用,必须采用模块化(Feature-First或者Module-First)的结构——也就是按业务功能模块来组织文件,而不是按文件类型来组织(不过工具类、通用组件类还是按类型组织)。

为什么中大型项目推荐模块化结构?举个电商平台的例子:如果按类型组织,订单相关的组件在views/orders/,订单相关的组合式函数在composables/orders/,订单相关的接口在api/orders/,订单相关的样式在assets/styles/orders/,每次做订单功能的迭代,得在4个不同的目录里跳来跳去,极其浪费时间;如果按模块化组织,订单相关的所有文件都放在modules/orders/里,找的时候直接去一个目录就行,效率提升很多。

规范版模块化结构详解

my-vue3-large/
├── node_modules/
├── public/
├── src/
│   ├── assets/             # 全局静态资源,按类型组织
│   │   ├── images/
│   │   │   ├── logos/      # 平台logo、品牌logo
│   │   │   ├── icons/      # 通用图标,比如箭头、加号、减号
│   │   │   └── placeholders/ # 占位图
│   │   ├── fonts/          # 全局自定义字体
│   │   └── styles/         # 全局样式
│   │       ├── reset.css   # 重置浏览器默认样式
│   │       ├── variables.css # 全局CSS变量,比如颜色、字体大小、间距
│   │       ├── mixins.css  # 全局CSS混合宏(如果用Sass/Less)
│   │       └── global.css  # 全局通用样式
│   ├── common/             # 全局通用模块,按类型组织(和简化版的components、composables、utils类似,但更规范)
│   │   ├── components/     # 全局通用组件,任何模块都能复用
│   │   │   ├── layout/     # 布局组件,比如头部、侧边栏、内容区、页脚
│   │   │   │   ├── Header.vue
│   │   │   │   ├── Sidebar.vue
│   │   │   │   ├── Content.vue
│   │   │   │   └── Footer.vue
│   │   │   ├── ui/         # UI组件库的二次封装或者自定义UI组件,比如按钮、输入框、下拉框、表格
│   │   │   │   ├── MyButton.vue
│   │   │   │   ├── MyInput.vue
│   │   │   │   ├── MySelect.vue
│   │   │   │   └── MyTable.vue
│   │   │   └── business/   # 全局通用业务组件,比如登录弹窗、上传组件、富文本编辑器
│   │   │       ├── LoginModal.vue
│   │   │       ├── UploadImage.vue
│   │   │       └── RichTextEditor.vue
│   │   ├── composables/    # 全局通用组合式函数,任何模块都能复用
│   │   │   ├── useAuth.js/ts # 登录认证相关,比如获取用户信息、退出登录、检查登录状态
│   │   │   ├── useRequest.js/ts # 统一请求封装,比如处理loading、错误提示、token刷新
│   │   │   ├── useTable.js/ts # 表格相关,比如分页、排序、筛选
│   │   │   └── usePermission.js/ts # 权限控制相关,比如检查按钮权限、页面权限
│   │   ├── utils/          # 全局通用工具函数
│   │   │   ├── date.js/ts  # 日期格式化、日期计算
│   │   │   ├── string.js/ts # 字符串处理、正则验证
│   │   │   ├── storage.js/ts # localStorage、sessionStorage、Cookie操作
│   │   │   └── validate.js/ts # 表单验证规则
│   │   ├── constants/      # 全局常量,比如状态码、错误提示、路由路径前缀
│   │   │   ├── statusCode.js/ts
│   │   │   ├── errorMessage.js/ts
│   │   │   └── routePrefix.js/ts
│   │   └── directives/     # 全局自定义指令,比如v-loading、v-permission、v-lazy
│   │       ├── loading.js/ts
│   │       ├── permission.js/ts
│   │       └── lazy.js/ts
│   ├── modules/            # 业务功能模块,按功能组织(核心核心核心!)
│   │   ├── user/           # 用户模块
│   │   │   ├── components/ # 用户模块专用组件,不能在其他模块复用
│   │   │   │   ├── UserInfoCard.vue
│   │   │   │   ├── UserAddressForm.vue
│   │   │   │   └── UserOrderList.vue
│   │   │   ├── views/      # 用户模块对应的页面组件
│   │   │   │   ├── UserLoginView.vue
│   │   │   │   ├── UserRegisterView.vue
│   │   │   │   ├── UserCenterView.vue
│   │   │   │   └── UserAddressListView.vue
│   │   │   ├── composables/ # 用户模块专用组合式函数
│   │   │   │   ├── useUserLogin.js/ts
│   │   │   │   ├── useUserRegister.js/ts
│   │   │   │   └── useUserAddress.js/ts
│   │   │   ├── api/        # 用户模块专用接口
│   │   │   │   └── index.js/ts
│   │   │   ├── constants/  # 用户模块专用常量
│   │   │   │   └── index.js/ts
│   │   │   ├── styles/     # 用户模块专用样式
│   │   │   │   └── index.css/scss/less
│   │   │   ├── types/      # 用户模块专用TypeScript类型定义(如果用TypeScript)
│   │   │   │   └── index.ts
│   │   │   └── router.js/ts # 用户模块专用路由配置
│   │   ├── product/        # 商品模块
│   │   │   ├── components/
│   │   │   ├── views/
│   │   │   ├── composables/
│   │   │   ├── api/
│   │   │   ├── constants/
│   │   │   ├── styles/
│   │   │   ├── types/
│   │   │   └── router.js/ts
│   │   ├── order/          # 订单模块
│   │   │   ├── components/
│   │   │   ├── views/
│   │   │   ├── composables/
│   │   │   ├── api/
│   │   │   ├── constants/
│   │   │   ├── styles/
│   │   │   ├── types/
│   │   │   └── router.js/ts
│   │   └── ...             # 其他业务功能模块
│   ├── router/             # 全局路由配置,用来整合各个业务模块的路由
│   │   ├── index.js/ts     # 全局路由入口
│   │   └── modules/        # 如果业务模块太多,也可以把各个模块的路由单独放在这里,不过推荐还是放在modules/对应的模块里
│   ├── store/              # Pinia状态管理目录,按功能组织或者按类型组织都可以,推荐按功能组织
│   │   ├── index.js/ts     # Pinia入口文件,初始化Pinia实例
│   │   ├── modules/        # Pinia状态模块,和业务功能模块对应
│   │   │   ├── user.js/ts  # 用户状态模块,比如存储用户信息、token
│   │   │   ├── product.js/ts # 商品状态模块,比如存储购物车、收藏夹
│   │   │   └── order.js/ts # 订单状态模块,比如存储当前订单信息
│   │   └── types/          # Pinia状态模块的TypeScript类型定义(如果用TypeScript)
│   │       └── index.ts
│   ├── App.vue             # 根组件,主要用来放全局布局组件(比如Header、Sidebar、Content、Footer)
│   └── main.js/ts          # 应用入口文件,初始化Vue应用实例、注册全局组件、全局指令、全局样式、Pinia、Router等
├── .env                    # 通用环境变量配置,不管是开发还是生产环境都会加载
├── .env.development        # 开发环境变量配置,覆盖通用环境变量
├── .env.staging            # 预发布环境变量配置(可选,中大型项目一般有)
├── .env.production         # 生产环境变量配置,覆盖通用环境变量
├── .env.local              # 本地环境变量配置(可选,覆盖所有其他环境变量,不会被Git提交)
├── .gitignore
├── .eslintrc.js/ts         # ESLint配置文件,用来检查代码规范
├── .prettierrc             # Prettier配置文件,用来格式化代码
├── .stylelintrc.js/ts      # Stylelint配置文件,用来检查CSS/Sass/Less规范
├── commitlint.config.js/ts # Commitlint配置文件,用来检查Git提交信息规范
├── husky/                  # Husky目录,用来配置Git钩子(比如pre-commit、commit-msg)
├── index.html/vite.config.js/ts
└── package.json

规范版结构的几个核心亮点

  1. 按业务功能模块化组织modules/:这个是最大的亮点,业务迭代效率提升至少30%——比如老板让你改订单模块的退款功能,你只需要打开modules/order/目录,就能找到所有相关的组件、组合式函数、接口、样式,不用到处跳。
  2. common/目录更细的分类:把全局通用模块分成components/layout、components/ui、components/business、composables、utils、constants、directives,找起来更方便,复用率更高——比如你想找全局通用的表格组件,直接去common/components/ui/MyTable.vue里找就行。
  3. Pinia状态管理按功能组织store/modules/:和业务功能模块对应,比如用户状态放在store/modules/user.js/ts里,商品状态放在store/modules/product.js/ts里,状态管理更清晰,不会像Vuex那样把所有状态都堆在一个文件里。
  4. 丰富的代码规范和Git钩子配置:中大型项目多人协作,代码规范和Git提交信息规范很重要——ESLint检查JavaScript/TypeScript规范,Prettier格式化代码,Stylelint检查CSS/Sass/Less规范,Commitlint检查Git提交信息规范,Husky配置pre-commit钩子(提交前自动检查代码规范和格式化)和commit-msg钩子(提交前自动检查提交信息规范),能有效避免代码混乱和提交垃圾信息。
  5. 完善的环境变量配置:通用环境变量、开发环境变量、预发布环境变量、生产环境变量、本地环境变量都有,满足不同场景的需求——比如本地环境可以用Mock数据接口,不用等后端接口写完就能开发前端功能。

适配新兴开发场景的调整:Vue3+SSR/SSG、Vue3+Electron、Vue3+UniApp

现在的Vue3不再只是做单页应用(SPA)了,还可以做服务端渲染(SSR)、静态站点生成(SSG)、桌面应用(Electron)、跨端应用(UniApp),不同的场景对应的目录结构也要做一些调整。

Vue3+SSR/SSG(用Nuxt 3)

如果你想做SEO友好的项目,比如电商平台的首页、商品详情页、个人博客,推荐用Nuxt 3——Nuxt 3是基于Vue3的SSR/SSG框架,它有自己默认的目录结构,不需要我们手动搭太多,只需要按它的规则来就行。

Nuxt 3的默认目录结构(假设项目名是my-nuxt3):

my-nuxt3/
├── .nuxt/                 # Nuxt自动生成的临时文件,千万不要手动改
├── node_modules/
├── public/                # 静态资源目录,和Vue CLI/Vite的public一样
├── assets/                # 需要被Nuxt处理的静态资源,和Vue CLI/Vite的assets一样
├── components/            # 通用组件目录,Nuxt会自动注册,不需要手动import
├── composables/           # 组合式函数目录,Nuxt会自动注册,不需要手动import
├── pages/                 # 页面组件目录,Nuxt会自动生成路由,不需要手动配置router
├── layouts/               # 布局组件目录,Nuxt会自动注册,不需要手动import
├── middleware/            # 中间件目录,用来处理路由守卫
├── plugins/               # 插件目录,用来注册全局组件、全局指令、全局样式、第三方库等
├── server/                # 服务端代码目录(SSR/SSG专用)
│   ├── api/               # 服务端接口目录
│   ├── middleware/        # 服务端中间件目录
│   └── routes/            # 服务端路由目录
├── store/                 # Pinia状态管理目录,Nuxt会自动注册,不需要手动初始化
├── utils/                 # 工具函数目录,Nuxt会自动注册,不需要手动import
├── .env
├── .env.development
├── .env.production
├── .gitignore
├── nuxt.config.ts         # Nuxt配置文件
├── package.json
└── README.md

Vue3+Electron(用Electron Forge或者Vite Electron Builder)

如果你想做桌面应用,比如笔记软件、音乐播放器,推荐用Vite Electron Builder——它是基于Vite的Vue3+Electron构建工具,构建速度快,配置简单。

Vite Electron Builder的默认目录结构(假设项目名是my-vue3-electron):

my-vue3-electron/
├── node_modules/
├── public/
├── src/
│   ├── main/               # Electron主进程代码目录
│   │   ├── index.js/ts     # 主进程入口文件
│   │   └── preload.js/ts   # 预加载脚本,用来在渲染进程和主进程之间建立通信
│   └── renderer/           # Electron渲染进程代码目录,就是普通的Vue3项目结构
│       ├── assets/
│       ├── components/
│       ├── views/
│       ├── router/
│       ├── composables/
│       ├── utils/
│       ├── api/
│       ├── App.vue
│       └── main.js/ts
├── .env
├── .env.development
├── .env.production
├── .gitignore
├── index.html
├── vite.config.js/ts      # Vite配置文件,需要配置Electron相关的插件
├── package.json
└── README.md

Vue3+UniApp(用HBuilderX或者Vue CLI/Vite)

如果你想做跨端应用,比如同时兼容微信小程序、支付宝小程序、抖音小程序、H5、App,推荐用UniApp——它是基于Vue3的跨端框架,一套代码可以编译到多个平台。

UniApp的默认目录结构(用Vite初始化,假设项目名是my-vue3-uniapp):

my-vue3-uniapp/
├── node_modules/
├── public/
├── src/
│   ├── assets/
│   ├── components/        # 通用组件目录
│   ├── pages/             # 页面组件目录,需要在pages.json里配置路由
│   ├── static/            # 静态资源目录,和Vue CLI/Vite的public一样
│   ├── store/             # Pinia状态管理目录
│   ├── uni_modules/       # UniApp插件市场的插件目录
│   ├── App.vue            # 应用配置文件(比如全局样式、全局生命周期)
│   ├── main.js/ts         # 应用入口文件
│   ├── manifest.json      # 应用配置文件(比如应用名称、版本号、权限)
│   └── pages.json         # 页面路由配置文件
├── .env
├── .env.development
├── .env.production
├── .gitignore
├── vite.config.js/ts      # Vite配置文件,需要配置UniApp相关的插件
├── package.json
└── README.md

最后再提几个搭建Vue3目录结构时的避坑建议

  1. 目录名和文件名要统一规范:比如目录名用小写字母加下划线(user_address)或者小写字母加短横线(user-address),不要用驼峰命名(UserAddress);通用组件用大驼峰命名(MyButton.vue),页面组件用大驼峰加View后缀(UserLoginView.vue),组合式函数用小驼峰加use前缀(useUserLogin.js/ts),工具函数用小驼峰(formatDate.js/ts)——统一规范很重要,不然团队协作时会很乱。
  2. 不要把所有文件都堆在根目录下:除了配置文件、入口HTML文件、package.json这些必须放在根目录下的文件,其他所有源代码都要放在src/目录下——不然根目录会很乱,找配置文件都难。
  3. 不要过度模块化:小项目就用简化版结构,不要强行用模块化结构,不然反而增加维护成本;中大型项目的业务功能模块划分要合理,不要太细也不要太粗——比如电商平台的商品模块,不要分成商品列表、商品详情、商品搜索三个模块,放在一个product模块里就行。
  4. 不要随便修改默认目录的名称:比如不要把components改成comp,不要把views改成page,不然其他开发者接手时会看不懂——除非你的团队有统一的约定。
  5. 一定要写README.md:README.md里要写清楚项目的介绍、技术栈、目录结构说明、环境变量说明、如何安装依赖、如何启动开发环境、如何打包生产环境——不管是小项目还是中大型项目,README.md都很重要。

好啦,关于Vue3目录结构的内容就说到这里,希望能帮到大家,如果你有更好的目录结构方案,欢迎在评论区留言交流。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门