前端項(xiàng)目目錄如何組織

背景

最近看了 antd pro 發(fā)現(xiàn)其項(xiàng)目的目錄結(jié)構(gòu)組織的不錯(cuò)。然后再按照自己的項(xiàng)目經(jīng)驗(yàn),對(duì)其項(xiàng)目的組織進(jìn)行修改,現(xiàn)在總結(jié)下自己的想法。

正題

我們看下 antd pro 自己生成的目錄結(jié)構(gòu)

  ├── mock                     # 本地模擬數(shù)據(jù)
  ├── public
  │   └── favicon.ico          # Favicon
  ├── src
  │   ├── assets               # 本地靜態(tài)資源
  │   ├── common               # 應(yīng)用公用配置,如導(dǎo)航信息
  │   ├── components           # 業(yè)務(wù)通用組件
  │   ├── e2e                  # 集成測(cè)試用例
  │   ├── layouts              # 通用布局
  │   ├── models               # dva model
  │   ├── routes               # 業(yè)務(wù)頁面入口和常用模板
  │   ├── services             # 后臺(tái)接口服務(wù)
  │   ├── utils                # 工具庫(kù)
  │   ├── g2.js                # 可視化圖形配置
  │   ├── theme.js             # 主題配置
  │   ├── index.ejs            # HTML 入口模板
  │   ├── index.js             # 應(yīng)用入口
  │   ├── index.less           # 全局樣式
  │   └── router.js            # 路由入口
  ├── tests                    # 測(cè)試工具
  ├── README.md
  └── package.json

區(qū)分通用組件和業(yè)務(wù)組件

由于 antd pro 本身引用了 antd 的組件庫(kù),所以不存在自己寫通用組件的步驟。但是有的時(shí)候我們自己項(xiàng)目會(huì)有自己寫通用組件的需要。組件除了有通用組件,還會(huì)有業(yè)務(wù)組件。通用組件是粒度比較細(xì)且和業(yè)務(wù)無關(guān)的組件,譬如 Dropdown。而業(yè)務(wù)組件可能是你這個(gè)項(xiàng)目特有的,譬如工具欄,或者某種特殊的彈框。業(yè)務(wù)組件大多數(shù)情況是由(但不僅僅由)通用組件組成。業(yè)務(wù)組件是粒度比較粗的組件。所以這個(gè)時(shí)候我一般會(huì)把通用組件放在 components 目錄下,而新建一個(gè) widgets 目錄放業(yè)務(wù)組件,這樣分的比較清楚。不過通用組件和業(yè)務(wù)組件的劃分邊界并不是每次都能分的很清楚,有時(shí)是會(huì)相互轉(zhuǎn)換的,如果實(shí)在覺得很難區(qū)分,那可以都放在 components 下。

領(lǐng)域?qū)ο?/h3>

src/models 目錄放的是 dva model,如果你用 redux,那么這里大致可能對(duì)應(yīng)的是 state 的概念,如果用 mobx 這里隱約對(duì)應(yīng)的是 store 的概念。在我看來這些都不是 model,只能叫做狀態(tài)(state)相關(guān)。我個(gè)人理解的 model 應(yīng)該指的是領(lǐng)域?qū)ο笠簿褪穷I(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(Domain-Driven Design)中的 domain object,類似于 java bean 的概念。所以我會(huì)把放在 models 下面的東西用一個(gè)新的目錄存放,通常叫 stores,而 models 下面會(huì)放領(lǐng)域?qū)ο螅╠omain object)。拿 todo list 為例,我會(huì)抽象出一個(gè) TodoItem 的領(lǐng)域?qū)ο螅涠x:

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

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

export default TodoItem;

枚舉

這個(gè)簡(jiǎn)單,通常項(xiàng)目都不會(huì)少了枚舉值,這個(gè)時(shí)候我會(huì)單獨(dú)新建一個(gè) enums 的目錄放項(xiàng)目所用到的所有枚舉對(duì)象。當(dāng)然,如果很少的話并入 common 目錄也未嘗不可。 這個(gè)時(shí)候 src 目錄基本上會(huì)變成這樣:

  ├── mock                     # 本地模擬數(shù)據(jù)
  ├── public
  │   └── favicon.ico          # Favicon
  ├── src
  │   ├── assets               # 本地靜態(tài)資源
  │   ├── common               # 應(yīng)用公用配置,如導(dǎo)航信息
  │   ├── enums                # 枚舉
  │   ├── components           # 通用組件
  │   ├── widgets              # 業(yè)務(wù)組件
  │   ├── e2e                  # 集成測(cè)試用例
  │   ├── layouts              # 通用布局
  │   ├── stores               # 狀態(tài)相關(guān)對(duì)象(dva model)
  │   ├── models               # domain object
  │   ├── routes               # 業(yè)務(wù)頁面入口和常用模板
  │   ├── services             # 后臺(tái)接口服務(wù)
  │   ├── utils                # 工具庫(kù)
  │   ├── g2.js                # 可視化圖形配置
  │   ├── theme.js             # 主題配置
  │   ├── index.ejs            # HTML 入口模板
  │   ├── index.js             # 應(yīng)用入口
  │   ├── index.less           # 全局樣式
  │   └── router.js            # 路由入口
  ├── tests                    # 測(cè)試工具
  ├── README.md
  └── package.json

精簡(jiǎn)

看上目錄很多,這里我精簡(jiǎn)下,如果你的項(xiàng)目沒有復(fù)雜的布局,沒有可視化圖形配置,沒有復(fù)雜的路由且用了 react-router4,最后沒有可配置主題那么基本的目錄結(jié)構(gòu)可以精簡(jiǎn)為:

  ├── mock                     # 本地模擬數(shù)據(jù)
  ├── public
  │   └── favicon.ico          # Favicon
  ├── src
  │   ├── assets               # 本地靜態(tài)資源
  │   ├── common               # 應(yīng)用公用配置,如導(dǎo)航信息
  │   ├── enums                # 枚舉
  │   ├── components           # 通用組件
  │   ├── widgets              # 業(yè)務(wù)組件
  │   ├── stores               # 狀態(tài)相關(guān)對(duì)象(dva model)
  │   ├── models               # domain object
  │   ├── routes               # 業(yè)務(wù)頁面入口和常用模板
  │   ├── services             # 后臺(tái)接口服務(wù)
  │   ├── utils                # 工具庫(kù)
  │   └── index.js             # 應(yīng)用入口
  ├── tests                    # 測(cè)試工具
  ├── README.md
  └── package.json

優(yōu)化

如果項(xiàng)目前期設(shè)計(jì)做的好,抽象建模工作做的到位,其實(shí)你會(huì)發(fā)現(xiàn),項(xiàng)目目錄大致還可以分為兩類:UI 相關(guān)和 UI 無關(guān)的。這個(gè)時(shí)候我會(huì)把 UI 相關(guān)的放到一個(gè) app 的目錄下,整個(gè)項(xiàng)目就會(huì)分成 MV(model,view) 的層次:

  ├── mock                     # 本地模擬數(shù)據(jù)
  ├── public
  │   └── favicon.ico          # Favicon
  ├── src
  │   ├── app
  │   │    ├── assets               # 本地靜態(tài)資源
  │   │    ├── components           # 通用組件
  │   │    ├── widgets              # 業(yè)務(wù)組件
  │   │    ├── stores               # 狀態(tài)相關(guān)對(duì)象(dva model)
  │   │    ├── routes               # 業(yè)務(wù)頁面入口和常用模板
  │   │    └── index.js
  │   ├── common               # 應(yīng)用公用配置,如導(dǎo)航信息
  │   ├── enums                # 枚舉
  │   ├── models               # domain object
  │   ├── services             # 后臺(tái)接口服務(wù)
  │   ├── utils                # 工具庫(kù)
  │   └── index.js             # 應(yīng)用入口
  ├── tests                    # 測(cè)試工具
  ├── README.md
  └── package.json

這么做的用意是當(dāng)你的項(xiàng)目 UI 框架重構(gòu)的時(shí)候可以只動(dòng) app 目錄。從 redux 變到 mobx,也可以從 react 變成 angular。當(dāng)然這層抽象不是必須的,只是我個(gè)人偏好,如果要重構(gòu)通常也會(huì)整個(gè)項(xiàng)目重構(gòu)。

總結(jié)

以上就是我根據(jù) antd pro 修改的,我認(rèn)為比較通用的項(xiàng)目目錄結(jié)構(gòu)(這里沒有提到測(cè)試相關(guān))。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容