Web應用的組件化(二)——管控平臺 #7

Web應用的組件化(二)

管控平臺

在上一篇中咱們提到了組件化的大體思路,這一篇主要講述在這麼作以後,咱們須要哪些外圍手段去管控整個開發過程。從各類角度看,面對較大規模前端開發團隊,都有必要創建這麼一個開發階段的協做平臺。前端

在這個平臺上,咱們要作哪些事情呢?node

1. HTML片斷

咱們爲何要管理HTML片斷?由於有界面要用它們,當這些片斷多了以後,須要有個地方來管理起來,能夠檢索、預覽它們,還能看到大體描述。git

這應該是整個環節中一個相對很簡單的東西,照理說,有目錄結構,而後剩下的就是單個的HTML片斷文件了,這就能夠解決存儲和檢索的問題了,但咱們還要考慮更多。後端

已有的HTML片斷,如何被使用呢?這確定是一種相似include的方式,經過某種特殊標籤(無論是前端仍是後端的方式)把這些片斷引用進來,這時候就有了第一個問題:前端工程化

假設有界面A和界面B同時引用了片斷C,在某個開發人員修改片斷C內容的時候,他如何得知將會影響到界面A和B呢?一個比較勉強的方式是全項目查找,但這在不少狀況下是不夠的。瀏覽器

若是咱們的HTML片斷是做爲獨立的公共庫存在的,它已經不能經過項目內查找去解決這一問題了,由於無論A仍是B,只要他不處於片斷C的項目空間,就無從追尋。服務器

這時候不少人會問兩個問題:markdown

  1. 跨項目的界面片斷重用,意義在哪裏?架構

    若是咱們的產品是針對一個小領域,它的複雜度根本不須要劃分多個項目部分來協做完成。設想場景是面對很大的行業,各項目都是子產品,未來多是其中若干個聯合部署,這時候,保持其中的一致性是很是重要的。好比咱們有個基本配置界面,在多個子產品中都要用,若是各自開發一個,其操做風格極可能就是不一致的,給人的印象就是不專業。因此會須要把常見的界面片斷都歸集起來,供業務方挑選使用。框架

  2. 修改C,只提供說明,可是不通知A和B,不實時更新他們的版本,而後自行決定怎樣升級,如何?

    這會有一個問題,每次有小功能升級的時候,代碼是最容易同步合併的,因此纔會有「持續集成」這個概念,若是是一直伴隨升級,總要比隔一個大階段才升級好,升級成本應儘可能分攤到平時,就像農婦養小豬,小豬天天長一點,天天都抱來抱去,不以爲吃力,即便長大了也還能抱得動。

如今問題就很明確了,必定要有一種方式來把這個依賴關係管理起來,很顯然,已有的版本庫是確定管不了這些的,因此只能在外圍作一些處理。

咱們創建一個管理平臺,除了管理實體文件的版本,還管它們之間的關係。具體這個關係如何收集整理,有兩種方式:手動配置,代碼分析。

手動配置是比較土的方式,開發人員每提交一個文件,就去這系統上手動配置它的依賴關係。代碼分析的話,要在每次提交文件的時候解析文件的包含規則,找出確切的文件。這二者各有利弊,前者比較笨,但容易作,後者對代碼格式的要求比較高,要考慮的狀況較多。

咱們的界面每每不是那麼簡單,HTML片斷也可能有層次的,舉例來講:

界面A裏面包含了片斷B,可是片斷B自身又包含了片斷C,因此這個依賴關係也是有層級的,須要在設計的時候一併考慮。

2. JavaScript模塊

JavaScript代碼的管理,比HTML片斷的情況好一些,由於業界不少這方面的解決方案。但它們仍是沒有解決當依賴項產生變動的時候反向通知的問題。

因此咱們仍是得像HTML片斷同樣,把它們的依賴關係都管理到平臺裏。因而,每一個JavaScript模塊都顯式配置了本身所依賴的其餘模塊,經過這種單向關係,造成了一套完整的視圖。

在JavaScript模塊的代碼實現中,咱們是不提倡直接寫依賴關係的。不少通用規範,好比AMD,每每建議咱們這樣寫模塊:

    define(['dep1', 'dep2'], function (dep1, dep2) { var moduleA = function () {}; return moduleA; });

但咱們的系統是面向行業的,比這種通用解決方案要苛刻一些。好比說,若是有一天重構代碼,JavaScript模塊們調整了目錄或者名字,這麼寫的就痛苦了,他必須把全部影響到的都去調整一遍,這是要搜索替換的。何況,就像上面HTML模板的部分提到的,影響了處於其餘項目中依賴它的代碼,缺乏合適的方式去通知他們修改。

因此咱們指望的是,在每一個編寫的JavaScript模塊中只存放具體實現,而把依賴關係放在咱們的平臺上管理,這樣,即便當前模塊做了更名之類的重構處理,處於外部項目中依賴它的那些代碼也沒必要修改,下一次版本發佈的生成過程會自動把這些事情幹掉。

對應到上面的這段代碼,咱們須要開發人員作的只是其中的實現,也就是moduleA的那個部分,外面這些依賴的殼子,是會在發佈階段根據已配置的依賴關係自動生成的。

若是須要,JavaScript模塊還能夠細分,好比相似Angular裏面那樣,把factory,controller和directive分離出來,這會對後續有些處理提供方便。

如今咱們有必要討論一下模塊的粒度了,咱們這裏提到的都是基本的粒度,每一個JavaScript模塊中存放的應該只有一個很具體東西的實現。那麼,有個問題,在咱們發佈的時候,是否是就按照這個粒度發佈出去呢?

很顯然不行,若是這麼作,極可能會出現複雜界面一次要用10多個HTTP請求才能加載完它所須要的全部JavaScript代碼的狀況,因此須要作一些合併。

那麼,合併的策略是什麼?在咱們這個平臺上,開發人員又是要怎樣定義這個合併關係的呢?咱們須要在模塊之上定義一個更大粒度的組織方式,這個方式與模塊的關係,就比如Java裏面,jar文件與class的關係。若是開發人員不顯式配置,也能夠經過全局策略,好比按最下層目錄來合併。

這個時候,在實際使用這些代碼的時候,須要帶兩個配置信息過去,一個是要動態載入的JavaScript文件(合併以後的),二是每一個JavaScript文件中包含的原始模塊。

3. 單元測試

若是JavaScript模塊都已經被良好有序管理起來,就能夠爲它們考慮單元測試的事情了。單元測試對於提升基礎單元的可靠度,是有很是重要意義的。

在咱們這個平臺裏,能夠把單元測試跟JavaScript模塊關聯起來,每一個JavaScript模塊能夠掛一組單元測試代碼,這些代碼能夠在線編寫,在線運行。

單元測試的本質就是編寫模擬代碼來調用已有模塊,考慮到咱們的模塊是JavaScript,因此不少思路都傾向於在瀏覽器端執行它們,對於單個模塊的單元測試,這不是個問題。

若是要批量執行整個系統的單元測試,那就不同了。把JavaScript代碼先加載到瀏覽器中,而後再執行,不少時候並不須要這麼複雜。咱們徹底能夠在服務端把它們作了。

藉助Node.js的能力,咱們能夠在服務端執行JavaScript代碼,也就意味着可以把絕大多數JavaScript模塊的單元測試在服務端就執行掉。固然,咱們爲此可能要多作很多事情,好比說,有些庫須要移植一份node版的,常見的有AJAX調用等等。

注意了,可以在服務端作JavaScript單元測試是有先決條件的,代碼的分層必須很良好,除了視圖層,其餘任何層面都不能操做DOM。因此咱們這裏主要測試的也正是除了視圖層以外的全部JavaScript業務邏輯。至於視圖層怎麼辦?這個真的很難解決,這世界上不是全部東西都能自動作的,只能先把可作的作了,之後再來考慮這些。

4. 文檔和示例管理

4.1. 文檔

如今咱們有HTML片斷和JavaScript模塊了,須要給它們多一些描述信息。簡單描述顯然是不夠的,咱們還要詳細文檔。

這種詳細文檔能夠經過某種方式生成,也能夠由開發人員手動編寫。與傳統的離線文檔不一樣,在線的文檔更實時,而且,每當一個開發人員變動了他的文檔以後,不須要通過全量構建,訪問者能夠實時訪問到他的最新版本。

熟悉GitHub的朋友們可能早已習慣這種方式,在項目庫裏面存在一些以md格式結尾的文本文件,使用markdown語法來編寫一些說明文檔。

毫無疑問,這類格式很適合在線協做,因此咱們也會在平臺上集成這麼一種編寫文檔的方式,不管是針對HTML模板仍是JavaScript模塊,或者是其餘什麼類型,甚至還能夠用來當博客,就像月影同窗的gitpress平臺,能直接從GitHub上拉取文本或者HTML文件造成博客。

文檔除了以集成的形式瀏覽以外,應當也能夠以單獨連接的方式發出去,這時候用戶就能夠像看一個新聞網頁同樣去瀏覽。若是再進一步作下去,還能夠作電子書的生成,提供打包的離線文檔。

4.2. 示例

在編寫代碼文檔的過程當中,可能免不了要插入示例,示例有兩種形態,一種是純文本,相似gist這樣,一種是可在線運行,相似jsfiddle和jsbin這樣。

這兩種都有各自的優勢,因此能夠都作,示例的存放能夠與文檔相似,也應當能經過一個連接獨立運行。

4.3. 幻燈片

有時候咱們看到一些在線的幻燈片,以爲效果很帥,好比reveal.js,咱們的開發人員有時候做代碼分析或者走查的時候也難免要寫一些演示,若是能把這些東西也隨項目管理起來,能在線查看,會是很不錯的一件事。因此咱們也能夠考慮給它們加個存儲界面,甚至作個簡易的在線編寫器。

5. 項目與目錄管理

說到如今,咱們彷佛還遺漏了一點什麼。那就是以上提到的這些東西,以什麼爲組織單位來存儲?

考慮到咱們的這個平臺是要管理一整個大產品的所有前端內容的,它裏面應該分了不少項目,對應到子產品上,這麼一來,很天然地,項目就成了第一級組織單位。項目之下,沒有懸念地,只有目錄了。

對於一個項目而言,它有哪些要作的事情呢?首先要能配置其實體存儲位置。前面提到的這麼多代碼、文檔之類,最終都是要實體存儲的,怎麼存?咱們固然能夠本身搞一套,在文件系統上作起來,可是還要考慮它們的版本管理,很是麻煩,因此不如直接對接某個版本庫,調用它的接口去存取文件,這裏配置的就是版本庫的路徑。

其次,要考慮從已有項目複製,相似GitHub裏面的fork功能,不過內部處理機制能夠略有不一樣,fork的項目默認未必要有實體文件,只有當產生了修改或者新增操做的時候才建立,剩下的還引用原來的就能夠了。咱們這裏的項目複製功能是爲項目化版本而考慮的,常常出現一個產品版本支持多個客戶項目的狀況,因此可能會用得着這個特性。

而後,也要考慮項目的依賴關係。依賴一個項目,意思是須要用到它裏面的組件,因此實質是組件的依賴。提供項目依賴這個視圖,只是爲了將來變動的一些考慮。

6. 評論管理

以前提到,咱們整個平臺的目的是爲了提升大型前端團隊的協做能力,協做是離不開交流的。上述的任何功能,都應當帶有交流溝通的能力。

好比說,若是開發人員A使用了其餘人寫的一個代碼組件a,對其中一些細節有疑問,他應當能夠對它進行評論。在他評論的時候,任何參與維護過這個組件的人員都能收到一個提醒,這時候他能夠選擇過來看看,回覆這個疑問。同理,在文檔、示例下也能夠如此操做。

在互聯網上有這類產品,用於在任意URL下掛接評論交流系統,比較有名的就是Disqus,咱們能夠看到不少網站下面掛着它,用於作交流評論,這樣用戶能夠用一個帳號在多個網站之間交流。國內也有同類的,好比多說,可以用微博、QQ等帳號登陸進行交流。

從咱們這個平臺自己看,若是是部署在企業內部做流程提高,引入外部評論系統的可能性就比較小了。由於在企業內部用,必定是但願這個員工的帳號信息跟工號掛鉤,也可以跟版本服務器帳號等模塊做集成,權限也便於控制。

從另一個角度講,某我的員登陸這個系統的時候,他可能收到不少消息,來自不一樣的代碼或文檔位置,挨個點過去回覆也有些麻煩,咱們應當給他提供一個全局視圖,讓他能在一個統一的界面把這些問題都答覆掉,若是他須要的話,也是能夠點進去到實際的位置。

7. 用戶和權限控制

從以上部分咱們已經看到,這個系統是一個比較複雜的開發過程管控平臺。這樣的話,每一個使用的人就應當能夠登陸,而後分配不一樣的權限等級。

未登陸用戶應當有一些東西的查看權限,可是不能發表評論。已登陸的用戶根據權限級別,能夠控制可否建立、修改項目,建立、修改目錄,代碼,單元測試,文檔等。

8. 國際化字符串管理

一個跨語言區域的Web應用不可避免要跟國際化打交道,這個事情一般是在服務端作,好比經過在界面代碼中嵌入相似<% =getRes(key, lan) %>這樣的代碼,去獲取相應的字符串,替換到界面裏來。

這個事情是要佔用應用服務器資源的,並且國際化自己實際上是一個在運行以前就已經肯定的事,徹底能夠把這個過程放在發佈階段就作掉。好比說,咱們給每種語言預先就把代碼生成多份,只是部署在一塊兒,根據須要的狀況來動態加載特定的那一份。

有很多客戶端的國際化方案,是把資源文件拆細,以頁面爲單位存儲,但這實際上是不太合理的。第一個緣由就是在Web2.0時代,「頁面」這個概念自己就已經弱化了,到了單頁應用裏,整個應用都只是一個頁面,這個時候,資源文件以什麼粒度來組織呢?

咱們提到過,採用MV*框架去作Web應用的架構,有一個目標是作組件化。組件化的意圖就是某個組件能夠儘量爲所欲爲地放在須要的地方用。若是把資源文件的粒度弄小到對應HTML片斷和JavaScript模塊這一級,靈活性卻是有了,帶來的問題就是管理成本增大。

作一個行業應用,最重要的就是業務一致性,這包括邏輯的一致性,也包括了術語的一致性。某一個詞,可能在多個資源文件中都出現,這就增長了不一致的可能性。

因此,應當有一個統一的術語管理平臺,一切界面上出現的文字或者提示,都必須來自這個平臺。

9. 靜態資源的管理

在發佈系統的時候,除了須要發佈代碼,還須要發佈圖片等靜態資源,這些東西也應當被管理起來。

靜態資源在兩種狀況下可用:隨產品發佈,在本平臺被引用。好比說有一個圖片,在這個平臺上做了管理,它能夠被配置到某個項目上,在發佈的時候導出。這個圖片還能夠被用連接的方式查看或者下載,若是本平臺內部的一個文檔或者示例要引用它,也是能夠的。

10. 樣式與主題管理

在Web系統裏,樣式和主題是很重要的一環。樣式的管理和發佈一直是一個比較複雜的話題,早幾年通常都是分塊寫,而後組合合併,最近這些年有LESS,SASS和Stylus這類技術,解決了編寫和發佈的分離問題。

咱們看看發佈的最大問題是什麼?是不一樣部分的合併。爲了追求靈活性,不得不把東西拆得很細,以前HTML片斷和JavaScript模塊的處理方式都是這樣。這麼作,咱們就須要另一件事:這些細小的東西,儘量要覆蓋全面。

對應到CSS裏面,咱們要作的是把每種在系統中可能出現的元素、類別都做爲單獨的規則維護起來,生成一個全局的規則列表。不一樣項目間,實現能夠不一樣,但規則的名字是固定的,定製只容許修改實現,不容許修改規則。若是要新增以前沒有的規則,也必須在全局規則列表裏先添加,再做實現。

樣式規則被管理以後,能夠在界面組件上對它做關聯,也能夠不作。作的好處是發佈的時候能只把用到的那些樣式規則生成發佈出去,若是能接受每次發佈全量CSS,那也無所謂。

除了規則,也須要考慮一些變量的管理,在CSS中合理使用變量,會大爲減輕定製化所致使的工做量。

11. 一鍵發佈

咱們引入了這麼一堆東西,實際上是增長了發佈的複雜度。爲何呢?

以前無論HTML、JavaScript仍是CSS,都是手寫出來,最多通過一個minify的工做,就發佈了,整個過程很簡單,兩句腳本搞定。

如今可複雜了,先要分析依賴關係,而後提取文件,而後國際化字符串替換,而後合併,而後代碼壓縮,整個過程很折騰,不給配置管理員一個解釋的話,他必定過來砍人。

咱們有個原則:解決問題的過程當中,若是引入了新的問題,要求負責解決原問題的人也一塊兒解決掉。如今爲了一些意圖,增長了版本發佈的複雜度,那也要有個辦法再把這事擺平,至少不能比原來複雜。

因此咱們就要把這些過程都集成到管控平臺裏,作一個一鍵發佈的過程,把全部的這些操做都集成起來,配置管理員發佈版本的時候只要點一下就能夠把全部這些事情作掉。甚至說,這些流程還能夠配置,可以加減環節。

這時候咱們作到了跟以前發版本同樣方便,能不能多作點什麼呢?

能夠把JavaScript單元測試集成到版本發佈階段。由於咱們已經把JavaScript按照職責作了分層,而且把UI部分作了隔離,就能夠在瀏覽器以外把這個單元測試作掉,平時提交代碼的時候也能夠作,最終在版本發佈階段再全量作一下,也是頗有意義的。

代碼依賴關係管理的另外一個目的是什麼呢?是最小化發佈,既然咱們都管理了文件之間的關係,那麼,從根出發,顯然是可以得出哪些代碼文件在本項目中使用的,就能夠每次從咱們的全量代碼庫中取得確切須要的一部分來發布。這也是咱們整個管控平臺帶來的優點。

12. 小結

咱們這一篇比較複雜,提出了一整套解決大規模前端協做的管控機制。這套理論的本質是在開發和版本發佈之間加了一個環節,把Web體系中除了服務以外的一切靜態資源都歸入其中,強化了現有主流的一些基於命令行的前端工程化組織模式。

相比於傳統行業,好比汽車製造,咱們這個環節至關於生產流水線的設計,其中一些組件的存儲就相似倉儲機制,發佈就相似出廠過程。

這個平臺自己還有很多其餘的可作的東西,好比甚至能夠在上面作界面的可視化定製等,這些是長遠的終極目標,在後面的文章裏會談談一些考慮。

後續文章中,咱們會展望有了這個平臺以後,整個前端的協做流程是怎樣的。

相關文章
相關標籤/搜索