提升開發(fā)體驗(yàn)我們主要從以下三個(gè)方面來(lái)提升我們的開發(fā)體驗(yàn)。 規(guī)范化當(dāng)團(tuán)隊(duì)人員不斷擴(kuò)充時(shí),我們需要制定統(tǒng)一的規(guī)范來(lái)對(duì)平時(shí)的開發(fā)工作做出一定約束和指導(dǎo)。統(tǒng)一的規(guī)范包括前端的代碼規(guī)范,根據(jù)規(guī)范定義好一套代碼檢查的規(guī)則,在代碼提交的時(shí)候進(jìn)行檢查,讓開發(fā)人員知道自己的代碼情況。 同時(shí),根據(jù)以往的開發(fā)經(jīng)驗(yàn),我們制定了統(tǒng)一的項(xiàng)目框架,根據(jù)業(yè)務(wù)功能不同,將一個(gè)項(xiàng)目(app)拆分成不同的業(yè)務(wù)模塊(module),而每一個(gè)模塊都包含自身的頁(yè)面(page)以及構(gòu)成頁(yè)面所需要的組件(widget),每一個(gè)項(xiàng)目涉及到app、module、page、widget這些已經(jīng)約定好的概念,這樣讓項(xiàng)目結(jié)構(gòu)更加清晰,而且讓團(tuán)隊(duì)內(nèi)不同業(yè)務(wù)的人員之間切換無(wú)障礙。 組件化在項(xiàng)目中引入組件化的概念,這里的組件對(duì)應(yīng)上文講到的widget,每一個(gè)組件都會(huì)包含組件自身的模板、css、js、圖片以及說明文件,我們使用組件來(lái)拼裝頁(yè)面,像搭積木一樣來(lái)拼裝我們的頁(yè)面,同時(shí)一個(gè)組件內(nèi)可以調(diào)用另一個(gè)組件。 在拿到設(shè)計(jì)稿后,我們首先需要確定哪些需要做成公共組件,那些是要做成獨(dú)立組件,以及組件間如何進(jìn)行通信。在頁(yè)面中調(diào)用這些組件后,會(huì)自動(dòng)加載組件的模板以及組件的靜態(tài)資源,而當(dāng)組件不再需要時(shí),只要移除掉組件引用,那么相應(yīng)的模板和靜態(tài)資源也會(huì)不再加載。 組件化的好處主要有這么幾點(diǎn)
自動(dòng)化編譯在前端開發(fā)中,我們總是會(huì)去使用很多工具、手段來(lái)優(yōu)化代碼、提升開發(fā)效率,例如,我們會(huì)使用sass、less等CSS預(yù)處理工具來(lái)編寫更好維護(hù)的樣式代碼,我們也會(huì)使用CSSLint、eslint等代碼檢查工具來(lái)檢查代碼的語(yǔ)法錯(cuò)誤,使用文件合并壓縮等手段來(lái)減少資源大小,除此之外我們還會(huì)去做雪碧圖合并、多倍圖處理、字體壓縮處理、代碼發(fā)布等等。 曾經(jīng)有大神說過,超過90s的工作都應(yīng)該自動(dòng)化掉。而以上所有的這些工作,貫穿我們整個(gè)開發(fā)流程,但是不同工具的切換不但顯得凌亂,而且影響開發(fā)效率。在自動(dòng)化、工程編譯的思想早已深入人心的當(dāng)下,我們當(dāng)然也要緊跟潮流,所以我們考慮通過自動(dòng)化手段來(lái)提升我們的效率,讓所有操作可以一鍵式開速執(zhí)行完。 我們將通過定義好一系列的編譯任務(wù),按照一定順序依次對(duì)我們的項(xiàng)目自動(dòng)進(jìn)行編譯操作,最后產(chǎn)生出可上線的代碼。 提升性能我們主要從以下四個(gè)方面來(lái)做好性能優(yōu)化。 首屏優(yōu)化頁(yè)面的打開速度一直是大家非常關(guān)心的一個(gè)指標(biāo),一個(gè)頁(yè)面打開太慢會(huì)讓讓用戶失去等待的耐心,為了讓用戶更快地看到頁(yè)面,我們考慮將頁(yè)面中部分靜態(tài)資源代碼直接嵌入頁(yè)面中,我們通過工具處理,在工程編譯階段,將指定的靜態(tài)資源代碼內(nèi)嵌入頁(yè)面中,這樣可以減少HTTP請(qǐng)求,提升首屏加載速度,同時(shí)降低頁(yè)面裸奔風(fēng)險(xiǎn)。 按需加載同時(shí),我們考慮通過盡量減小頁(yè)面體積來(lái)提升頁(yè)面打開速度,在業(yè)務(wù)上我們將頁(yè)面劃分為一個(gè)個(gè)樓層組件,以京東美妝館為例,頁(yè)面中從上而下分為首焦、至IN尖貨、今日特惠、潮流前沿、口碑榜單這么幾個(gè)樓層組件,其實(shí)這個(gè)頁(yè)面還有很長(zhǎng),內(nèi)容非常多且復(fù)雜。 之前我們的做法是整個(gè)頁(yè)面直出,這樣一次性加載的內(nèi)容會(huì)非常多,為了提升打開速度,我們考慮通過按需加載的方式來(lái)優(yōu)化頁(yè)面的加載。我們?cè)陧?yè)面中只放每一個(gè)樓層的框架性代碼,樓層的模板和數(shù)據(jù)都通過異步的方式去拉取,來(lái)實(shí)現(xiàn)樓層組件的按需加載,同時(shí)我們可以對(duì)模板以及數(shù)據(jù)進(jìn)行緩存,以此來(lái)減少請(qǐng)求,做更極致的優(yōu)化。在開發(fā)中我們以正常組件的方式去開發(fā)整個(gè)頁(yè)面,隨后通過編譯工具,在代碼編譯階段自動(dòng)將樓層的模板抽離成一個(gè)獨(dú)立的JS文件,并給樓層容器打上標(biāo)記位,通過頁(yè)面加載邏輯去按需拉取模板,再進(jìn)行渲染。
通過上述步驟,實(shí)現(xiàn)按需加載的自動(dòng)化生成,在提升性能的同時(shí),很好地解放我們生產(chǎn)力。 基于資源表加載根據(jù)頁(yè)面組件化,通過工具分析,我們將獲得頁(yè)面與組件的依賴關(guān)系表,同時(shí)也能確認(rèn)頁(yè)面所引用資源的依賴關(guān)系,例如,我們?cè)陧?yè)面hello中同步引用組件topbar,那么依賴關(guān)系表中將會(huì)記錄同步引用關(guān)系hello引用topbar.tpl、topbar.css、topbar.js,那么頁(yè)面hello將會(huì)自動(dòng)加載組件topbar的CSS與JS,同時(shí)依賴表會(huì)記錄異步引用的關(guān)系,假如我們?cè)诮M件C中通過API異步引用了組件D的js,那么會(huì)在依賴表中記錄C異步引用D.js這一個(gè)依賴關(guān)系,這樣D.js這個(gè)資源將會(huì)在用到的時(shí)候被異步調(diào)用。 同步引用的資源通過生成combo形式鏈接,在服務(wù)端進(jìn)行文件合并,這樣在頁(yè)面加載的時(shí)候,頁(yè)面只會(huì)加載自己需要的同步資源,異步的資源將會(huì)在用到的時(shí)候再加載,有效避免資源冗余。同時(shí)刪除、增加組件也非常方便,只需改動(dòng)模板中對(duì)組件調(diào)用,通過編譯工具會(huì)自動(dòng)重新生成模板以及combo鏈接。 我們可以將資源加載的操作抽離出來(lái),形成一套統(tǒng)一的資源加載框架設(shè)計(jì),這樣我們使用的模板可以變得更加靈活,無(wú)論是純html模板,還是PHP或Java之類的后端模板都能有效支持。編譯工具掃描代碼后只生成資源依賴表,我們通過實(shí)現(xiàn)各語(yǔ)言平臺(tái)的資源加載框架,讓不同語(yǔ)言的模板都能基于同一個(gè)資源依賴表進(jìn)行資源加載。 同時(shí),對(duì)資源進(jìn)行MD5重命名處理,文件md5重命名也是一種提升性能的有效手段,使用文件md5后開啟服務(wù)器強(qiáng)緩存,可以提升緩存的利用率并避免不必要的緩存判斷處理。但文件md5重命名后會(huì)出現(xiàn)開發(fā)時(shí)引用的文件名對(duì)不上的問題,這就需要在資源表中記錄原文件名與md5重命名后之間的對(duì)應(yīng)關(guān)系,當(dāng)我們引用一個(gè)資源時(shí),就會(huì)通過查表獲取重命名后的資源名,然后利用代碼中引用資源定位的能力來(lái)進(jìn)行資源名自動(dòng)替換。 靜態(tài)資源預(yù)加載所謂靜態(tài)資源預(yù)加載,就是當(dāng)用戶在進(jìn)行瀏覽頁(yè)面的時(shí)候,我們可以在當(dāng)前頁(yè)面靜默加載下一個(gè)頁(yè)面的靜態(tài)資源,這樣當(dāng)用戶進(jìn)入到下一個(gè)頁(yè)面時(shí)就能快速打開頁(yè)面,從而在不知不覺中提升頁(yè)面的打開速度。 我們會(huì)在靜態(tài)資源預(yù)加載平臺(tái)上配置每一個(gè)頁(yè)面id對(duì)應(yīng)需要預(yù)加載頁(yè)面資源的id,然后系統(tǒng)通過讀取資源依賴表獲取到所需要預(yù)加載的靜態(tài)資源,生成預(yù)加載資源列表文件,再將文件推送到線上服務(wù)器,通過頁(yè)面掛載js請(qǐng)求獲取預(yù)加載資源列表,隨后靜默加載資源。在有了資源依賴表后,我們可以準(zhǔn)確地分析到每一個(gè)頁(yè)面引用資源的請(qǐng)求,就可以很好地實(shí)現(xiàn)靜態(tài)資源預(yù)加載的功能。 Athena工欲善其事,必現(xiàn)利其器。為了實(shí)現(xiàn)我們對(duì)提升開發(fā)效率和產(chǎn)品性能的訴求,我們提出了比較完整的工程化解決方案以及對(duì)應(yīng)的工具Athena。 Athena是由京東【凹凸實(shí)驗(yàn)室】() 推出的一套項(xiàng)目流程工具,通過Athena,我們可以很流程地跑完整個(gè)開發(fā)流程。Athena分為兩部分,一是本地自動(dòng)化編譯工具,二是資源管理平臺(tái),其架構(gòu)如下 本地自動(dòng)化工具Athena本地編譯工具是一個(gè)基于NodeJs的命令行工具,通過執(zhí)行命令的方式來(lái)優(yōu)化我們的開發(fā)流程,目前Athena的主要功能有
創(chuàng)建項(xiàng)目結(jié)構(gòu)在執(zhí)行創(chuàng)建命令時(shí),Athena會(huì)從管理平臺(tái)下載自定義好的項(xiàng)目模板,可以根據(jù)模板創(chuàng)建項(xiàng)目、模塊、頁(yè)面、和組件。Athena有四個(gè)創(chuàng)建命令: 通過執(zhí)行 隨后可以通過 通過 通過 開發(fā)使用組件化Athena中實(shí)現(xiàn)組件化主要是分為兩種,一是針對(duì)純HTML模板,通過擴(kuò)展模板引擎方法實(shí)現(xiàn),提供了組件化API
通過模板引擎編譯,執(zhí)行widget.load方法,可以實(shí)現(xiàn)加載模板,記錄依賴關(guān)系的目的。 二是針對(duì)不同語(yǔ)言的后端模板,通過實(shí)現(xiàn)各自的組件化框架來(lái)進(jìn)行組件的加載,例如 Athena中的APIAthena針對(duì)模板提供了一系列的API來(lái)擴(kuò)展豐富的功能,例如前面提到的 同時(shí)Athena中還提供了其他API:
雪碧圖標(biāo)識(shí) 編譯預(yù)覽編譯任務(wù)在編寫完項(xiàng)目,就可以通過命令來(lái)對(duì)項(xiàng)目進(jìn)行編譯了,執(zhí)行編譯命令 本地預(yù)覽執(zhí)行預(yù)覽命令
Mock server在進(jìn)行項(xiàng)目預(yù)覽的同時(shí),Athena同時(shí)提供了mock data的服務(wù),我們可以配置相應(yīng)的路由,以及路由接口對(duì)應(yīng)的假數(shù)據(jù),所有的接口請(qǐng)求會(huì)發(fā)送到mock server上,在mock server中可以選擇將請(qǐng)求代理到假數(shù)據(jù)平臺(tái)還是代理到線上接口,這樣就可以脫離后端進(jìn)行開發(fā)聯(lián)調(diào)了,以此實(shí)現(xiàn)數(shù)據(jù)的前后端分離。 項(xiàng)目部署在開發(fā)預(yù)覽完后,通過命令 組件維護(hù)我們通過組件化的手段已經(jīng)將我們的項(xiàng)目進(jìn)行組件化了,這樣我們經(jīng)過業(yè)務(wù)迭代積累,產(chǎn)出很多業(yè)務(wù)公共組件,但在以往的項(xiàng)目開發(fā)中,公共組件的更新與維護(hù)一直很受限制,而且有哪些公共組件、公共組件長(zhǎng)什么樣子,只能依靠口口相傳或者手工維護(hù)的文檔。所以在Athena中我們加入了組件平臺(tái),在組件平臺(tái)上統(tǒng)一展示各個(gè)業(yè)務(wù)的公共組件,而得益于本地工具,組件平臺(tái)不需要人工干預(yù)維護(hù),我們可以在本地通過命令 這樣組件的維護(hù)更加自動(dòng)化,公共組件的使用也更加方便了。
自身優(yōu)化為了提升開發(fā)效率,Athena做了一些優(yōu)化操作 精簡(jiǎn)項(xiàng)目預(yù)覽時(shí)的任務(wù)在開發(fā)時(shí)進(jìn)行項(xiàng)目預(yù)覽時(shí),會(huì)執(zhí)行精簡(jiǎn)版的編譯任務(wù),剔除了類似文件壓縮、雪碧圖生成、模板抽離處理等耗時(shí)的操作,只保留核心、必須的編譯任務(wù),這樣可以極大地減少編譯時(shí)間,提升開發(fā)的效率。 預(yù)覽時(shí)監(jiān)聽細(xì)化在開發(fā)進(jìn)行預(yù)覽時(shí),會(huì)對(duì)所有文件的改動(dòng)進(jìn)行監(jiān)聽,而針對(duì)每一類文件都有非常細(xì)化的操作,當(dāng)文件改動(dòng)時(shí)只會(huì)執(zhí)行改文件所需要的編譯任務(wù),而不會(huì)進(jìn)行整體編譯,這樣可以很好地提升開發(fā)效率。例如改動(dòng)某一組件的CSS文件,則只會(huì)針對(duì)該文件執(zhí)行一些相關(guān)的CSS操作。 同時(shí)得益于所有文件依賴關(guān)系的記錄,在監(jiān)聽時(shí)會(huì)根據(jù)依賴關(guān)系進(jìn)行文件編譯,例如某sass文件中引入了另一個(gè)sass庫(kù)文件,修改這個(gè)sass庫(kù)文件的時(shí)候,會(huì)根據(jù)引用關(guān)系表同時(shí)更新到所有引用到這個(gè)sass文件的文件,這樣項(xiàng)目文件更新及時(shí),讓開發(fā)流程更加流暢。 編譯緩存在圖片壓縮和sass編譯時(shí),開啟文件緩存,將已經(jīng)編譯過且沒有改動(dòng)的文件過濾掉,不再編譯,大幅提升編譯速度。 發(fā)布緩存設(shè)置發(fā)布過濾,根據(jù)文件md5過濾掉已經(jīng)發(fā)布過的文件,提升發(fā)布速度。 技術(shù)選型Athena本地工具早期技術(shù)選型是 管理平臺(tái)性能優(yōu)化一直是前端工程師探索的課題,很多時(shí)候就是資源的分配問題,也就是資源管理。為了更好地配合本地構(gòu)建工具來(lái)管理資源,我們搭建了管理平臺(tái)。我們來(lái)看下,結(jié)合本地構(gòu)建工具和管理平臺(tái),工作流程變成了怎樣? 工作流程
在上面的publish指令中,工具會(huì)掃描所有文件,執(zhí)行代碼檢查,掃描頁(yè)面文件,獲取組件依賴關(guān)系,根據(jù)組件依賴關(guān)系進(jìn)行文件合并,然后會(huì)進(jìn)行樣式處理、js處理以及圖片的處理,根據(jù)配置是否進(jìn)行md5重命名文件,組裝html,插入樣式、js和圖片,最后將編譯好的文件發(fā)布到相應(yīng)的機(jī)器。在整個(gè)過程里面,會(huì)生成資源關(guān)系依賴表,最終會(huì)將資源關(guān)系表及編譯后的文件上傳至管理平臺(tái)。 除此之外,每個(gè)指令的操作都會(huì)上報(bào)給管理平臺(tái)。管理平臺(tái)收到數(shù)據(jù)后,會(huì)對(duì)數(shù)據(jù)進(jìn)行處理,最終可以在平臺(tái)上看到項(xiàng)目相關(guān)的信息。 整體工作流程圖如下: 從上面的工作流程中,我們可以看到,管理平臺(tái)需要有數(shù)據(jù)統(tǒng)計(jì)、資源管理以及項(xiàng)目管理的功能。整體架構(gòu)圖如下: 數(shù)據(jù)統(tǒng)計(jì)數(shù)據(jù)統(tǒng)計(jì)包含項(xiàng)目操作日志,主要是用于統(tǒng)計(jì)團(tuán)隊(duì)每個(gè)成員具體的操作,方便項(xiàng)目成員查看項(xiàng)目代碼變更;另一部份是統(tǒng)計(jì)樣式表、腳本以及圖片的壓縮數(shù)據(jù),用于顯示工具給我們項(xiàng)目帶來(lái)的提升。 以下是操作日志統(tǒng)計(jì): 資源管理資源管理是管理平臺(tái)的核心,主要分為4個(gè)部分:模塊展示、依賴關(guān)系、組件預(yù)覽和權(quán)限控制。這部分功能主要通過本地構(gòu)建工具提供的資源關(guān)系表來(lái)完成。 模塊展示模塊展示,用于記錄項(xiàng)目具體包含哪些模塊以及模塊具體的信息。在平常開發(fā)中,我們的項(xiàng)目會(huì)分為許多模塊,不同的模塊有不同的人來(lái)開發(fā)和維護(hù)。當(dāng)項(xiàng)目越大的時(shí)候,可以通過管理平臺(tái)清晰地看到模塊具體的信息。 依賴關(guān)系依賴關(guān)系,主要是html、css、js和圖片相互之間的關(guān)系。通過分析資源關(guān)系依賴表,可以獲取到各個(gè)資源被引用的情況以及線上版本的情況。當(dāng)線上環(huán)境采用md5來(lái)做資源管理時(shí),我們不是很清晰地知道靜態(tài)資源對(duì)應(yīng)線上哪個(gè)版本的資源,而有了這個(gè)依賴關(guān)系表,當(dāng)出現(xiàn)問題時(shí),我們可以更快地定位到具體的資源。 組件管理我們采用組件來(lái)拼湊頁(yè)面,當(dāng)項(xiàng)目越大時(shí),組件越多,那么如何管理組件成為了一個(gè)棘手的問題。比如說,有一些比較老的冗余組件,我們不確定是否為其他頁(yè)面所引用,那么就不能愉快地刪除它。有了組件管理,可以清晰地知道組件的被調(diào)用情況,就可以對(duì)組件做相應(yīng)的操作。 組件管理,結(jié)合組件平臺(tái)來(lái)使用,在管理平臺(tái)上引用組件地址預(yù)覽組件,同時(shí)可以獲取到組件被引用以及引用資源(如css、js、圖片)的相關(guān)情況。 我們的組件分為兩種,一類是通過ath w自動(dòng)創(chuàng)建的,通過ath pu提交到管理平臺(tái)的,在管理平臺(tái)上進(jìn)行組件的相關(guān)分析和編譯,得到組件的信息,這類組件主要是跟業(yè)務(wù)綁定的;另一類是通過ath widget-publish提交到組件平臺(tái)的,由組件平臺(tái)進(jìn)行相關(guān)處理,這類組件是通用組件,與業(yè)務(wù)無(wú)關(guān),用于展示給開發(fā)以及相關(guān)業(yè)務(wù)方看的。 在組件平臺(tái)上可以預(yù)覽與編輯相關(guān)的組件,通過與設(shè)計(jì)師約定相關(guān)的設(shè)計(jì)規(guī)范來(lái)促使組件達(dá)到盡可能地復(fù)用,進(jìn)而減少設(shè)計(jì)師的工作量,提升我們的工作效率。 組件提交到組件平臺(tái)通過ath widget-publish指令將組件提交到組件平臺(tái),組件平臺(tái)會(huì)對(duì)組件源碼進(jìn)行編譯,將組件名稱md5、組件歸類以及組件版本記錄等等。 從組件平臺(tái)上下載組件通過ath widget-load指令將組件下載到本地,當(dāng)本地構(gòu)建工具向組件平臺(tái)發(fā)起請(qǐng)求時(shí),會(huì)帶上組件名稱,組件平臺(tái)會(huì)將源碼進(jìn)行編譯,將組件名稱重命名,并且相應(yīng)地替換源碼中的組件名稱,同時(shí)記錄組件的被引用記錄。 權(quán)限控制權(quán)限控制,項(xiàng)目中存在公共組件模塊,公共組件比較穩(wěn)定,比如說輪播組件、選項(xiàng)卡組件等等,這部分代碼一般比較少變動(dòng),可由少部分人來(lái)更新和維護(hù),所以加入了權(quán)限控制機(jī)制,保證公共組件的穩(wěn)定性。 項(xiàng)目管理我們?cè)谑褂帽镜貥?gòu)建工具時(shí),需要配置多個(gè)參數(shù),比如主機(jī)信息、選擇模版等,在命令行環(huán)境下有些不直觀。為了簡(jiǎn)化這個(gè)操作,管理平臺(tái)提供了項(xiàng)目創(chuàng)建的功能,同時(shí)提供了模版創(chuàng)建的功能。 在項(xiàng)目信息、模塊信息以及組件信息發(fā)生變更的時(shí)候,為了第一時(shí)間能夠通知項(xiàng)目成員更新,加入了消息通知的功能,目前通過發(fā)送郵件的方式,后期可以加入微信提醒的功能。 技術(shù)選型管理平臺(tái)前端采用React+Redux的方式,后端采用Express+MongoDB,整體技術(shù)選型如下: 假數(shù)據(jù)服務(wù)存在的問題在平常的開發(fā)中,經(jīng)常需要前后端聯(lián)調(diào),但是在項(xiàng)目開始之初,很多接口并沒有提供,在以前的開發(fā)模式下,需要等待后端提供接口或者自己先定義接口,前端開發(fā)的進(jìn)度可能會(huì)受影響。 Mock數(shù)據(jù)平臺(tái)為了不影響前端開發(fā)的進(jìn)度,我們搭建了Mock數(shù)據(jù)平臺(tái),通過與后端協(xié)商數(shù)據(jù)格式,自定義數(shù)據(jù)接口,這樣子就可以做到前后端分離,讓前端獨(dú)立于后端進(jìn)行開發(fā)。 Mock數(shù)據(jù)平臺(tái)基于mockjs搭建而成,通過簡(jiǎn)單的mock語(yǔ)法來(lái)生成數(shù)據(jù)。 Mock數(shù)據(jù)平臺(tái)目前有如下功能:
寫在最后本次分享首先講述了我們?cè)跇I(yè)務(wù)膨脹、人員不斷增加的背景下遇到的項(xiàng)目開發(fā)上的問題,并提出了我們自己對(duì)于這些問題思考總結(jié)后得出的解決方案與思路,最后產(chǎn)出適合我們團(tuán)隊(duì)、業(yè)務(wù)的開發(fā)工具—— Athena。希望我們的方案能給大家?guī)?lái)一定的借鑒作用。 感謝您的閱讀,本文由 凹凸實(shí)驗(yàn)室 版權(quán)所有。如若轉(zhuǎn)載,請(qǐng)注明出處:凹凸實(shí)驗(yàn)室(https:///notes/2016/07/19/A-little-exploration-of-front-end-engineering/)
|
|
|
來(lái)自: WindySky > 《項(xiàng)目總結(jié)》