前言
好的書本分章節、好的代碼分模塊,那麼好的架構該如何定義呢?
咳咳,不要意思,題目起大了~~ 小生之輩,豈敢以架構而論。
不過話說來,很多人都認為前端無非就是 HTML+CSS+JS,一個目錄一類文件,有何架構可言。但是我想說。。。。你說的都對!
但是,筆者一直在探索不同的頁面架構組織形式,鄙人愚見,好的架構,能夠方便拓展和開發以及後期的項目維護。
在筆者剛開始接觸前端的時候,就一直在思考怎麼樣的架構比較舒服易於擴展,且能裝 B。React-Full-Dianping-Demo裡面就有寫到對於react+react-redux+soga的一些列代碼組織的思考:react技術棧項目結構探究
一直還在學習,本文也只是拿來探討下本次我開發一個頁面時,我個人的一些代碼組織方式。拋個磚~
望各位大佬不嗇賜教。
項目架構
<code>src
├─ action-log
│ ├─ constants.ts
│ └─ index.ts
├─ app.js
├─ app.json
├─ common
│ ├─ animation-utils.ts
│ ├─ business-utils.ts
│ ├─ constants.ts
│ ├─ detail-utils.ts
│ ├─ mtop-utils.ts
│ ├─ net-utils.ts
│ ├─ price-utils.ts
│ ├─ storage-utils.ts
│ ├─ string-utils.ts
│ ├─ time-utils.ts
│ ├─ type.ts
│ ├─ url-utils.ts
│ └─ utils.ts
├─ components
│ ├─ loading-page
│ │ ├─ index.css
│ │ └─ index.tsx
│ └─ pm-bottom
│ ├─ index.css
│ └─ index.tsx
├─ document
│ └─ index.jsx
├─ event
│ └─ EVENTS.ts
├─ modules
│ ├─ bottom-action
│ │ ├─ index.css
│ │ └─ index.tsx
│ └─ page-container
│ ├─ base
│ ├─ decorator
│ ├─ index.tsx
│ └─ libs
└─ pages
├─ buyer-identity
│ ├─ components
│ ├─ constants
│ ├─ customized-hooks
│ ├─ index.tsx
│ ├─ types
│ └─ utils
複製代碼/<code>
或許上面看起來並不是很直觀,截圖解釋下
大概的看下,腦海中有個大概的位置和每個文件的作用。下面我們再來細品
目錄職責
其實劃分了這麼多的目錄,無非就是為了最大可能的複用。其中也包括對於組件狀態的抽離、hooks 特性的利用。
pages 層以外的公共邏輯
畢竟是MPA應用,所以一切還都是圍繞著 pages 展開。
action-log
首先這裡的action-log目錄就不多說了,因為沒有太多可借鑑性。大概就是返回一個 ActionLog對象,來進行一些業務上的埋點、信息收集等邏輯的處理。所以這裡如果大家有一些公共的基礎類封裝,都是可以放這裡的。
common
<code>common
├─ animation-utils.ts
├─ business-utils.ts
├─ constants.ts
├─ detail-utils.ts
├─ mtop-utils.ts
├─ net-utils.ts
├─ price-utils.ts
├─ storage-utils.ts
├─ string-utils.ts
├─ time-utils.ts
├─ type.ts
├─ url-utils.ts
└─ utils.ts
複製代碼/<code>
由於該項目的比較複雜,業務邏輯相對較多。所以這裡我將 utils按照類別,區分出來了以上幾種。方面後期開發中的維護和擴展,也便於查找。
除了一些從命名可以區分出來的utils 以外,這裡還放了一個 type.ts和constants.ts,用途自如其名。
components
相信框架使用者對於 components 的命名都不為陌生.是的,就是對於一些公共組件的封裝,比如我這裡放的兩個組件loading-page,pm-bottom等公共組件。components 相對來說是比較“小”的概念,劃分依據這這個項目中也比較簡單,就是是否為“木偶組件”(雖然 hooks 了以後,咱不太適合這麼說),
modules
<code>modules
├─ bottom-action
│ ├─ index.css
│ └─ index.tsx
└─ page-container
├─ base
│ ├─ base.tsx
│ ├─ error.tsx
│ └─ scrollBase.tsx
├─ decorator
│ └─ withError.tsx
├─ index.tsx
└─ libs
├─ displayName.ts
├─ navbarTransparent.ts
├─ spm.ts
└─ title.ts
複製代碼/<code>
更具有模塊的概念,這裡最典型的page-contaienr的模塊,作用就是每一個頁面的通用底層容器,早在之前的文章中其實有介紹到這個容器,如何用 Decorator 裝飾你的 Typescript,所以這裡就不再贅述了,其實就是一些基礎功能的封裝。所以也就是解釋了event的目錄存在。
而這裡modules和conponents最大的區別就是,複雜度和內部狀態管理。如果內部狀態較為複雜,且有很多的交互,那麼我們就稱之為 module.是的,這裡的界限,我們劃分較為模糊。
但是當你拿到一份設計稿的時候,估計就能明白我的良苦用心了~
紅色框就可以理解為 module,綠色框可以理解為 components
page 的組織
針對單個頁面裡面的組織,其實都大同小異。(突然發現前端架構沒有太多可言)
目錄區分的並不是很多,但是也都較為清晰。簡單介紹下每個區域的分工,需要展開的,我們在後續展開介紹
- index.tsx 頁面的入口文件,但是本身裡面不會編寫太多業務邏輯
- utils 該頁面的工具函數,包括接口的請求、數據的 format等
- customized-hooks 自定義hooks,這裡有兩個,初始化 UI 所需要的數據(邊距等),業務請求的數據。
- constants 頁面的常量,包括請求的 api、spm 埋點、固定的一些該頁面業務數據等
- components 該頁面的組件(注意這裡沒有 module,因為太多了真的容易混亂),頁面的 components,有簡單的,也有複雜的。
以上就是一些目錄結構和代碼組織的交代。其實還是比較簡單清晰的。下面介紹下
頁面數據流向和管理規則
碎碎叨叨道不到個明明白白
因為是業務代碼,所以這裡就不會粘貼太多代碼了
簡單的解釋下上面的流程
初始化 UI 的邏輯比較偏於業務,其實沒有太多可借鑑的。這裡我代碼裡面的工作也就是適配 iPhone X的一些UI。
重點說下初始化接口數據的過程吧。其實也就是各個頁面中的 components 的狀態初始化
interface
首先我們需要定義每一個模塊的 props,畢竟是因為用的 ts,註釋即文檔。所以我們將每一個 components 的 props 都定義到 type 目錄中,畢竟很多時候接口返回的數據,需要我們做一次 format,而這個 format 的目的就是為了 components 更好的使用。換句話說,這些接口,可複用! 那必然定義到外面
注意接口上都要寫註釋啊!!!!理由如下:
將所有數據處理的方法,全部放到 utils 中(注意數據兜底的處理,這裡我所有的數據處理都寫好工具函數,並添加充分的單元測試)
真正的做到對 components 而言,開箱即用。
因為有 type 的定義和 components 之間的約束,所以無論是componemts 內部的數據使用還是 index.tsx 裡面的模塊引入時 props 的注入,都有很好的約束
編寫時候的提醒
漏寫時候的報錯
組件通信
由於我們使用了 hooks,且相對隔離的組件劃分,原則上,組件通信其實並不是很多。當然,也必然是有的。
其實這方面的約束主要歸結於業務的複雜度,如果數據邏輯比較複雜,且通信較多。那麼可以考慮使用 useContext 和 useReducer
說下這次需求中涉及到的通信。
原則:組件儘可能值管理自己的狀態。
遵循如上原則,最終的業務交互邏輯都是由組件內部管理,涉及到的同級通信則通過父組件操作。而父組件操作的原則就是只拿數據,不做任何業務處理。(儘可能的撇清關係)
約束
- index儘可能不寫業務邏輯
- UI 初始化和模塊數據初始化需自定義 hooks
- 狀態儘可能抽離。component 過於複雜需額外抽離 component 、 utils 和 customized-hooks 等。參照上文
- component 的 props 需抽離複用
- 公共 utils 方法編寫充分的單元測試
- 公共 utils 的方法導出需單獨導出(bundle 大小),且編寫註釋(調用時候的提醒)
- 儘可能定義 interface,並且編寫註釋.畢竟註釋即文檔
以上約束後期應該都會編寫相應的 Eslint 來進行強約束(咳咳,程序猿基本素養不可靠)
最後看下我正在補充的單元測試,編寫單元測試過程中,的確發現了不少工具函數的邊緣情況處理的有問題
結束語
按照如上的 page 代碼組織後面又寫了一個頁面,感覺代碼的組織和狀態的管理還是較為清晰的。後續會編寫相應的 cli 來自動生成頁面基礎架構,比如 pmCli add page or pmCli add com
最後,本文只做一個拋轉,並非定義一種規範。更多的約束和組織,希望大家多多交流,互相學習。
學習交流
- 關注公眾號【全棧前端精選】,每日獲取好文推薦
原鏈接:https://juejin.im/post/5e705e4ee51d45270b7d7bb2
閱讀更多 Echa攻城獅 的文章
關鍵字: HTML 上文 TypeScript