前端資源治理(一):問題及思路

  • 2019 年 12 月 16 日
  • 筆記

0.也談前端工程化

隨著前端技術的飛速發展,前端需要一種更加工程化的方式解決前端開發日益複雜的問題。前端工程化本質也是軟體工程的一種,由於軟體工程並無嚴格的定義(或者說缺乏統一的定義),因此前端工程化的內涵其實相當寬泛,一般來說,前端工程化重點關注的是研發和維護效率,所有最終目的是這個的,都可以算作前端工程化的範疇。前端工程化近幾年也是技術熱點,基本上大型前端技術交流會議都有此專題,從規範、組件、編譯及構建、工作流、持續集成、監控等多個維度都有涉及,筆者嘗試從前端資源治理的角度談一下前端工程化,本文是系列文章的第一篇,主要講問題及解決的思路,不涉及具體的實現細節。

1.前端資源治理的含義

首先,這裡所說的前端資源,並非是僅指js、css、圖片等靜態資源,頁面、後端介面、配置數據、監控點等,都可以納入前端資源的定義的範疇。

在工作中,你是否會碰到以下問題:

  1. 同事或者領導發現某個頁面有bug,需要在微信群或者內部溝通工具大群里問是誰負責?可能還要挨個艾特各個TL,需要各個TL確認。
  2. 某個組件要升級,但是不知道那些頁面使用了,需要在溝通群里問或者搜項目源程式碼,逐個找到負責人。
  3. 某個大型營銷活動突然要換一個新的氛圍logo,但是不知道哪些頁面使用了舊logo,需要安排巡檢,人肉去找出來。
  4. 告警發現某個重要頁面的出現了內容空窗,原因是運營同學沒有及時補充運營數據,但是不知道是哪個運營負責,需要在微信大群或者內部溝通工具大群里問。
  5. 大促來臨,某個重要頁面的流量預計有10倍或者20倍的增長,要通知各個介面的同學做擴容和容災準備,需要手工梳理頁面的依賴的介面列表。
  6. 某個限時的頁面已經到點下線,但是仍然有流量,不知道流量入口在哪裡。
  7. 我要在統計系統上查看某個頁面的性能數據,但是該系統是以頁面名字而不是地址來查找的,查找過程找的人老眼昏花。
  8. 某個後端介面要升級或者要下線,需要分析nginx的訪問日誌找到頁面地址,然後再拉各個TL,逐個確認都是哪些同事負責。
  9. 等等等

上面的問題一般是大型複雜業務場景(通常是多個團隊合作開發,業務複雜,頁面成百上千甚至上萬)下才有的,如果你所在的團隊也有上面的問題,那麼我認為你也需要對前端的資源進行治理。

那麼什麼是前端資源治理呢?筆者對其的定義是:

將前端相關的頁面、js/css/圖片/字體、介面、配置、監控點等的依賴關係進行收集、存儲和管理,並將割裂的組件系統、配置系統、監控系統、業務系統等進行重構和整合,最終形成以頁面管理為基礎的統一的有序的平台,所有關聯資訊都能夠被查詢和檢索,最終實現整體協作效率的提升。

此處使用「治理」而不是「管理」的原因,「治理」一詞更強調合作整改的過程。在很多互聯網企業,通常已經有一些獨立的組件系統、配置系統、監控系統等,但是這些系統很多都是獨立的碎片化的系統,彼此都是割裂的,割裂意味著缺乏協同,進而影響研發效率。因此,前端資源治理的一個關鍵詞是「整合」,整合已有的系統。

第二個關鍵詞是「關聯關係管理」,前端相關的頁面、組件、js/css/圖片/字體、介面、配置、監控點及負責人等,他們是存在關聯關係的,比如頁面是誰負責的、誰修改的、引用了哪些組件、圖片、字體、介面、在什麼地方配置數據、監控點都有哪些等,我們需要把這些關聯關係在管理端記錄下來,並提供檢索和查詢。

2.前端資源治理的實現

前端資源資訊看似繁雜,js、css、圖片、頁面、後端介面、配置數據、監控點等,但是他們有一個串聯的錨點,這個錨點就是頁面,不管是H5、小程式,還是原生APP,不管是從研發的角度,還是從回饋問題的角度,基本上都是以頁面為單位進行的,其他的如組件、CSS、圖片、介面、配置等,都是被頁面引用的,都可以通過頁面串聯起來的,下圖可以清晰的表達出這些依賴關係。

因此,實現前端資源治理的第一個要點是做好頁面管理,把頁面自身的資訊,如頁面名稱、頁面地址、負責人、修改時間等資訊進行提取、存儲,使之能夠被查詢和檢索。在頁面管理基礎之上,我們還要把js、css、圖片、頁面、後端介面、配置數據、監控點等各個前端資源之間的關聯關係也要存儲和管理起來,使之能夠被查詢和檢索。

關聯關係從來源上講,主要有以下幾種來源:

  1. 程式碼靜態分析產生。通常包括頁面資訊自身、頁面跟js/css/圖片等的依賴關係、頁面跟介面的依賴關係等。
  2. 管理端配置產生。通常包括頁面跟監控系統的配置、頁面的運營配置數據等
  3. 統計數據產生。通常包括頁面來源數據等。

2.1 頁面資訊的提取

前端資源治理的第一要點是頁面資訊管理,因此必須能夠拿到頁面基本資訊。頁面基本資訊應該包括哪些呢?通常來說,至少應該包括頁面URL、頁面名稱、頁面創建人、創建時間等幾個欄位。

當前的前端頁面開發,不管是H5、小程式,還是原生APP,通常會經過編譯構建的過程(通常是命令行工具或者IDE,比如基於gulp和webpack的工作流工具),在構建完成階段可以提取出頁面的基本資訊。以下是編譯構建提取頁面資訊的流程:

頁面的編譯構建流程,一般分為兩種:

  1. 獨立構建。常見於H5,此種場景一般是一個人負責一個頁面,不存在多人協作的情況,也不需要git分支管理啥的,開發完成即可走構建流程,只需要在構建完成的時候分析即可,頁面的URL、頁面標題、創建人、創建時間等資訊比較容易提取,比如頁面修改人可以取自命令行工具的用戶登錄身份(命令行工具可以做類似於NPM的login功能,登錄後記錄用戶身份ID)、頁面標題可以解析頁面html的title的內容(小程式下則解析自頁面json文件的navigationBarTitleText欄位)等。
  2. 持續集成構建。這種一般是需要多人協作的H5、小程式、原生APP等,一般涉及到分支管理和合併的問題,同一個頁面可能被多人修改,因此頁面資訊中的用戶資訊部分提取相對複雜,需要分析git log資訊才能拿到,其他的資訊欄位提取邏輯與獨立構建情況相同。以下是一個典型的多人協作的頁面的git log資訊。

對於上面的情況,我們可以考慮定一個規則,比如取最近的5條log,並移除持續集成系統生成的log,管理端存儲的時候回,以用戶名+時間為key,去掉重複的部分。

構建流程分析出頁面基本資訊後,需提交到管理端保存,所以管理端需要提供post介面。管理端以此為基礎,形成」頁面管理系統「。

2.2 程式碼靜態分析出的關聯關係

構建流程除可以分析基本資訊外,還可以分析出頁面的版本資訊,比如頁面依賴的組件依賴表、靜態資源依賴表(js/css/圖片)、介面依賴表、修改人、修改時間等。靜態依賴分析通常有3種方式:

  1. 基於AST的依賴分析。AST就是抽象語法樹,目前前端對他的研究和使用越來越廣泛,webpack內部就使用了acorn這個AST分析庫。藉助於webpack強大的模組解析和依賴分析能力,我們可以拿到js與npm組件、css與背景圖等之間的關聯關係(可以在webpack的after-resolve鉤子中進行分析)。另外,除了構建前的依賴關係,我們還可以拿到構建處理後的資源依賴關係(可以在webpac的emit鉤子中進行分析),前者我們稱為引用依賴關係(包括靜態資源依賴表、組件依賴表),後者我們稱為發布依賴關係。
  2. 基於DOM操作的依賴分析。webpack並不是以html為入口的,但是實際上我們的開發的入口可以認為就是頁面,藉助於JsDom等強大的類庫,我們可以用我們熟悉的前端的DOM操作來分析html頁面對js、css、圖片等的依賴關係。
  3. 基於正則匹配的依賴分析。頁面對於介面的依賴分析,由於這種是非明確的程式碼依賴關係,所以一般通過正則匹配來解析。一般對程式碼有一定的約束規則,比如不用用變數拼接介面地址。這個解析不會如AST那麼精確,但是只要約定規則,基本上都能滿足需求。可以考慮把此類實現封裝為webpack的loader。

上面的第一種和第三種的分析,都應該是一個遞歸分析過程,最終生成頁面的靜態資源依賴表、組件依賴表、介面依賴表等。這些資訊提交到管理端進行保存。

2.3 管理系統之間的關聯關係

在很多互聯網企業,通常已經有一些獨立的成熟的CMS系統(如給運營用的內容配置系統,配置活動時間、商品ID等)、監控系統(如測速系統、業務監控系統、異常監控系統)等,通常這些系統由不同的團隊開發,而且經常都有一個叫做"頁面管理"的東西,且要手工配置頁面地址。這些系統中的監控點配置、運營配置等資訊,都是以頁面維度進行創建和使用的,但是這些資訊很難通過對前端程式碼靜態分析的方法進行提取(比如運營配置資訊,這個可以是前端直接使用,也可能是後端使用,要分析的話兩端程式碼都要分析,比較麻煩)。我們的思路應該是在管理端通過頁面管理來進行關聯,實質上是要做系統整合。

整合的思路也比較簡單,就是原來各個系統廢棄掉原來自身的」頁面管理「,而是使用前面靜態分析提取到的統一的頁面管理,監控系統、運營配置系統等系統都可以以此為入口進入,從而把頁面相關的各個管理系統關聯起來,進而把各種能力串聯。

2.4 統計數據產生的關聯關係

對於大型應用來說,一般都有一些業務統計數據,最典型的就是點擊流數據了。這種數據既不在程式碼中,也不在管理端配置,而且通過統計和分析才能拿到。前面提到的「某個限時的頁面已經到點下線,但是仍然有流量,不知道流量入口在哪裡」這種問題的解決,其實依賴於點擊流的統計分析數據了,點擊流系統一般都有「來源分析」,這種數據也不是敏感數據,所以可以考慮跟頁面管理做關聯和整合,或者提供API給頁面管理系統。另外還有一個例子就是,介面和頁面的關聯關係,前面提到通過靜態分析得到的頁面和介面的依賴表有可能不夠準確,但是介面訪問Web Server的時候,一般都有access.log,可以通過access.log來做分析,拿到比較完整的頁面依賴的介面資訊,以及介面依賴的頁面資訊,有些介面的調用需要有open api的那種註冊調用機制,就另當別論了。

2.5 關聯關係的查詢和存儲

管理端應該提供正反兩個方向的查詢和檢索能力:

  1. 正向查詢。通過頁面來查詢依賴的組件、靜態資源(js/css/圖片)、後端介面等。此種比較簡單,因為提交的時候已經有完整的依賴資訊,只需要提供簡單的查詢。
  2. 反向查詢。通過組件、靜態資源、介面、運營配置資訊、監控配置資訊等,反查有哪些頁面依賴。

對於關聯關係的存儲,用關係型DB的話,一般只能使用like查詢,可能要掃描全表,因而性能比較差,可以考慮存儲到MongoDB中創建索引,或者存儲到ElasticSearch中建立索引。

2.6 其他

前面提到的,其實有一個假設的前提「只有一個Web應用,且介面都是前端發起的」,但是對於其他情況,思路是類似的:

  1. 多應用(業務)。多應用情況,通常要在頁面管理的上一層加上「應用管理」,即頁面屬於哪一個應用(業務)。對於同一個頁面投放在不同應用的場景,可能頁面還得加上渠道標識。
  2. 頁面直出(服務端渲染)。對於頁面直出邏輯的程式碼,做前面類似的分析即可。另外,本文主要是探討從前端視角考慮問題,所以關聯核心是頁面管理,但是從整體技術架構視角,可能就不是了。

3.結語

本文探討了前端資源治理的含義以及要解決的問題,並介紹了實現前端資源治理的思路,是筆者近期在前端工程化方面的思考,部分已經完成,部分正在推進。本文並不涉及實現的細節,細節在後面的系列文章中進一步講解。前端治理的兩個關鍵點,一個是系統整合,一個是關聯關係管理,整體串聯的核心是頁面管理。