良好的目录结构设计可以在保证代码功能模块清晰的同时提供很好的扩展性,给项目带来长久的生命力。

项目目录结构

通常来说,整个项目的代码都在 src 目录下。我们建议 src 目录组织如下:

src
|
+-- assets          # 图片字体等静态资源
|
+-- components      # 全应用共享的公共组件
|
+-- config          # 全局配置、环境变量等。在这里导出,应用中其他代码通过导入获取。
|
+-- context         # 所有的全局 context
|
+-- features        # 功能模块目录,也可以叫 pages
|
+-- hooks           # 全应用共享的公共 hooks
|
+-- lib             # 导出预处理过的公共库,比如添加了 interceptor 的 axios 实例。
|
+-- routes          # 路由配置
|
+-- test            # 测试代码
|
+-- types           # 整个应用共用的 typescript 类型定义
|
+-- utils           # 整个应用共享的 utils 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

功能模块目录结构

为了保证能以最简单、最具可维护性的方式扩展应用,我们应该尽可能将代码约束在 features 目录中。每个 feature 目录中应该仅仅包含这个功能特有的代码,避免功能特有的代码与其他公共代码混合在一起。维护一个功能模块的代码比维护一个偏平的大目录更加简单。

一个 feature 目录的结构如下:

src/features/awesome-feature
|
+-- api         # 导出与这个功能相关的所有 API 请求
|
+-- components  # 这个功能内的公共组件,其他地方不能使用
|
+-- hooks       # 这个功能内使用的 hooks,其他地方不能使用
|
+-- routes      # 功能内的路由配置
|
+-- types       # 功能内的 typescript 类型定义
|
+-- utils       # 功能内使用的 utils 函数
|
+-- index.ts    # 功能入口点,同时也可以在这里导出任何可以被其他地方使用的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

feature 目录下的 index.ts 应该导出所有这个功能模块可以对外提供的 API。

比如我们可以在其他模块这样导入 awesome-feature 内的 AwesomeComponent

import {AwesomeComponent} from "@/features/awesome-feature"
1

但是不能像下面这样导入 AwesomeComponent

import {AwesomeComponent} from "@/features/awesome-feature/components/AwesomeComponent"
1

ESLint 提供了一个配置可以帮助我们禁止上面这种直接导入方式。配置如下:

{
    rules: {
        'no-restricted-imports': [
            'error',
            {
            patterns: ['@/features/*/*'],
            },
        ],

    ...rest of the configuration
}
1
2
3
4
5
6
7
8
9
10
11

关注微信公众号,获取最新推送~

加微信,深入交流~