<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何創(chuàng)建可擴(kuò)展和可維護(hù)的前端架構(gòu)

          共 5182字,需瀏覽 11分鐘

           ·

          2021-10-19 23:34

          點(diǎn)擊上方 前端瓶子君,關(guān)注公眾號

          回復(fù)算法,加入前端編程面試算法每日一題群

          現(xiàn)代的前端框架和庫可以輕松地創(chuàng)建可重用的 UI 組件。在創(chuàng)建可維護(hù)前端應(yīng)用方面,這是一個(gè)很好的方向。但是,在多年來的許多項(xiàng)目中,我發(fā)現(xiàn)開發(fā)可重復(fù)使用的組件常常是不夠的。我的項(xiàng)目由于需求的變化或者新需求的出現(xiàn)而變得不可維護(hù)。要查找正確的文件或調(diào)試多個(gè)文件所需的時(shí)間越來越長。

          必須改變。我可以提高搜索技能,或者更熟練地使用 Visual Studio Code。但我并不是唯一在前端工作的人。所以,我們需要對前端項(xiàng)目進(jìn)行設(shè)置。要讓它們變得更易于維護(hù)和擴(kuò)展。那意味著我們可以對當(dāng)前特性進(jìn)行修改,但也可以更快地添加新特性。

          1高級架構(gòu)

          對于后端開發(fā),我們可以遵循很多架構(gòu)模式。領(lǐng)域驅(qū)動(dòng)開發(fā)(domain-driven development,DDD)和關(guān)注點(diǎn)分離(separation of concerns,SoC)是目前使用的兩個(gè)概念。這兩個(gè)概念給前端開發(fā)帶來了巨大價(jià)值。在 DDD 中,你試著把相似的特性分組合起來,并盡量使它們和其他組(比如模塊)解耦。而在 SoC 中,例如,我們可以分離邏輯、試圖和數(shù)據(jù)模型(例如,使用 MVC 或 MVVM 設(shè)計(jì)模式)。

          希望現(xiàn)代的前端應(yīng)用程序能完成越來越多的繁重工作。當(dāng)復(fù)雜度增加時(shí),Bug 也會(huì)變得更加頻繁。由于用戶和前端的交互,我們需要一個(gè)既可維護(hù)又可擴(kuò)展的可靠架構(gòu)。在這一點(diǎn)上,我的首選架構(gòu)是模塊化和領(lǐng)域驅(qū)動(dòng)的。記住,我的想法也許會(huì)改變,但這是我此刻首選的方式。

          當(dāng)用戶與我們的應(yīng)用交互時(shí),應(yīng)用將路由引導(dǎo)用戶到正確的模塊。每一個(gè)模塊都被完全包含。然而,如果用戶想要使用一個(gè)應(yīng)用,而非幾個(gè)小應(yīng)用,就會(huì)有一些藕合。該耦合存在于特定的特性或業(yè)務(wù)邏輯中。有幾個(gè)特性可以在模塊間共享。你可以將該邏輯放在應(yīng)用層。也就是說,每個(gè)模塊可以選擇與應(yīng)用層進(jìn)行交互。例如,需要通過客戶端的 API 連接到后端,或者設(shè)置 API 網(wǎng)關(guān)。

          在查看項(xiàng)目的結(jié)構(gòu)時(shí),我們可以遵循如下所示的內(nèi)容。應(yīng)用層的所有代碼都在 app 目錄下。并且所有的模塊都有一個(gè)目錄,位于 modules 目錄下。不依賴業(yè)務(wù)邏輯的可重復(fù)使用的 UI 組件(如表格)在 components 目錄下。

          app/assets/components/lib/modules/styles/

          其余的目錄存放我們的靜態(tài) assets(如圖片)或者 lib 中的輔助函數(shù)。輔助函數(shù)可以非常簡單。它們可以將某些東西轉(zhuǎn)換為某種格式,或者幫助處理對象。但更復(fù)雜的代碼可以存放于 lib 目錄中。處理模式或圖的工作(例如檢查有向圖中的循環(huán)的算法)也不例外。

          很多人都使用 CSS-in-JS 或樣式組件之類的東西,但是我更喜歡普通的 CSS。為什么呢?無需 JavaScript,我們可以使用 CSS 和 HTML 解決很多 UI 問題。當(dāng)我們應(yīng)用 SoC 的概念時(shí),這會(huì)變得更加容易。此外,在一個(gè)地方維護(hù) CSS 使你更容易維護(hù),因?yàn)槟憧梢詼p少重復(fù)的工作。它要求一個(gè)穩(wěn)定的 CSS 架構(gòu)。盡管我會(huì)在另一篇博文中討論這個(gè)問題,但是我的 CSS 架構(gòu)是基于 Harry Roberts 的 ITCSS。

          2填寫應(yīng)用細(xì)節(jié)

          通過高層和項(xiàng)目結(jié)構(gòu),我們已經(jīng)有了一個(gè)良好的開端。然而,為了實(shí)現(xiàn)這一前端架構(gòu),我們還需要更多的細(xì)節(jié)。我們先來看看更詳細(xì)的架構(gòu)圖,如下圖所示。在這幅圖中,我放大了應(yīng)用層,但同時(shí)也放大了一個(gè)模塊。在我們的前端應(yīng)用中,應(yīng)用層是我們的核心,所以我們首先討論它。

          應(yīng)用層由兩部分組成:存儲(chǔ)和客戶端 API。存儲(chǔ)是我們的全局應(yīng)用狀態(tài)。這個(gè)狀態(tài)保存著不同模塊在同一時(shí)間可以存取的數(shù)據(jù)。即使在屏幕上不需要這些數(shù)據(jù),它也會(huì)持續(xù)存在于存儲(chǔ)中。正如你所看到的,每一個(gè)發(fā)送到存儲(chǔ)的更新請求都可以通過一連串的邏輯。這就是我們所說的中間件。這是 Redux 中使用的一種模式。中間件的一個(gè)簡單例子是記錄存儲(chǔ)的傳入請求。

          有時(shí)候,需要通過外部服務(wù)中的數(shù)據(jù)對存儲(chǔ)的傳入請求進(jìn)行增強(qiáng)。在 Redux 中,我們使用 Promise 處理這個(gè)調(diào)用。它可能是后端服務(wù),但是它也可能是公共的第三方 API。有些情況下,只需使用瀏覽器 fetch API 就可以實(shí)現(xiàn)單一目的的 REST 調(diào)用。如果希望使用同一個(gè) API 來執(zhí)行不同的調(diào)用,那么創(chuàng)建 API 客戶端定義是個(gè)不錯(cuò)的想法。

          基本的 API 客戶端處理外部請求、響應(yīng)和錯(cuò)誤。你甚至可以讓它為你提供有關(guān)請求狀態(tài)的信息(例如,加載)。不過,更復(fù)雜的 API 客戶端可以處理更多的事情。有些 API 通過 web-socket 連接甚至是 GraphQL API。在這種情況下,你將擁有更多的配置選項(xiàng),如下圖所示。

          對于更加復(fù)雜的 API 客戶端,我們可以通過中間件修改所有發(fā)出的請求(例如,添加認(rèn)證頭)。響應(yīng)可以由后件修改(比如更改數(shù)據(jù)結(jié)構(gòu))。更改響應(yīng)之后,我們將其存儲(chǔ)在客戶端的緩存中,這就像應(yīng)用存儲(chǔ)一樣。有什么不同嗎?緩存只處理傳入的 API 數(shù)據(jù),而我們可以把任何數(shù)據(jù)放入應(yīng)用存儲(chǔ)里。

          很多前端應(yīng)用都會(huì)有專門的后端服務(wù)來對話。無論是在有許多微服務(wù)的 Kubernetes 集群之上的 API 網(wǎng)關(guān),還是一個(gè)單一的單體后端。但是有時(shí)候我們需要連接到不同的外部服務(wù)。使用這種架構(gòu),我們可以創(chuàng)建大量的 API 客戶端。每個(gè) API 客戶端都有緩存、中間件和后件。我們應(yīng)用的不同部分應(yīng)該能夠與這些 API 客戶端中的每一個(gè)進(jìn)行交互。

          應(yīng)用目錄的相應(yīng)項(xiàng)目結(jié)構(gòu)可以如下所示:

          app/  api/config/  store/pubsub/  schemas/  index.js

          app 中的兩個(gè)目錄現(xiàn)在聽起來應(yīng)該很熟悉:api 和 store。這兩個(gè)目錄保存了與前面描述的用例有關(guān)的所有內(nèi)容。config 存放靜態(tài)定義和配置(比如常量),用于整個(gè)應(yīng)用。schemas 描述了 JavaScript 對象的特定數(shù)據(jù)結(jié)構(gòu)。這在使用 TypeScript 或 JavaScript 時(shí)都可以使用。應(yīng)用的所有通用模式都存儲(chǔ)在 schemas 目錄中。

          pubsub 是一個(gè)很好的例子,它可以擴(kuò)展前端的基本架構(gòu)。pubsub 可以用于模塊通信或管理預(yù)定作業(yè)。因?yàn)樗鼘τ趹?yīng)用的核心很重要,所以它位于 app 目錄內(nèi)。最后,我們得到了 index.js 文件。通過這個(gè)文件,我們可以添加 app 目錄中的所有函數(shù)和常量。這就是說,這個(gè)文件的功能是進(jìn)入應(yīng)用邏輯的入口點(diǎn)。

          3模塊的架構(gòu)

          介紹了應(yīng)用層之后,就剩下模塊了。詳細(xì)的架構(gòu)圖已經(jīng)顯示了一個(gè)模塊的內(nèi)部結(jié)構(gòu)。如果應(yīng)用的路由指向一個(gè)特定的模塊時(shí),這個(gè)模塊就會(huì)決定路由應(yīng)該如何繼續(xù)。模塊的路由決定哪個(gè)頁面應(yīng)該顯示。一個(gè)頁面包括許多 UI 組件,也就是用戶在屏幕上看到的內(nèi)容。

          在本例中,頁面與 UI 組件沒有任何區(qū)別。它是一個(gè)大的 UI 組件。然而,其他模塊可以與組件(和動(dòng)作)交互,但不能與頁面交互。只有使用嵌套路由才能使來自不同模塊的頁面相互作用。這就是說,你將模塊的路由放在不同模塊的頁面中。

          組件通過動(dòng)作與應(yīng)用層交互。這些動(dòng)作可能表現(xiàn)為各種形式。它們可以是普通的 JavaScript 函數(shù)、Redux 相關(guān)函數(shù)或者 React Hooks。有時(shí)候,你有一些小的實(shí)用函數(shù)專門用于某些模塊。如果是這樣,你可以將它們放到 actions 目錄下,也可以為模塊創(chuàng)建一個(gè)專門的 utils 目錄。下面顯示了項(xiàng)目的模塊結(jié)構(gòu):

          users/  actions/  components/config/    constants.js    routes.js    tables.js        forms.js  pages/gql/  schemas/  index.js

          和應(yīng)用層一樣,我們也可以有靜態(tài)代碼(如常量或模式定義),而只涉及到我們的模塊。本例中,我們將這些代碼放入 config 或 schema 目錄下。在使用 GraphQL 時(shí),可以有查詢和變異的定義。這些應(yīng)該放在 gql 目錄下(或者一個(gè)具有相似用途的目錄)。添加 interface.js 文件,用于存儲(chǔ)該模塊的應(yīng)用。這個(gè)文件描述了如何訪問存儲(chǔ)中的數(shù)據(jù)。

          index.js 作為 app 目錄的 index.js。在這里,我們描述了供他人訪問的所有的組件、動(dòng)作和常量。

          4模塊的通信

          并不是每個(gè)模塊都需要擁有上述所有的目錄和文件。比如,有些模塊不需要頁面,因?yàn)樗鼈冎话ńM件和動(dòng)作?!癴iles”模塊就是一個(gè)很好的例子。這個(gè)模塊結(jié)合了組建和動(dòng)作來查看和上傳文件。一個(gè)例子是一個(gè)拖放文件的區(qū)域,將結(jié)果上傳到一個(gè) blob 存儲(chǔ)。它可以成為可重復(fù)使用的組件。但是,文件的實(shí)際上傳取決于我們能夠使用的服務(wù)。我們通過將 UI 組件和上傳文件的實(shí)際動(dòng)作結(jié)合起來,創(chuàng)建了一個(gè)小的包含模塊。將組件與業(yè)務(wù)邏輯結(jié)合在一起時(shí),我們將其轉(zhuǎn)換為模塊。

          但是其他模塊是如何使用文件模塊中的組件或者動(dòng)作的?模塊的 index.js 文件描述了哪些組件、動(dòng)作和常量可以被其他組件訪問。因此,我們可以在文件模塊中使用文件拖放區(qū)或上傳動(dòng)作。然而,有時(shí)候我們需要選擇我們想要公開的內(nèi)容。這是一個(gè)動(dòng)作,還是我們要將這一動(dòng)作合并為一個(gè)組件?

          下面來看看用戶下拉列表的示例。通過創(chuàng)建動(dòng)作,可以為我們提供可以從不同模塊選擇的所有用戶。不過,現(xiàn)在我們需要在其他所有模塊中創(chuàng)建一個(gè)特定的下拉列表。這可能不需要太多努力,就能得到一個(gè)通用的下拉組件。但這個(gè)組件可能無法在窗體中工作。也許有必要?jiǎng)?chuàng)建一個(gè)可以使用的 UserDropdown 組件?,F(xiàn)在我們只在用戶周圍更改一個(gè)組件時(shí)更改。因此有時(shí)候我們需要選擇公開的內(nèi)容:動(dòng)作或組件。

          在組件之間使用的一種高級模式是使用 pubsub。在這個(gè)模式下,不能共享組件,但是我們可以共享數(shù)據(jù)。上面的圖片說明了它的工作原理。再一次強(qiáng)調(diào)一下,這是一種高級模式,僅當(dāng)你想要走微型前端路線或者需要的時(shí)候。

          5UI 組件剖析

          還缺少最后一個(gè)細(xì)節(jié)層面,那就是 UI 組件的架構(gòu)。我在以前的博文中已經(jīng)對此進(jìn)行過描述。你可以從這種解剖圖中看到一些我們已經(jīng)廣泛應(yīng)用的概念。

          前端是用戶的第一個(gè)入口點(diǎn)。當(dāng)前端項(xiàng)目特性增加時(shí),我們也引入了更多的 Bug。但是我們的用戶期望沒有 Bug,新特性也會(huì)更快。那不可能。但是,只要有了一個(gè)好的架構(gòu),我們就能盡可能達(dá)到這個(gè)目標(biāo)。

          作者介紹:

          Kevin Pennekamp,富有創(chuàng)意的前端工程師。喜歡 CSS,并遵循一些基本的工程原則。

          原文鏈接:

          作者 | Kevin Pennekamp
          譯者 | Sambodhi
          策劃 | 辛?xí)粤?
          來自|InfoQ
          https://dev.to/crinklesio/how-to-create-a-scalable-and-maintainable-front-end-architecture-4f47

          最后

          歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
          回復(fù)「算法」,加入前端編程源碼算法群,每日一道面試題(工作日),第二天瓶子君都會(huì)很認(rèn)真的解答喲!
          回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
          回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
          如果這篇文章對你有幫助,在看」是最大的支持

           》》面試官也在看的算法資料《《
          “在看和轉(zhuǎn)發(fā)”就是最大的支持
          瀏覽 60
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产日皮网站在线观看 | 精品国产a∨一区天美传媒 | 婷婷五月综合网 | 国产精品久久久久久久久久久久久久久久久久 | 久久九九精品免费视频 |