前端项目目录如何组织

背景

最近看了 antd pro 发现其项目的目录结构组织的不错。然后再按照自己的项目经验,对其项目的组织进行修改,现在总结下自己的想法。

正题

我们看下 antd pro 自己生成的目录结构

  ├── mock                     # 本地模拟数据
  ├── public
  │   └── favicon.ico          # Favicon
  ├── src
  │   ├── assets               # 本地静态资源
  │   ├── common               # 应用公用配置,如导航信息
  │   ├── components           # 业务通用组件
  │   ├── e2e                  # 集成测试用例
  │   ├── layouts              # 通用布局
  │   ├── models               # dva model
  │   ├── routes               # 业务页面入口和常用模板
  │   ├── services             # 后台接口服务
  │   ├── utils                # 工具库
  │   ├── g2.js                # 可视化图形配置
  │   ├── theme.js             # 主题配置
  │   ├── index.ejs            # HTML 入口模板
  │   ├── index.js             # 应用入口
  │   ├── index.less           # 全局样式
  │   └── router.js            # 路由入口
  ├── tests                    # 测试工具
  ├── README.md
  └── package.json

区分通用组件和业务组件

由于 antd pro 本身引用了 antd 的组件库,所以不存在自己写通用组件的步骤。但是有的时候我们自己项目会有自己写通用组件的需要。组件除了有通用组件,还会有业务组件。通用组件是粒度比较细且和业务无关的组件,譬如 Dropdown。而业务组件可能是你这个项目特有的,譬如工具栏,或者某种特殊的弹框。业务组件大多数情况是由(但不仅仅由)通用组件组成。业务组件是粒度比较粗的组件。所以这个时候我一般会把通用组件放在 components 目录下,而新建一个 widgets 目录放业务组件,这样分的比较清楚。不过通用组件和业务组件的划分边界并不是每次都能分的很清楚,有时是会相互转换的,如果实在觉得很难区分,那可以都放在 components 下。

领域对象

src/models 目录放的是 dva model,如果你用 redux,那么这里大致可能对应的是 state 的概念,如果用 mobx 这里隐约对应的是 store 的概念。在我看来这些都不是 model,只能叫做状态(state)相关。我个人理解的 model 应该指的是领域对象也就是领域驱动设计(Domain-Driven Design)中的 domain object,类似于 java bean 的概念。所以我会把放在 models 下面的东西用一个新的目录存放,通常叫 stores,而 models 下面会放领域对象(domain object)。拿 todo list 为例,我会抽象出一个 TodoItem 的领域对象,其定义:

class TodoItem {
  id = -1;
  text = '';
  done = false;

  constructor( rawData ) {
    if ( rawData ) {
      Object.assign( this, rawData );
    }
  }
}

export default TodoItem;

枚举

这个简单,通常项目都不会少了枚举值,这个时候我会单独新建一个 enums 的目录放项目所用到的所有枚举对象。当然,如果很少的话并入 common 目录也未尝不可。 这个时候 src 目录基本上会变成这样:

  ├── mock                     # 本地模拟数据
  ├── public
  │   └── favicon.ico          # Favicon
  ├── src
  │   ├── assets               # 本地静态资源
  │   ├── common               # 应用公用配置,如导航信息
  │   ├── enums                # 枚举
  │   ├── components           # 通用组件
  │   ├── widgets              # 业务组件
  │   ├── e2e                  # 集成测试用例
  │   ├── layouts              # 通用布局
  │   ├── stores               # 状态相关对象(dva model)
  │   ├── models               # domain object
  │   ├── routes               # 业务页面入口和常用模板
  │   ├── services             # 后台接口服务
  │   ├── utils                # 工具库
  │   ├── g2.js                # 可视化图形配置
  │   ├── theme.js             # 主题配置
  │   ├── index.ejs            # HTML 入口模板
  │   ├── index.js             # 应用入口
  │   ├── index.less           # 全局样式
  │   └── router.js            # 路由入口
  ├── tests                    # 测试工具
  ├── README.md
  └── package.json

精简

看上目录很多,这里我精简下,如果你的项目没有复杂的布局,没有可视化图形配置,没有复杂的路由且用了 react-router4,最后没有可配置主题那么基本的目录结构可以精简为:

  ├── mock                     # 本地模拟数据
  ├── public
  │   └── favicon.ico          # Favicon
  ├── src
  │   ├── assets               # 本地静态资源
  │   ├── common               # 应用公用配置,如导航信息
  │   ├── enums                # 枚举
  │   ├── components           # 通用组件
  │   ├── widgets              # 业务组件
  │   ├── stores               # 状态相关对象(dva model)
  │   ├── models               # domain object
  │   ├── routes               # 业务页面入口和常用模板
  │   ├── services             # 后台接口服务
  │   ├── utils                # 工具库
  │   └── index.js             # 应用入口
  ├── tests                    # 测试工具
  ├── README.md
  └── package.json

优化

如果项目前期设计做的好,抽象建模工作做的到位,其实你会发现,项目目录大致还可以分为两类:UI 相关和 UI 无关的。这个时候我会把 UI 相关的放到一个 app 的目录下,整个项目就会分成 MV(model,view) 的层次:

  ├── mock                     # 本地模拟数据
  ├── public
  │   └── favicon.ico          # Favicon
  ├── src
  │   ├── app
  │   │    ├── assets               # 本地静态资源
  │   │    ├── components           # 通用组件
  │   │    ├── widgets              # 业务组件
  │   │    ├── stores               # 状态相关对象(dva model)
  │   │    ├── routes               # 业务页面入口和常用模板
  │   │    └── index.js
  │   ├── common               # 应用公用配置,如导航信息
  │   ├── enums                # 枚举
  │   ├── models               # domain object
  │   ├── services             # 后台接口服务
  │   ├── utils                # 工具库
  │   └── index.js             # 应用入口
  ├── tests                    # 测试工具
  ├── README.md
  └── package.json

这么做的用意是当你的项目 UI 框架重构的时候可以只动 app 目录。从 redux 变到 mobx,也可以从 react 变成 angular。当然这层抽象不是必须的,只是我个人偏好,如果要重构通常也会整个项目重构。

总结

以上就是我根据 antd pro 修改的,我认为比较通用的项目目录结构(这里没有提到测试相关)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容