前端工程——基礎(chǔ)篇

喂喂喂膘魄,那個(gè)切圖的乌逐,把頁(yè)面寫(xiě)好就發(fā)給研發(fā)工程師套模板吧。
你好创葡,切圖仔浙踢。

不知道你的團(tuán)隊(duì)如何定義前端開(kāi)發(fā),據(jù)我所知灿渴,時(shí)至今日仍然有很多團(tuán)隊(duì)會(huì)把前端開(kāi)發(fā)歸類(lèi)為產(chǎn)品或者設(shè)計(jì)崗位洛波,雖然身份之爭(zhēng)多少有些無(wú)謂,但我對(duì)這種偏見(jiàn)還是心存芥蒂逻杖,醞釀了許久,決定寫(xiě)一個(gè)系列的文章荸百,試著從工程的角度系統(tǒng)的介紹一下我對(duì)前端闻伶,尤其是Web前端的理解。

只要我們還把自己的工作看作為一項(xiàng)軟件開(kāi)發(fā)活動(dòng)够话,那么我相信讀過(guò)下面的內(nèi)容你也一定會(huì)有所共鳴蓝翰。

前端,是一種GUI軟件


現(xiàn)如今前端可謂包羅萬(wàn)象女嘲,產(chǎn)品形態(tài)五花八門(mén)畜份,涉獵極廣,什么高大上的基礎(chǔ)庫(kù)/框架欣尼,拽炫酷的宣傳頁(yè)面爆雹,還有屌炸天的小游戲……不過(guò)這些一兩個(gè)文件的小項(xiàng)目并非是前端技術(shù)的主要應(yīng)用場(chǎng)景,更具商業(yè)價(jià)值的則是復(fù)雜的Web應(yīng)用愕鼓,它們功能完善钙态,界面繁多,為用戶提供了完整的產(chǎn)品體驗(yàn)菇晃,可能是新聞聚合網(wǎng)站册倒,可能是在線購(gòu)物平臺(tái),可能是社交網(wǎng)絡(luò)磺送,可能是金融信貸應(yīng)用驻子,可能是音樂(lè)互動(dòng)社區(qū),也可能是視頻上傳與分享平臺(tái)……

從本質(zhì)上講估灿,所有Web應(yīng)用都是一種運(yùn)行在網(wǎng)頁(yè)瀏覽器中的軟件崇呵,這些軟件的圖形用戶界面(Graphical User Interface,簡(jiǎn)稱(chēng)GUI)即為前端甲捏。

如此復(fù)雜的Web應(yīng)用演熟,動(dòng)輒幾十上百人共同開(kāi)發(fā)維護(hù),其前端界面通常也頗具規(guī)模,工程量不亞于一般的傳統(tǒng)GUI軟件:

盡管Web應(yīng)用的復(fù)雜程度與日俱增芒粹,用戶對(duì)其前端界面也提出了更高的要求兄纺,但時(shí)至今日仍然沒(méi)有多少前端開(kāi)發(fā)者會(huì)從軟件工程的角度去思考前端開(kāi)發(fā),來(lái)助力團(tuán)隊(duì)的開(kāi)發(fā)效率化漆,更有甚者還對(duì)前端保留著”如玩具般簡(jiǎn)單“的刻板印象估脆,日復(fù)一日,刀耕火種座云。

歷史悠久的前端開(kāi)發(fā)疙赠,始終像是放養(yǎng)的野孩子,原始如斯朦拖,不免讓人慨嘆圃阳!

前端工程的三個(gè)階段


現(xiàn)在的前端開(kāi)發(fā)倒也并非一無(wú)所有,回顧一下曾經(jīng)經(jīng)歷過(guò)或聽(tīng)聞過(guò)的項(xiàng)目璧帝,為了提升其前端開(kāi)發(fā)效率和運(yùn)行性能捍岳,前端團(tuán)隊(duì)的工程建設(shè)大致會(huì)經(jīng)歷三個(gè)階段:

第一階段:庫(kù)/框架選型

前端工程建設(shè)的第一項(xiàng)任務(wù)就是根據(jù)項(xiàng)目特征進(jìn)行技術(shù)選型。

基本上現(xiàn)在沒(méi)有人完全從0開(kāi)始做網(wǎng)站睬隶,哪怕是政府項(xiàng)目用個(gè)jquery都很正常吧锣夹,React/Angularjs等框架橫空出世,解放了不少生產(chǎn)力苏潜,合理的技術(shù)選型可以為項(xiàng)目節(jié)省許多工程量這點(diǎn)毋庸置疑银萍。


第二階段:簡(jiǎn)單構(gòu)建優(yōu)化

選型之后基本上就可以開(kāi)始敲碼了,不過(guò)光解決開(kāi)發(fā)效率還不夠恤左,必須要兼顧運(yùn)行性能贴唇。前端工程進(jìn)行到第二階段會(huì)選型一種構(gòu)建工具,對(duì)代碼進(jìn)行壓縮飞袋,校驗(yàn)滤蝠,之后再以頁(yè)面為單位進(jìn)行簡(jiǎn)單的資源合并。
前端開(kāi)發(fā)工程化程度之低授嘀,常常出乎我的意料,我之前在百度工作時(shí)是沒(méi)有多少概念的锣险,直到離開(kāi)大公司的溫室蹄皱,去到業(yè)界與更多的團(tuán)隊(duì)交流才發(fā)現(xiàn),能做到這個(gè)階段在業(yè)界來(lái)說(shuō)已然超出平均水平芯肤,屬于“具備較高工程化程度”的團(tuán)隊(duì)了巷折,查看網(wǎng)上形形色色的網(wǎng)頁(yè)源代碼,能做到最基本的JS/CSS壓縮的Web應(yīng)用都已跨入標(biāo)準(zhǔn)互聯(lián)網(wǎng)公司行列崖咨,不難理解為什么很多前端團(tuán)隊(duì)對(duì)于前端工程構(gòu)建的認(rèn)知還僅停留在“壓縮锻拘、校驗(yàn)、合并”這種程度。


第三階段:JS/CSS模塊化開(kāi)發(fā)

分而治之是軟件工程中的重要思想署拟,是復(fù)雜系統(tǒng)開(kāi)發(fā)和維護(hù)的基石婉宰,這點(diǎn)放在前端開(kāi)發(fā)中同樣適用。在解決了基本開(kāi)發(fā)效率運(yùn)行效率問(wèn)題之后推穷,前端團(tuán)隊(duì)開(kāi)始思考維護(hù)效率心包,模塊化是目前前端最流行的分治手段。

很多人覺(jué)得模塊化開(kāi)發(fā)的工程意義是復(fù)用馒铃,我不太認(rèn)可這種看法蟹腾,在我看來(lái),模塊化開(kāi)發(fā)的最大價(jià)值應(yīng)該是分治区宇,是分治娃殖,分治!(重說(shuō)三)议谷。
不管你將來(lái)是否要復(fù)用某段代碼炉爆,你都有充分的理由將其分治為一個(gè)模塊。

JS模塊化方案很多柿隙,AMD/CommonJS/UMD/ES6 Module等叶洞,對(duì)應(yīng)的框架和工具也一大堆,說(shuō)起來(lái)很煩禀崖,大家自行百度吧衩辟;CSS模塊化開(kāi)發(fā)基本都是在less、sass波附、stylus等預(yù)處理器的import/mixin特性支持下實(shí)現(xiàn)的艺晴。

雖然這些技術(shù)由來(lái)已久,在如今這個(gè)“言必及React”的時(shí)代略顯落伍掸屡,但想想業(yè)界的絕大多數(shù)團(tuán)隊(duì)的工程化落后程度封寞,放眼望去,毫不夸張的說(shuō)仅财,能達(dá)到第三階段的前端團(tuán)隊(duì)已屬于高端行列狈究,基本具備了開(kāi)發(fā)維護(hù)一般規(guī)模Web應(yīng)用的能力。

然而盏求,做到這些就夠了么抖锥?Naive!


第四階段

前端是一種技術(shù)問(wèn)題較少碎罚、工程問(wèn)題較多的軟件開(kāi)發(fā)領(lǐng)域磅废。

當(dāng)我們要開(kāi)發(fā)一款完整的Web應(yīng)用時(shí),前端將面臨更多的工程問(wèn)題荆烈,比如:

  • 大體量:多功能拯勉、多頁(yè)面、多狀態(tài)、多系統(tǒng)宫峦;
  • 大規(guī)模:多人甚至多團(tuán)隊(duì)合作開(kāi)發(fā)岔帽;
  • 高性能:CDN部署、緩存控制斗遏、文件指紋山卦、緩存復(fù)用、請(qǐng)求合并诵次、按需加載账蓉、同步/異步加載、移動(dòng)端首屏CSS內(nèi)嵌逾一、HTTP 2.0服務(wù)端資源推送

這些無(wú)疑是一系列嚴(yán)肅的系統(tǒng)工程問(wèn)題铸本。

前面講的三個(gè)階段雖然相比曾經(jīng)“茹毛飲血”的時(shí)代進(jìn)步不少,但用于支撐第四階段的多人合作開(kāi)發(fā)以及精細(xì)的性能優(yōu)化似乎還欠缺點(diǎn)什么遵堵。

到底箱玷,缺什么呢?


沒(méi)有銀彈

讀過(guò)《人月神話》的人應(yīng)該都聽(tīng)說(shuō)過(guò)陌宿,軟件工程 沒(méi)有銀彈锡足。沒(méi)錯(cuò),前端開(kāi)發(fā)同樣沒(méi)有銀彈壳坪,可是現(xiàn)在是連?鉛彈都沒(méi)有的年月2暗谩(剛有了BB彈,摔)
前端歷來(lái)以“簡(jiǎn)單”著稱(chēng)爽蝴,在前端開(kāi)發(fā)者群體中沐批,小而美的價(jià)值觀占據(jù)著主要的話語(yǔ)權(quán),甚至成為了某種信仰蝎亚,想與其他人交流一下工程方面的心得九孩,得到的回應(yīng)往往都是兩個(gè)字:太重。

重你妹发框!你的腦容量只有4K嗎躺彬?

工程方案其實(shí)也可以小而美!只不過(guò)它的小而美不是指代碼量梅惯,而是指“規(guī)則”顾患。找到問(wèn)題的根源,用最少最簡(jiǎn)單明了的規(guī)則制定出最容易遵守最容易理解的開(kāi)發(fā)規(guī)范或工具个唧,以提升開(kāi)發(fā)效率和工程質(zhì)量,這同樣是小而美的典范设预!

2011年我有幸參與到FIS 項(xiàng)目中徙歼,與百度眾多大中型項(xiàng)目的前端研發(fā)團(tuán)隊(duì)共同合作,不斷探索實(shí)踐前端開(kāi)發(fā)的工程化解決方案,13年離開(kāi)百度去往UC魄梯,面對(duì)完全不同的產(chǎn)品形態(tài)桨螺,不同的業(yè)務(wù)場(chǎng)景,不同的適配終端酿秸,甚至不同的網(wǎng)絡(luò)環(huán)境灭翔,過(guò)往的方法論仍然能夠快速落地,為多個(gè)團(tuán)隊(duì)的不同業(yè)務(wù)場(chǎng)景量身定制出合理的前端解決方案辣苏。

這些經(jīng)歷讓我明悟了一個(gè)道理:
進(jìn)入第四階段肝箱,我們只需做好兩件事就能大幅提升前端開(kāi)發(fā)效率,并且兼顧運(yùn)行性能稀蟋,那就是——組件化開(kāi)發(fā)與資源管理煌张。

第一件事:組件化開(kāi)發(fā)
分治的確是非常重要的工程優(yōu)化手段。在我看來(lái)退客,前端作為一種GUI軟件骏融,光有JS/CSS的模塊化還不夠,對(duì)于UI組件的分治也有著同樣迫切的需求:

如上圖萌狂,這是我所信仰的前端組件化開(kāi)發(fā)理念,簡(jiǎn)單解讀一下:

  • 頁(yè)面上的每個(gè) 獨(dú)立的 可視/可交互區(qū)域視為一個(gè)組件茫藏;
  • 每個(gè)組件對(duì)應(yīng)一個(gè)工程目錄,組件所需的各種資源都在這個(gè)目錄下就近維護(hù)冤留;
  • 由于組件具有獨(dú)立性树灶,因此組件與組件之間可以 自由組合纤怒;
  • 頁(yè)面只不過(guò)是組件的容器,負(fù)責(zé)組合組件形成功能完整的界面天通;
  • 當(dāng)不需要某個(gè)組件泊窘,或者想要替換組件時(shí),可以整個(gè)目錄刪除/替換像寒。

其中第二項(xiàng)描述的就近維護(hù)原則烘豹,是我覺(jué)得最具工程價(jià)值的地方,它為前端開(kāi)發(fā)提供了很好的分治策略诺祸,每個(gè)開(kāi)發(fā)者都將清楚的知道携悯,自己所開(kāi)發(fā)維護(hù)的功能單元,其代碼必然存在于對(duì)應(yīng)的組件目錄中筷笨,在那個(gè)目錄下能找到有關(guān)這個(gè)功能單元的所有內(nèi)部邏輯憔鬼,樣式也好龟劲,JS也好,頁(yè)面結(jié)構(gòu)也好轴或,都在那里昌跌。

組件化開(kāi)發(fā)具有較高的通用性,無(wú)論是前端渲染的單頁(yè)面應(yīng)用照雁,還是后端模板渲染的多頁(yè)面應(yīng)用蚕愤,組件化開(kāi)發(fā)的概念都能適用。組件HTML部分根據(jù)業(yè)務(wù)選型的不同饺蚊,可以是靜態(tài)的HTML文件萍诱,可以是前端模板,也可以是后端模板:

不同的技術(shù)選型決定了不同的組件封裝和調(diào)用策略卸勺。

基于這樣的工程理念砂沛,我們很容易將系統(tǒng)以獨(dú)立的組件為單元進(jìn)行分工劃分:

由于系統(tǒng)功能被分治到獨(dú)立的模塊或組件中,粒度比較精細(xì)碍庵,組織形式松散静浴,開(kāi)發(fā)者之間不會(huì)產(chǎn)生開(kāi)發(fā)時(shí)序的依賴苹享,大幅提升并行的開(kāi)發(fā)效率得问,理論上允許隨時(shí)加入新成員認(rèn)領(lǐng)組件開(kāi)發(fā)或維護(hù)工作宫纬,也更容易支持多個(gè)團(tuán)隊(duì)共同維護(hù)一個(gè)大型站點(diǎn)的開(kāi)發(fā)。

結(jié)合前面提到的模塊化開(kāi)發(fā)蝌蹂,整個(gè)前端項(xiàng)目可以劃分為這么幾種開(kāi)發(fā)概念:

以上5種開(kāi)發(fā)概念以相對(duì)較少的規(guī)則組成了前端開(kāi)發(fā)的基本工程結(jié)構(gòu)孤个,基于這些理念硅急,我眼中的前端開(kāi)發(fā)就成了這個(gè)樣子:

綜合上面的描述丑罪,對(duì)于一般中小規(guī)模的項(xiàng)目吩屹,大致可以規(guī)劃出這樣的源碼目錄結(jié)構(gòu):

如果項(xiàng)目規(guī)模較大,涉及多個(gè)團(tuán)隊(duì)協(xié)作擦盾,還可以將具有相關(guān)業(yè)務(wù)功能的頁(yè)面組織在一起迹卢,形成一個(gè)子系統(tǒng)腐碱,進(jìn)一步將整個(gè)站點(diǎn)拆分出多個(gè)子系統(tǒng)來(lái)分配給不同團(tuán)隊(duì)維護(hù),針對(duì)這種情況后面我會(huì)單開(kāi)文章詳細(xì)介紹殃饿。

我有一個(gè)前端學(xué)習(xí)交流QQ群:328058344 如果你在學(xué)習(xí)前端的過(guò)程中遇到什么問(wèn)題瓷们,歡迎來(lái)我的QQ群提問(wèn)谬晕,群里每天還會(huì)更新一些學(xué)習(xí)資源攒钳。禁止閑聊文兢,非喜勿進(jìn)姆坚。

以上架構(gòu)設(shè)計(jì)歷經(jīng)許多不同公司不同業(yè)務(wù)場(chǎng)景的前端團(tuán)隊(duì)驗(yàn)證兼呵,收獲了不錯(cuò)的口碑击喂,是行之有效的前端工程分治方案懂昂。

吐槽:我本人非常反對(duì)某些前端團(tuán)隊(duì)將前端開(kāi)發(fā)劃分為“JS開(kāi)發(fā)”和“頁(yè)面重構(gòu)”兩種崗位凌彬,更傾向于組件粒度的開(kāi)發(fā)理念,對(duì)GUI軟件開(kāi)發(fā)的分工規(guī)劃應(yīng)該以功能為單位原探,而不是開(kāi)發(fā)語(yǔ)言咽弦;對(duì)開(kāi)發(fā)者的技術(shù)要求也應(yīng)該是掌握完整的端內(nèi)技術(shù)。

第二件事:“智能”靜態(tài)資源管理
上面提到的模塊化/組件化開(kāi)發(fā)闹蒜,僅僅描述了一種開(kāi)發(fā)理念,也可以認(rèn)為是一種開(kāi)發(fā)規(guī)范砌烁,倘若你認(rèn)可這規(guī)范函喉,對(duì)它的分治策略產(chǎn)生了共鳴梳毙,那我們就可以繼續(xù)聊聊它的具體實(shí)現(xiàn)了顿天。

很明顯咽白,模塊化/組件化開(kāi)發(fā)之后排抬,我們最終要解決的授段,就是模塊/組件加載的技術(shù)問(wèn)題届搁。然而前端與客戶端GUI軟件有一個(gè)很大的不同:

前端是一種遠(yuǎn)程部署,運(yùn)行時(shí)增量下載的GUI軟件

前端應(yīng)用沒(méi)有安裝過(guò)程表锻,其所需程序資源都部署在遠(yuǎn)程服務(wù)器,用戶使用瀏覽器訪問(wèn)不同的頁(yè)面來(lái)加載不同的資源确镊,隨著頁(yè)面訪問(wèn)的增加骚腥,漸進(jìn)式的將整個(gè)程序下載到本地運(yùn)行辐益,“增量下載”是前端在工程上有別于客戶端GUI軟件的根本原因钱床。

上圖展示了一款界面繁多功能豐富的應(yīng)用懈万,如果采用Web實(shí)現(xiàn)口予,相信也是不小的體量裳涛,如果用戶第一次訪問(wèn)頁(yè)面就強(qiáng)制其加載全站靜態(tài)資源再展示端三,相信會(huì)有很多用戶因?yàn)槭ツ托亩魇尴住8鶕?jù)“增量”的原則旋奢,我們應(yīng)該精心規(guī)劃每個(gè)頁(yè)面的資源加載策略,使得用戶無(wú)論訪問(wèn)哪個(gè)頁(yè)面都能按需加載頁(yè)面所需資源然痊,沒(méi)訪問(wèn)過(guò)的無(wú)需加載至朗,訪問(wèn)過(guò)的可以緩存復(fù)用,最終帶來(lái)流暢的應(yīng)用體驗(yàn)剧浸。

這正是Web應(yīng)用“免安裝”的魅力所在锹引。

由“增量”原則引申出的前端優(yōu)化技巧幾乎成為了性能優(yōu)化的核心,有加載相關(guān)的按需加載唆香、延遲加載嫌变、預(yù)加載、請(qǐng)求合并等策略凸舵;有緩存相關(guān)的瀏覽器緩存利用琼富,緩存更新人断、緩存共享步做、非覆蓋式發(fā)布等方案;還有復(fù)雜的BigRender、BigPipe簿透、Quickling蚂维、PageCache等技術(shù)苹祟。這些優(yōu)化方案無(wú)不圍繞著如何將增量原則做到極致而展開(kāi)。
所以我覺(jué)得:

第四階段前端開(kāi)發(fā)最迫切需要做好的就是在基礎(chǔ)架構(gòu)中貫徹增量原則庄呈。

相信這種貫徹不會(huì)隨著時(shí)間的推移而改變颁独,在可預(yù)見(jiàn)的未來(lái)吓懈,無(wú)論在HTTP1.x還是HTTP2.0時(shí)代温兼,無(wú)論在ES5亦或者ES6/7時(shí)代装处,無(wú)論是AMD/CommonJS/UMD亦或者ES6 module時(shí)代,無(wú)論端內(nèi)技術(shù)如何變遷仿耽,我們都有足夠充分的理由要做好前端程序資源的增量加載俺泣。

正如前面說(shuō)到的,第三階段前端工程缺少點(diǎn)什么呢打掘?我覺(jué)得是在其基礎(chǔ)架構(gòu)中缺少這樣一種“智能”的資源加載方案琴锭。沒(méi)有這樣的方案蓖捶,很難將前端應(yīng)用的規(guī)模發(fā)展到第四階段洒宝,很難實(shí)現(xiàn)落地前面介紹的那種組件化開(kāi)發(fā)方案父能,也很難讓多方合作高效率的完成一項(xiàng)大型應(yīng)用的開(kāi)發(fā)坡慌,并保證其最終運(yùn)行性能良好黔酥。在第四階段,我們需要強(qiáng)大的工程化手段來(lái)管理”玩具般簡(jiǎn)單“的前端開(kāi)發(fā)洪橘。

在我的印象中跪者,F(xiàn)acebook是這方面探索的偉大先驅(qū)之一,早在2010年的Velocity China大會(huì)上熄求,來(lái)自Facebook的David Wei博士就為業(yè)界展示了他們令人驚艷的靜態(tài)網(wǎng)頁(yè)資源管理和優(yōu)化技術(shù)渣玲。

David Wei博士在當(dāng)年的交流會(huì)上提到過(guò)一些關(guān)于Facebook的一些產(chǎn)品數(shù)據(jù):

  • Facebook整站有10000+個(gè)靜態(tài)資源;
  • 每個(gè)靜態(tài)資源都有可能被翻譯成超過(guò)100種語(yǔ)言版本抡四;
  • 每種資源又會(huì)針對(duì)瀏覽器生成3種不同的版本柜蜈;
  • 要針對(duì)不同帶寬的用戶做5種不同的打包方法仗谆;
  • 有3指巡、4個(gè)不同的用戶組,用于小批次體驗(yàn)新的產(chǎn)品功能隶垮;
  • 還要考慮不同的送達(dá)方法藻雪,可以直接送達(dá),或者通過(guò)iframe的方式提升資源并行加載的速度狸吞;
  • 靜態(tài)資源的壓縮和非壓縮狀態(tài)可切換勉耀,用于調(diào)試和定位線上問(wèn)題

這是一個(gè)狀態(tài)爆炸的問(wèn)題指煎,將所有狀態(tài)乘起來(lái),整個(gè)網(wǎng)站的資源組合方式會(huì)達(dá)到幾百萬(wàn)種之多(去重之后統(tǒng)計(jì)大概有300萬(wàn)種組合方式)便斥。支撐這么大規(guī)模前端項(xiàng)目運(yùn)行的底層架構(gòu)正是魏博士在那次演講中分享的Static Resource Management System(靜態(tài)資源管理系統(tǒng))至壤,用以解決Facebook項(xiàng)目中有關(guān)前端工程的3D問(wèn)題(Development,Deployment枢纠,Debugging)像街。

那段時(shí)間FIS項(xiàng)目正好遇到瓶頸,當(dāng)時(shí)的FIS還是一個(gè)用php寫(xiě)的task-based構(gòu)建工具晋渺,那時(shí)候?qū)τ谇岸斯こ痰恼J(rèn)知度很低镰绎,覺(jué)得前端構(gòu)建不就是幾個(gè)壓縮優(yōu)化校驗(yàn)打包任務(wù)的組合嗎,寫(xiě)好流程調(diào)度木西,就針對(duì)不同需求寫(xiě)插件唄畴栖,看似非常簡(jiǎn)單。但當(dāng)我們支撐越來(lái)越多的業(yè)務(wù)團(tuán)隊(duì)八千,接觸到各種不同的業(yè)務(wù)場(chǎng)景時(shí)吗讶,我們深刻的感受到task-based工具的粗糙,團(tuán)隊(duì)每天疲于根據(jù)各種業(yè)務(wù)場(chǎng)景編寫(xiě)各種打包插件叼丑,構(gòu)建邏輯異常復(fù)雜关翎,隱隱看到不可控的跡象。

我們很快意識(shí)到把基礎(chǔ)架構(gòu)放到構(gòu)建工具中實(shí)現(xiàn)是一件很愚蠢的事鸠信,試圖依靠構(gòu)建工具實(shí)現(xiàn)各種優(yōu)化策略使得構(gòu)建變成了一個(gè)巨大的黑盒纵寝,一旦發(fā)生問(wèn)題,定位起來(lái)非常困難星立,而且每種業(yè)務(wù)場(chǎng)景都有不同的優(yōu)化需求爽茴,構(gòu)建工具只能通過(guò)靜態(tài)分析來(lái)優(yōu)化加載,具有很大的局限性绰垂,單頁(yè)面/多頁(yè)面/PC端/移動(dòng)端/前端渲染/后端渲染/多語(yǔ)言/多皮膚/高級(jí)優(yōu)化等等資源加載問(wèn)題室奏,總不能給每個(gè)都寫(xiě)一套工具吧,更何況這些問(wèn)題彼此之間還可以有多種組合應(yīng)用劲装,工具根本寫(xiě)不過(guò)來(lái)胧沫。

Facebook的做法無(wú)疑為我們亮起了一盞明燈,不過(guò)可惜它并不開(kāi)源(不是技術(shù)封鎖占业,而是這個(gè)系統(tǒng)依賴FB體系中的其他方面绒怨,通用性不強(qiáng),開(kāi)源意義不大)谦疾,我們只能?chē)L試挖掘相關(guān)信息南蹂,網(wǎng)上對(duì)它的完整介紹還是非常非常少,分析facebook的前端代碼也沒(méi)有太多收獲念恍,后來(lái)無(wú)意中發(fā)現(xiàn)了facebook使用的項(xiàng)目管理工具phabricator中的一個(gè)靜態(tài)管理方案Celerit六剥,以及相關(guān)的說(shuō)明]晚顷,看它的描述很像是Facebook靜態(tài)資源管理系統(tǒng)的一個(gè)mini版!

簡(jiǎn)單看過(guò)整個(gè)系統(tǒng)之后發(fā)現(xiàn)原理并不復(fù)雜(小而美的典范)疗疟,它是通過(guò)一個(gè)小工具掃描所有靜態(tài)資源该默,生成一張資源表,然后有一個(gè)PHP實(shí)現(xiàn)的資源管理框架(Celerity)提供了資源加載接口策彤,替代了傳統(tǒng)的script/link等靜態(tài)的資源加載標(biāo)簽权均,最終通過(guò)查表來(lái)加載資源。

雖然沒(méi)有真正看過(guò)FB的那套系統(tǒng)锅锨,但眼前的這個(gè)小小的框架給了當(dāng)時(shí)的我們足夠多的啟示:

靜態(tài)資源管理系統(tǒng) = 資源表 + 資源加載框架

多么優(yōu)雅的實(shí)現(xiàn)斑瓷蕖!

資源表是一份數(shù)據(jù)文件(比如JSON)必搞,是項(xiàng)目中所有靜態(tài)資源(主要是JS和CSS)的構(gòu)建信息記錄必指,通過(guò)構(gòu)建工具掃描項(xiàng)目源碼生成,是一種k-v結(jié)構(gòu)的數(shù)據(jù)恕洲,以每個(gè)資源的id為key塔橡,記錄了資源的類(lèi)別、部署路徑霜第、依賴關(guān)系葛家、打包合并等內(nèi)容,比如:

{
    "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.css"
    }
}

而資源加載框架則提供一些資源引用的API泌类,讓開(kāi)發(fā)者根據(jù)id來(lái)引用資源癞谒,替代靜態(tài)的script/link標(biāo)簽來(lái)收集、去重刃榨、按需加載資源弹砚。調(diào)用這些接口時(shí),框架通過(guò)查表來(lái)查找資源的各項(xiàng)信息枢希,并遞歸查找其依賴的資源的信息桌吃,然后我們可以在這個(gè)過(guò)程中實(shí)現(xiàn)各種性能優(yōu)化算法來(lái)“智能”加載資源。

根據(jù)業(yè)務(wù)場(chǎng)景的不同苞轿,加載框架可以在瀏覽器中用JS實(shí)現(xiàn)茅诱,也可以是后端模板引擎中用服務(wù)端語(yǔ)言實(shí)現(xiàn),甚至二者的組合搬卒,不一而足瑟俭。

這種設(shè)計(jì)很快被驗(yàn)證具有足夠的靈活性,能夠完美支撐不同團(tuán)隊(duì)不同技術(shù)規(guī)范下的性能優(yōu)化需求秀睛,前面提到的按需加載尔当、延遲加載莲祸、預(yù)加載蹂安、請(qǐng)求合并椭迎、文件指紋、CDN部署田盈、Bigpipe畜号、Quickling、BigRender允瞧、首屏CSS內(nèi)嵌简软、HTTP 2.0服務(wù)端推送等等性能優(yōu)化手段都可以很容易的在這種架構(gòu)上實(shí)現(xiàn),甚至可以根據(jù)性能日志自動(dòng)進(jìn)行優(yōu)化(Facebook已實(shí)現(xiàn))述暂。

因?yàn)橛辛速Y源表痹升,我們可以很方便的控制資源加載,通過(guò)各種手段在運(yùn)行時(shí)計(jì)算頁(yè)面的資源使用情況畦韭,從而獲得最佳加載性能疼蛾。無(wú)論是前端渲染的單頁(yè)面應(yīng)用,還是后端渲染的多頁(yè)面應(yīng)用艺配,這種方法都同樣適用察郁。

此外,它還很巧妙的約束了構(gòu)建工具的職責(zé)——只生成資源表转唉。資源表是非常通用的數(shù)據(jù)結(jié)構(gòu)皮钠,無(wú)論什么業(yè)務(wù)場(chǎng)景,其業(yè)務(wù)代碼最終都可以被掃描為相同結(jié)構(gòu)的表數(shù)據(jù)赠法,并標(biāo)記資源間的依賴關(guān)系麦轰,有了表之后我們只需根據(jù)不同的業(yè)務(wù)場(chǎng)景定制不同的資源加載框架就行了,從此徹底告別一個(gè)團(tuán)隊(duì)維護(hù)一套工具的時(shí)代砖织!

恩原朝,如你所見(jiàn),雖然徹底告別了一個(gè)團(tuán)隊(duì)一套工具的時(shí)代镶苞,但似乎又進(jìn)入了一個(gè)團(tuán)隊(duì)一套框架的時(shí)代喳坠。其實(shí)還是有差別的,因?yàn)榭蚣芫哂泻艽蟮撵`活性茂蚓,而且不那么黑盒壕鹉,采用框架實(shí)現(xiàn)資源管理相比構(gòu)建更容易調(diào)試、定位和升級(jí)變更聋涨。

深耕靜態(tài)資源加載框架可以帶來(lái)許多收益晾浴,而且有足夠的靈活性和健壯性面向未來(lái)的技術(shù)變革,這個(gè)我們留作后話牍白。

總結(jié)

回顧一下前面提到過(guò)的前端工程三個(gè)階段:

  • 第一階段:庫(kù)/框架選型
  • 第二階段:簡(jiǎn)單構(gòu)建優(yōu)化
  • 第三階段:JS/CSS模塊化開(kāi)發(fā)

現(xiàn)在補(bǔ)充上第四階段:

  • 第四階段:組件化開(kāi)發(fā)與資源管理

由于先天缺陷脊凰,前端相比其他軟件開(kāi)發(fā),在基礎(chǔ)架構(gòu)上更加迫切的需要組件化開(kāi)發(fā)和資源管理,而解決資源管理的方法其實(shí)一點(diǎn)也不復(fù)雜:

一個(gè)通用的資源表生成工具 + 基于表的資源加載框架

近幾年來(lái)各種你聽(tīng)到過(guò)的各種資源加載優(yōu)化策略大部分都可以在這樣一套基礎(chǔ)上實(shí)現(xiàn)狸涌,而這種優(yōu)化對(duì)于業(yè)務(wù)來(lái)說(shuō)是完全透明的切省,不需要重構(gòu)的性能優(yōu)化——這不正是我們一直所期盼的嗎?正如魏小亮博士所說(shuō):我們可以把優(yōu)秀的人集中起來(lái)去優(yōu)化加載帕胆。

如何選型技術(shù)朝捆、如何定制規(guī)范、如何分治系統(tǒng)懒豹、如何優(yōu)化性能芙盘、如何加載資源,當(dāng)你從切圖開(kāi)始轉(zhuǎn)變?yōu)樗伎歼@些問(wèn)題的時(shí)候脸秽,我想說(shuō):

你好儒老,工程師!

我有一個(gè)前端學(xué)習(xí)交流QQ群:328058344 如果你在學(xué)習(xí)前端的過(guò)程中遇到什么問(wèn)題记餐,歡迎來(lái)我的QQ群提問(wèn)贷盲,群里每天還會(huì)更新一些學(xué)習(xí)資源。禁止閑聊剥扣,非喜勿進(jìn)巩剖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市钠怯,隨后出現(xiàn)的幾起案子佳魔,更是在濱河造成了極大的恐慌,老刑警劉巖晦炊,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鞠鲜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡断国,警方通過(guò)查閱死者的電腦和手機(jī)贤姆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)稳衬,“玉大人霞捡,你說(shuō)我怎么就攤上這事”【危” “怎么了碧信?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)街夭。 經(jīng)常有香客問(wèn)我砰碴,道長(zhǎng),這世上最難降的妖魔是什么板丽? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任呈枉,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猖辫。我一直安慰自己酥泞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布住册。 她就那樣靜靜地躺著,像睡著了一般瓮具。 火紅的嫁衣襯著肌膚如雪荧飞。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天名党,我揣著相機(jī)與錄音叹阔,去河邊找鬼。 笑死传睹,一個(gè)胖子當(dāng)著我的面吹牛耳幢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播欧啤,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼睛藻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了邢隧?” 一聲冷哼從身側(cè)響起店印,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎倒慧,沒(méi)想到半個(gè)月后按摘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纫谅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年炫贤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片付秕。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡兰珍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出询吴,到底是詐尸還是另有隱情俩垃,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布汰寓,位于F島的核電站口柳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏有滑。R本人自食惡果不足惜跃闹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧望艺,春花似錦苛秕、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至惩激,卻和暖如春店煞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背风钻。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工顷蟀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留骡技,地道東北人鸣个。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像布朦,于是被迫代替她去往敵國(guó)和親囤萤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,735評(píng)論 25 707
  • [原文](https://github.com/fouber/blog)前端工程前端是趴,是一種GUI軟件阁将,所有Web...
    Www劉閱讀 362評(píng)論 0 4
  • 性能優(yōu)化方向分類(lèi) 請(qǐng)求數(shù)量: 合并腳本和樣式表, CSS Sprites右遭, 拆分初始化負(fù)載做盅, 劃分主域(使用“查找...
    Www劉閱讀 1,761評(píng)論 3 8
  • 看了以后很震撼,不愧是高評(píng)分的作品窘哈,在這2017年的角度來(lái)看吹榴,依舊是無(wú)法被超越的經(jīng)典!滚婉!所謂經(jīng)典图筹,一是無(wú)法超越,再...
    舊年憶浮華閱讀 569評(píng)論 0 0
  • 1.文章標(biāo)題让腹,設(shè)置了懸念远剩。勾起了人們的好奇心,讓人有往下閱讀的欲望骇窍。 2.文章采用了1 2 3 4+結(jié)論的框架來(lái)證...
    楊一韻閱讀 175評(píng)論 0 6