您的位置:首頁 >  新聞中心 > 云通訊公告
  云通訊公告
 

這些坑,我做前端構(gòu)建時都遇見了

來源:原創(chuàng)    時間:2017-11-28    瀏覽:0 次

很多做前端的朋友經(jīng)常問我:為什么我打包總是很慢?為什么我內(nèi)存占用這么大,該怎么優(yōu)化?去哪兒網(wǎng)是怎么做前端構(gòu)建的?
這里,我和大家分享一下在去哪兒網(wǎng)是如何進行前端工程化相關(guān)工作的。
在企業(yè)環(huán)境下的大型工程構(gòu)建會遇到種種問題,我們也是通過不斷地摸索才逐漸總結(jié)出一套解決方案,現(xiàn)在把我們所遇到的一些坑和如何處理這些問題拿出來與大家交流。 
一、構(gòu)建工具演化篇
作為公司內(nèi)部的構(gòu)建工具,最重要的一點是穩(wěn)定性,因為假如它出了問題,不僅會導(dǎo)致項目發(fā)布失敗,還有可能會引起線上故障。
然而在保持穩(wěn)定的同時,它也一定是在不斷發(fā)展的。無論是開發(fā)語言的變化,還是前端框架的迭代更新,都會帶來新的需求。
為了滿足這些需求,在設(shè)計時就一定要有一定的預(yù)見性,知道哪部分未來可能需要擴展以適應(yīng)新的場景。
如何同時擁有穩(wěn)定性和擴展性是公司級別的構(gòu)建工具面臨的最大挑戰(zhàn)。
階段一:完全定制化構(gòu)建
在 2014 年我最開始加入去哪兒網(wǎng)的時候,公司中有一個統(tǒng)一的開發(fā)和構(gòu)建工具——FEKit。它當時主要解決幾個問題:
模塊依賴。類似于 Browserify,可以遵循 CommonJS 標準打包模塊。
包管理器。那時候 npm 還沒有完全流行于前端,F(xiàn)EKit 自己實現(xiàn)了一套類似于 npm 的包管理器,并搭建了模塊倉庫,開發(fā)者可以從倉庫上面安裝包也可以發(fā)布自己的包。
目錄約定。FEKit 對源碼目錄、目標目錄以及打包生成資源的命名格式有自己的規(guī)定,它的好處是可以讓開發(fā)和構(gòu)建發(fā)布的流程相對統(tǒng)一,減少學習成本。
除上面之外,F(xiàn)EKit 還具備 SASS 編譯、代碼壓縮、版本號生成等特性,在當時可以說是比較完備的開發(fā)構(gòu)建工具了。
同時也可以看出它其實是將一整套構(gòu)建流程封裝好,只要開發(fā)者熟悉了它的配置,在面對任何一個 FEKit 的項目的時候都能較快上手。
但是隨著時間的推移也逐漸暴露出 FEKit 在擴展性方面的不足,由于它內(nèi)置的編譯打包流程是規(guī)定死的,因此它很難去適應(yīng)新的需求。
比如,當 ES2015 出現(xiàn)后,有些同學提出想把 Babel 放在 FEKit 的構(gòu)建流程里面。
但是在公司的打包發(fā)布平臺上面 FEKit 只能存在一個版本,任何改動都會影響到所有項目的發(fā)布,我們很難去冒這樣的風險去改動所有業(yè)務(wù)的打包流程,這也阻礙了 FEKit 向前推進的腳步。 
階段二:放開手腳自定義構(gòu)建
為了實現(xiàn)各自的需求,不同的業(yè)務(wù)開始嘗試自己搭建一套開發(fā)和發(fā)布流程。Gulp、Grunt、Webpack 全都有,大家各玩各的。
看似都能實現(xiàn)新的需求了,但從這類孤立搭建的工程中也發(fā)現(xiàn)了幾個共同的問題:
重復(fù)造輪子。像是配置預(yù)編譯器、生成資源版本號、Mock 服務(wù)等這些類似的工作經(jīng)常被重頭到尾實現(xiàn)一遍。
而如果它們由統(tǒng)一的工具來實現(xiàn)則可以節(jié)省很多開發(fā)成本。
缺少構(gòu)建層面的優(yōu)化。不管是從打包出來的資源體積以及編譯速度上,不少工程都還有很大的提升空間。
我們曾試著將其中一個工程的公用庫用 CommonChunks 的方式提取出來,將整體資源體積減小了多一半。
造成這個問題的原因是很多時候開發(fā)同學只是想短平快地完成一些業(yè)務(wù),并不會過多關(guān)注流程上的優(yōu)化。
溝通和學習成本高。大家各玩一套的結(jié)果是跨團隊和跨工程時會由于構(gòu)建工具和流程不一樣而帶來額外的成本。
當面對一個缺少文檔的新工程時,一個剛接觸的同學可能會完全不知所措,而工程之間構(gòu)建工具的不一致也會導(dǎo)致切換環(huán)境時要花費更多的精力。 
階段三:約束與自由的平衡
基于以上幾點問題,我們決定開發(fā)一個新的構(gòu)建工具,在設(shè)計時希望它能解決以下幾個問題:
提供統(tǒng)一的配置,如資源輸入輸出目錄、版本號規(guī)則、壓縮插件等,并且允許更改這些配置。
有默認的構(gòu)建流程,也允許自定義工作流。比如開發(fā)者可以選擇使用 Babel、TypeScript 來編譯 JavaScript,也可以用 SASS、LESS 來做樣式的預(yù)編譯等等。
提供統(tǒng)一的構(gòu)建優(yōu)化手段和工具服務(wù),像是按需加載、多進程打包編譯等這類工作最好內(nèi)置在工具中,業(yè)務(wù)不需要過多地關(guān)心如何優(yōu)化項目。
于是后來我們開發(fā)了 YKit。它最大的特點在于允許開發(fā)者在其基礎(chǔ)上自定義配置,并且可以將一系列構(gòu)建工作流封裝為模塊,然后就可以像搭積木一樣快速地通過這些模塊搭建起一個環(huán)境。
舉個例子,當你想開發(fā)一個 React 項目的時候,使用 ykit init react 一行命令就可以將一個內(nèi)置好各項 React 相關(guān)配置的工程初始化好。而當你需要使用其它配置的時候安裝和引入更多的 YKit 插件即可。
比如,希望在項目中使用 TypeScript,則執(zhí)行命令 npm install ykit-config-ts;
想要使用 Mock 數(shù)據(jù)中間件,則執(zhí)行 npm install ykit-config-mock,以此類推。
YKit 其實是基于 Webpack 的一層封裝,在面向開發(fā)者的時候它把復(fù)雜的 Webpack 配置封裝在各個 npm 模塊內(nèi)部,對于開發(fā)者而言則只要關(guān)注功能即可。
同時 YKit 也留了一個更改配置的接口 —— modifyWebpackConfig,把內(nèi)部的 Webpack 配置對象暴露出來,開發(fā)者可以基于自身的需求進行進一步深入定制。
從上面可以看出,YKit 是一個兼顧統(tǒng)一性與自由度的解決方案。在去哪兒那么多業(yè)務(wù)線,每個小團隊都有自己習慣的開發(fā)方式。
YKit 希望做的事情是幫助每個團隊將它們的構(gòu)建配置封裝起來,通過 npm 模塊的方式來管理,這樣當每次新建一個項目的時候,直接拿來以前封裝好的配置即可,以最快的速度搭建好一整套開發(fā)和發(fā)布流程。 
二、構(gòu)建速度優(yōu)化篇
1. npm 包版本號固定
相面在講包管理器的時候時候已經(jīng)介紹過,使用版本固定文件可以帶來兩個好處。
避免語義化版本號( semver )帶來的包版本變化風險。
加快 npm 解析包依賴的速度。
在去哪兒網(wǎng)發(fā)布前端項目時(其實也包括 Node.js 項目)會進行版本固定文件是否存在的校驗,如果沒有則會直接阻斷發(fā)布。 
2. npm 包緩存
在一般企業(yè)環(huán)境中進行前端發(fā)布一般有兩種方式。
在開發(fā)者本地進行工程構(gòu)建,將打包好的資源( JS、CSS 等)上傳  CDN。
通過特定的服務(wù)器將代碼倉庫克隆下來,進行構(gòu)建和發(fā)布。 
在去哪兒網(wǎng)我們使用第二種方式。但是有一個問題,由于是在服務(wù)器上進行 npm 模塊安裝和打包,并且當時 npm 的緩存機制效率較低,通常 npm install 的耗時很長。
針對這種情況,我們設(shè)計了一個 npm 包緩存工具—— ncs( npm-cache-share )。
ncs 不僅可以充分利用本機的 npm 緩存,還可以和多臺服務(wù)器間共享緩存。由于發(fā)布的服務(wù)器有多臺,因此每一臺的安裝結(jié)果都可以緩存下來供其它的服務(wù)器使用。
通過這種緩存機制可以大大提高安裝 npm 模塊速度,在一個充分緩存的環(huán)境下,一個大型工程的安裝過程也只有短短幾秒。 
3. 打包編譯優(yōu)化
談到打包和編譯這部分,就又回到我們說的 YKit 上面。在每一個封裝的配置模塊的里面 YKit 其實已經(jīng)做了優(yōu)化。
比如說,對于 React 項目來說,YKit 會使用 Happypack 來進行多進程編譯。
在生產(chǎn)環(huán)境下,會添加 process.env.NODE_ENV= production 的環(huán)境變量來使 React 去掉開發(fā)環(huán)境代碼。 
在各類封裝好的構(gòu)建方案中 YKit 也會提供相應(yīng)的最佳實踐,這樣業(yè)務(wù)同學基本不用踩坑,各項優(yōu)化以及各種兼容性的問題基本都在方案內(nèi)部得到實現(xiàn)和解決,對于開發(fā)者而言是透明的。
三、代碼質(zhì)量篇 
每個公司幾乎都有自己的一套代碼風格或者是編碼約定。在不斷有新人進公司的過程中,如何保證風格的統(tǒng)一?代碼質(zhì)量檢測是一個很好的方法。
1. 代碼質(zhì)量控制的意義
試想一下,假如你剛進一個公司沒多久,提交了自己的第一段代碼。然后你的 Leader 來找你,跟你說你這個代碼哪里哪里不規(guī)范(其實也許只是不符合公司的風格),會不會覺得有點不太舒服?
如果換成是一個質(zhì)量檢測工具,在你提交的時候自動攔截下來并指出問題。
你稍作修改之后重新提交并且完美通過,同時 Leader 看到的也是符合他編碼要求的代碼,這樣是不是顯得友好地多? 
很多代碼中容易疏忽的錯誤都可以靠質(zhì)量控制工具檢測出來。
比如忘記刪掉了打印調(diào)試日志的代碼、哪個變量聲明了但是沒有用到、或者說在頁面打了個 Alert 出來。
機器完全能幫我們查出來并且修改掉,為什么還要去人力測試和改正呢。 
2. Sonar
Sonar 是一個質(zhì)量檢測平臺,在去哪兒網(wǎng)我們用它來做持續(xù)集成,控制前后端代碼的質(zhì)量。
每當我們提交了一段代碼上去以后,都會自動通過 Sonar 進行質(zhì)量檢測,并把檢測結(jié)果發(fā)回來。
結(jié)果中的信息會進行分級,有一些問題是阻斷性質(zhì)的,意思是必須要進行修改,否則無法進行發(fā)布。
還有一些則只是警告,告訴開發(fā)者這種編碼風格不太好,但并不會影響發(fā)布流程。 
3. ESLint
對于前端開發(fā)者來說 ESLint 應(yīng)該再熟悉不過了。如果說 Sonar 是公司級別的質(zhì)量控制工具,那么 ESLint 則是各個前端團隊自己使用的工具。
在前面我們提到的 YKit 中有一個專門為去哪兒網(wǎng)設(shè)計的配置插件,內(nèi)部包含了一些基本的規(guī)則。
但是對于更詳細的規(guī)則而言,由于不同的團隊內(nèi)部約束并不一樣,這里留給了團隊自己進行配置。 
四、發(fā)布平臺篇 
之前在去哪兒網(wǎng)主要使用 Jenkins 作為發(fā)布平臺,它基本能夠滿足所有業(yè)務(wù)的需求。
比如,用它來打包和發(fā)布前端、后端、客戶端應(yīng)用、通過 Sonar 進行代碼質(zhì)量檢測、集成郵件通知等等。
而 Jenkins 也存在一些不足之處,比如界面比較過時、用戶體驗差、在一些多應(yīng)用聯(lián)合發(fā)布的場景下速度較慢。
因此后來我們自己搭了一個內(nèi)部的發(fā)布平臺 Portal,它有如下幾項優(yōu)勢:
更現(xiàn)代的設(shè)計以及更友好的用戶體驗,特別是進度和日志得到了更清晰地呈現(xiàn)。
錯誤處理。對于不具備版本描述文件這類阻斷發(fā)布性質(zhì)的錯誤可以提前進行校驗,不必讓大家等了一會然后突然報錯了。
性能提升。一次發(fā)布任務(wù)可能牽扯到前后端多個應(yīng)用的發(fā)布,以前只能集中在一臺服務(wù)器上順序發(fā)布,現(xiàn)在可以多臺服務(wù)器分散執(zhí)行,資源調(diào)配更均衡。
在目前發(fā)布平臺的使用上,Jenkins 和 Portal 都有,畢竟 Jenkins 用了這么久很多業(yè)務(wù)同學會比較習慣。
但就未來來說 Portal 這類新的平臺應(yīng)該會占據(jù)越來越大的比重,畢竟它更適合于快速實現(xiàn)一些公司內(nèi)部定制化的需求。


免费视频观无码一区,国内精品一区二区无码,99精品无码视频在线播放,ā片国产在线播放