讀百度張雲龍的前端工程有感

小標題:我剛寫前端不到半年,學習速度比較快,也能夠說比較浮躁,最近在研究node,想本身攬了全棧的活兒,偶然看到了一篇叫前端架構那些事兒的文章,因而跟着文章,我找到了張雲龍先生的git,看了一下他對前端架構的見解,自認爲深有感觸,所以記下來,以告訴本身是有多麼膚淺。php

張雲龍先生以切圖仔引入,然而我並不怎麼會切圖,能夠說我是十分業餘的前端設計者,我只會敲敲代碼,搭搭頁面,寫寫動畫,能夠說我巧妙地避過了先生說的人們對前端的見解,想想,「幸運」!css

「前端,是一種GUI軟件」,「從本質上講,全部Web應用都是一種運行在網頁瀏覽器中的軟件,這些軟件的圖形用戶界面(Graphical User Interface,簡稱GUI)即爲前端」,張雲龍先生如是說。我想你們確定都會這麼認爲。如今的前端,已經開始可以處理數據,可以知足許多客戶的需求(固然沒有後臺是不行的),像是一個獨立的應用呈如今客戶面前,需求愈來愈大,愈來愈多,所以,不斷深刻發展的前端邏輯和框架也讓前端成爲了避免能只是一人兩人去搭建的平臺,那麼張雲龍先生認爲前端工程是如何劃分的呢?html

前端工程分三個階段:庫/框架選型、簡單構建優化、JS/CSS模塊化開發、提高多人合做開發效率及性能優化。前端

第一階段:庫/框架選型node

  前端工程建設的第一項任務就是根據項目特徵進行技術選型。git

第二階段:簡單構建優化ajax

  前端工程進行到第二階段會選型一種構建工具,對代碼進行壓縮,校驗,以後再以頁面爲單位進行簡單的資源合併。算法

第三階段:JS/CSS模塊化開發(分治)json

  分而治之是軟件工程中的重要思想,是複雜系統開發和維護的基石,這點放在前端開發中一樣適用。在解決了基本開發效率運行效率問題以後,前端團隊開始思考維護效率,模塊化是目前前端最流行的分治手段。JS模塊化方案不少,AMD/CommonJS/UMD/ES6 Module等,對應的框架和工具也一大堆,提及來很煩,你們自行百度吧;CSS模塊化開發基本都是在less、sass、stylus等預處理器的import/mixin特性支持下實現的。後端

第四階段:組件化開發與資源管理

前端是一種技術問題較少、工程問題較多的軟件開發領域。

當咱們要開發一款完整的Web應用時,前端將面臨更多的工程問題,好比:

  • 大致量:多功能、多頁面、多狀態、多系統;
  • 大規模:多人甚至多團隊合做開發;
  • 高性能:CDN部署、緩存控制文件指紋、緩存複用、請求合併、按需加載、同步/異步加載、移動端首屏CSS內嵌、HTTP 2.0服務端資源推送

 作到第四階段要作的事:

第一件事:組件化開發

分治的確是很是重要的工程優化手段。在我看來,前端做爲一種GUI軟件,光有JS/CSS的模塊化還不夠,對於UI組件的分治也有着一樣迫切的需求:

如上圖,這是我所信仰的前端組件化開發理念,簡單解讀一下:

  1. 頁面上的每一個 獨立的 可視/可交互區域視爲一個組件;
  2. 每一個組件對應一個工程目錄,組件所需的各類資源都在這個目錄下就近維護
  3. 因爲組件具備獨立性,所以組件與組件之間能夠 自由組合
  4. 頁面只不過是組件的容器,負責組合組件造成功能完整的界面;
  5. 當不須要某個組件,或者想要替換組件時,能夠整個目錄刪除/替換。

其中第二項描述的就近維護原則,是我以爲最具工程價值的地方,它爲前端開發提供了很好的分治策略,每一個開發者都將清楚的知道,本身所開發維護的功能 單元,其代碼必然存在於對應的組件目錄中,在那個目錄下能找到有關這個功能單元的全部內部邏輯,樣式也好,JS也好,頁面結構也好,都在那裏。

組件化開發具備較高的通用性,不管是前端渲染的單頁面應用,仍是後端模板渲染的多頁面應用,組件化開發的概念都能適用。組件HTML部分根據業務選型的不一樣,能夠是靜態的HTML文件,能夠是前端模板,也能夠是後端模板。

基於這樣的工程理念,咱們很容易將系統以獨立的組件爲單元進行分工劃分:

因爲系統功能被分治到獨立的模塊或組件中,粒度比較精細,組織形式鬆散,開發者之間不會產生開發時序的依賴,大幅提高並行的開發效率,理論上容許隨時加入新成員認領組件開發或維護工做,也更容易支持多個團隊共同維護一個大型站點的開發。

結合前面提到的模塊化開發,整個前端項目能夠劃分爲這麼幾種開發概念:

名稱 說明 舉例
JS模塊 獨立的算法和數據單元 瀏覽器環境檢測(detect),網絡請求(ajax),應用配置(config),DOM操做(dom),工具函數(utils),以及組件裏的JS單元
CSS模塊 獨立的功能性樣式單元 柵格系統(grid),字體圖標(icon-fonts),動畫樣式(animate),以及組件裏的CSS單元
UI組件 獨立的可視/可交互功能單元 頁頭(header),頁尾(footer),導航欄(nav),搜索框(search)
頁面 前端這種GUI軟件的界面狀態,是UI組件的容器 首頁(index),列表頁(list),用戶管理(user)
應用 整個項目或整個站點被稱之爲應用,由多個頁面組成  

以上5種開發概念以相對較少的規則組成了前端開發的基本工程結構,基於這些理念,我眼中的前端開發就成了這個樣子:

 

綜合上面的描述,對於通常中小規模的項目,大體能夠規劃出這樣的源碼目錄結構:

若是項目規模較大,涉及多個團隊協做,還能夠將具備相關業務功能的頁面組織在一塊兒,造成一個子系統,進一步將整個站點拆分出多個子系統來分配給不一樣團隊維護。

第二件事:「智能」靜態資源管理

上面提到的模塊化/組件化開發,僅僅描述了一種開發理念,也能夠認爲是一種開發規範,假若你承認這規範,對它的分治策略產生了共鳴,那咱們就能夠繼續聊聊它的具體實現了。

很明顯,模塊化/組件化開發以後,咱們最終要解決的,就是模塊/組件加載的技術問題。然而前端與客戶端GUI軟件有一個很大的不一樣:前端應用沒有安裝過程,其所需程序資源都部署在遠程服務器,用戶使用瀏覽器訪問不一樣的頁面來加載不一樣的資源,隨着頁面訪問的增長,漸進式的將整個程序下載到本地運行,「增量下載」是前端在工程上有別於客戶端GUI軟件的根本緣由。

上圖展現了一款界面繁多功能豐富的應用,若是採用Web實現,相信也是不小的體量,若是用戶第一次訪問頁面就強制其加載全站靜態資源再展現,相信會 有不少用戶由於失去耐心而流失。根據「增量」的原則,咱們應該精心規劃每一個頁面的資源加載策略,使得用戶不管訪問哪一個頁面都能按需加載頁面所需資源,沒訪 問過的無需加載,訪問過的能夠緩存複用,最終帶來流暢的應用體驗。

這正是Web應用「免安裝」的魅力所在。

由「增量」原則引伸出的前端優化技巧幾乎成爲了性能優化的核心,有加載相關的按需加載、延遲加載、預加載、請求合併等策略;有緩存相關的瀏覽器緩存 利用,緩存更新、緩存共享、非覆蓋式發佈等方案;還有複雜的BigRender、BigPipe、Quickling、PageCache等技術。這些優 化方案無不圍繞着如何將增量原則作到極致而展開。

因此我以爲:

相信這種貫徹不會隨着時間的推移而改變,在可預見的將來,不管在HTTP1.x仍是HTTP2.0時代,不管在ES5亦或者ES6/7時代,不管是 AMD/CommonJS/UMD亦或者ES6 module時代,不管端內技術如何變遷,咱們都有足夠充分的理由要作好前端程序資源的增量加載。

正如前面說到的,第三階段前端工程缺乏點什麼呢?我以爲是在其基礎架構中缺乏這樣一種「智能」的資源加載方案。沒有這樣的方案,很難將前端應用的規 模發展到第四階段,很難實現落地前面介紹的那種組件化開發方案,也很難讓多方合做高效率的完成一項大型應用的開發,並保證其最終運行性能良好。在第四階 段,咱們須要強大的工程化手段來管理」玩具般簡單「的前端開發。

在個人印象中,Facebook是這方面探索的偉大先驅之一,早在2010年的Velocity China大會上,來自Facebook的David Wei博士就爲業界展現了他們使人驚豔的靜態網頁資源管理和優化技術。

David Wei博士在當年的交流會上提到過一些關於Facebook的一些產品數據:

  • Facebook整站有10000+個靜態資源;
  • 每一個靜態資源都有可能被翻譯成超過100種語言版本;
  • 每種資源又會針對瀏覽器生成3種不一樣的版本;
  • 要針對不一樣帶寬的用戶作5種不一樣的打包方法;
  • 有三、4個不一樣的用戶組,用於小批次體驗新的產品功能;
  • 還要考慮不一樣的送達方法,能夠直接送達,或者經過iframe的方式提高資源並行加載的速度;
  • 靜態資源的壓縮和非壓縮狀態可切換,用於調試和定位線上問題

這是一個狀態爆炸的問題,將全部狀態乘起來,整個網站的資源組合方式會達到幾百萬種之多(去重以後統計大概有300萬種組合方式)。支撐這麼大規模前端項目運行的底層架構正是魏博士在那次演講中分享的Static Resource Management System(靜態資源管理系統),用以解決Facebook項目中有關前端工程的3D問題(Development,Deployment,Debugging)。

靜態資源管理系統 = 資源表 + 資源加載框架

資源表是一份數據文件(好比JSON),是項目中全部靜態資源(主要是JS和CSS)的構建信息記錄,經過構建工具掃描項目源碼生成,是一種k-v結構的數據,以每一個資源的id爲key,記錄了資源的類別、部署路徑、依賴關係、打包合併等內容,好比:

{
    "a.js": {
        "url": "/static/js/a.5f100fa.js",
        "dep": [ "b.js", "a.css" ]
    },
    "a.css": {
        "url": "/static/css/a.63cf374.css",
        "dep": [ "button.css" ]
    },
    "b.js": {
        "url": "/static/js/b.97193bf.js"
    },
    "button.css": {
        "url": "/static/css/button.de33108.js"
    }
}
而資源加載框架則提供一些資源引用的API,讓開發者根據id來引用資源,替代靜態的script/link標籤來收集、去重、按需加載資源。調用這些接 口時,框架經過查表來查找資源的各項信息,並遞歸查找其依賴的資源的信息,而後咱們能夠在這個過程當中實現各類性能優化算法來「智能」加載資源。
根據業務場景的不一樣,加載框架能夠在瀏覽器中用JS實現,也能夠是後端模板引擎中用服務端語言實現,甚至兩者的組合,不一而足。

這種設計很快被驗證具備足夠的靈活性,可以完美支撐不一樣團隊不一樣技術規範下的性能優化需求,前面提到的按需加載、延遲加載、預加載、請求合併、文件 指紋、CDN部署、Bigpipe、Quickling、BigRender、首屏CSS內嵌、HTTP 2.0服務端推送等等性能優化手段均可以很容易的在這種架構上實現,甚至能夠根據性能日誌自動進行優化(Facebook已實現)。

由於有了資源表,咱們能夠很方便的控制資源加載,經過各類手段在運行時計算頁面的資源使用狀況,從而得到最佳加載性能。不管是前端渲染的單頁面應用,仍是後端渲染的多頁面應用,這種方法都一樣適用。

此外,它還很巧妙的約束了構建工具的職責——只生成資源表。資源表是很是通用的數據結構,不管什麼業務場景,其業務代碼最終均可以被掃描爲相同結構 的表數據,並標記資源間的依賴關係,有了表以後咱們只需根據不一樣的業務場景定製不一樣的資源加載框架就好了,今後完全告別一個團隊維護一套工具的時代!!!

因爲先天缺陷,前端相比其餘軟件開發,在基礎架構上更加迫切的須要組件化開發和資源管理,而解決資源管理的方法其實一點也不復雜:

一個通用的資源表生成工具 + 基於表的資源加載框架

近幾年來各類你聽到過的各類資源加載優化策略大部分均可以在這樣一套基礎上實現,而這種優化對於業務來講是徹底透明的,不須要重構的性能優化——這不正是咱們一直所期盼的嗎?正如魏小亮博士所說:咱們能夠把優秀的人集中起來去優化加載。

如何選型技術、如何定製規範、如何分治系統、如何優化性能、如何加載資源,當你從切圖開始轉變爲思考這些問題的時候,我想說:

你好,工程師!

相關文章
相關標籤/搜索