客戶端JavaScript的5個(gè)弊端
譯注:原來(lái)的標(biāo)題是:“我們?yōu)樯恫挥肁ngularJS:…”,后來(lái)作者覺(jué)得不妥就改掉了,因?yàn)锳ngularJS是通常適用于單頁(yè)面程序框架(SPA) 很多人理解為對(duì)AngularJS的抨擊,但這并不是他的本意。
幾個(gè)月前,當(dāng)我們打開Sourcegraph網(wǎng)站的時(shí)候,它是一個(gè)富AngularJS應(yīng)用,服務(wù)器只要把原始HTML和JSON endpoints返回,剩下的就交給Angular來(lái)搞定了。我們就這樣懵懵懂懂地做出了最初版本的Sourcegraph。
但是單頁(yè)(single-page) JavaScript框架并不適用于每一個(gè)站點(diǎn)。Sourcegraph就是一個(gè)內(nèi)容為主的站點(diǎn),我們漸漸發(fā)現(xiàn)這個(gè)富js應(yīng)用的開發(fā)還是弊大于利;下面是我們?cè)谔街@條路上遇到的溝溝坎坎,希望對(duì)有雷同遭遇的開發(fā)人員一些幫助。
下周,我們來(lái)討論更多地關(guān)于我們是如何從AngularJS遷移server-side GO templates
客戶端JS框架的5個(gè)弊端
我們?cè)缇椭肋@會(huì)有很多的困難,但是不知道到底有多難
1. 搜索排名和Twitter/Facebook預(yù)覽
搜索引擎爬蟲和社交網(wǎng)站的預(yù)覽抓取器不能加載純Javascript站點(diǎn),而如果提供替換版本又慢又復(fù)雜
有兩種方法可以允許爬蟲閱讀你得站點(diǎn)。你可以在服務(wù)器端運(yùn)行一個(gè)瀏覽器實(shí)例用以執(zhí)行你的應(yīng)用里的Javascript,然后返回HTML結(jié)果(PlantomJS或者WebLoop)。 或者你可以為你的站點(diǎn)專門建立一個(gè)HTML版本為爬蟲服務(wù)
***個(gè)方法需要你為每一次頁(yè)面加載建立一個(gè)headless瀏覽器(或者tab),比起直接產(chǎn)出HTML,這樣會(huì)花費(fèi)很多的時(shí)間和系統(tǒng)資源。基于你用的框架,會(huì)花費(fèi)很多的工作來(lái)決定什么時(shí)候已經(jīng)準(zhǔn)備好的頁(yè)面將被渲染。 你可以緩存頁(yè)面,但是如果頁(yè)面經(jīng)常改變,不但優(yōu)化甚微而且會(huì)增大復(fù)雜度。
這樣做還會(huì)降低你的頁(yè)面加載速度好幾秒,對(duì)搜索引擎排名也不利。(PlantomJS需要Xvfb和WebKit)
第二個(gè)方法(做一個(gè)服務(wù)器端站點(diǎn))對(duì)簡(jiǎn)單地站點(diǎn)有效,但是如果頁(yè)面很多,那用這個(gè)方法就形同噩夢(mèng)。
如果Google認(rèn)為你的服務(wù)器版本站點(diǎn)跟你的主站版本有很大的不同,那他就會(huì)狠狠的懲罰你,到時(shí)候你連怎么死的都不知道
2. 不可靠的統(tǒng)計(jì)和監(jiān)控
很多分析工具需要易于出錯(cuò),人工集成來(lái)使用HTML5 history API(pushState)用于導(dǎo)航。因?yàn)樗麄兒茈y自動(dòng)檢測(cè)到你的應(yīng)用使用pushState導(dǎo)航到了新的頁(yè)面。即使可以做到,他們?nèi)匀恍枰却銘?yīng)用里的信號(hào)來(lái)收集新頁(yè)面的信息
如何解決這個(gè)問(wèn)題呢?取決于你的客戶端用什么導(dǎo)航和你想集成什么分析工具。用Google分析+Backbone.js?嘗試一下backbone.analytics。用Heap(順便說(shuō)一下,太酷了)和UI-Router?設(shè)置你自己的$stateChangeSuccess并調(diào)用heap.track
還沒(méi)完事呢!你想追蹤起始頁(yè)面加載?也許你在雙向跟蹤他?你會(huì)跟蹤失敗的頁(yè)面記載嗎?如果你使用replaceState代替pushState呢?如果你錯(cuò)誤的配置了分析掛鉤或者屬于檢查導(dǎo)致依賴升級(jí)搞壞了事情。當(dāng)你發(fā)現(xiàn)的售后,很難去恢復(fù)你錯(cuò)過(guò)的分析數(shù)據(jù)(或者消除重復(fù)數(shù)據(jù))
3. 又慢又復(fù)雜的構(gòu)建工具
前-后端JavaScript構(gòu)建工具,比如Grunt,需要復(fù)雜的配置而且很慢。還好我們有像ng-boilerplate這樣的project來(lái)幫我們做配置,但是如果你想添加一個(gè)自定義的步驟還是逃不出又慢有復(fù)雜的怪圈(我為什么說(shuō)Grunt復(fù)雜,看看這個(gè)配置文件就知道了)
一旦你配置好了你的應(yīng)用,你仍然要忍受漫長(zhǎng)的JavaScript構(gòu)建時(shí)間。你可以把dev和production構(gòu)建通道分開來(lái)提高開發(fā)速度,但是始終免不了走這么一遭,用AngularJS尤其如此,他需要在丑陋的代碼前使用ngmin(如果你用了這個(gè)功能)。其實(shí),Sourcegraph因?yàn)檫@些丑陋的JavaScript表現(xiàn)代碼幾度被毀
還好,Gulp已經(jīng)有了極大的提高
4. 慢,不可靠的測(cè)試
測(cè)試JavaScript-only的站點(diǎn)需要使用基于瀏覽器的測(cè)試框架,比如Selenium,PhantomJS,或者WebLoop。安裝這些(除了PhantomJS)通常意味著安裝WebKit和Java依賴,配置Xvfb(機(jī)關(guān)新的PhantomJS移除了這些先決條件),或者運(yùn)行一個(gè)本地的VNC客戶端和服務(wù)器來(lái)測(cè)試。***,你還需要在持續(xù)集成的服務(wù)器上設(shè)定所有東東
相反,測(cè)試服務(wù)器端產(chǎn)生的頁(yè)面通常只需要類庫(kù)來(lái)或者URLs并解析HTML,安裝和配置起來(lái)簡(jiǎn)單許多
一旦你開始寫瀏覽器測(cè)試,你必須處理異步加載。你不能在頁(yè)面還沒(méi)有加載的時(shí)候就測(cè)試頁(yè)面上的元素,但是如果在一個(gè)特定時(shí)間端里沒(méi)有加載,你的測(cè)試就會(huì)失敗。瀏覽器測(cè)試類庫(kù)提供了很好地功能來(lái)處理這種情況,他們只能在負(fù)載的頁(yè)面里使用這些功能
如果你想聯(lián)合重量級(jí)瀏覽器來(lái)進(jìn)行(Selenium,加上Firefox或者Webkit)很復(fù)雜的測(cè)試(因?yàn)闉g覽器的異步特質(zhì))?你的測(cè)試需要很多配置,很長(zhǎng)的時(shí)間來(lái)執(zhí)行,而且很不可靠
5. 慢,可以緩解,但沒(méi)有解決
在富JavaScript應(yīng)用中,頁(yè)面轉(zhuǎn)化幾乎是瞬間發(fā)生,然后所有的特定元素異步加載。在server-side應(yīng)用中,完全相反:頁(yè)面在服務(wù)器端加載完成前不會(huì)發(fā)送到客戶端
聽(tīng)起來(lái)似乎是client-side應(yīng)用勝利了,但是也許會(huì)是個(gè)坑也不一定
當(dāng)用戶點(diǎn)擊一個(gè)鏈接,client-side應(yīng)用會(huì)立刻加載頁(yè)面并呈現(xiàn)。如果用戶用sidebar導(dǎo)航到一個(gè)需要5秒鐘才可以加載的頁(yè)面。***次感覺(jué)很快,但是如果一個(gè)用戶需要的信息在sidebar里,對(duì)用戶來(lái)說(shuō)就感覺(jué)很難受。即使你需要的特定內(nèi)容立即呈現(xiàn),你仍需要忍受加載指示器和頁(yè)面填充后的抖動(dòng)
我們來(lái)考慮如果開發(fā)人員想在那個(gè)頁(yè)面添加新功能。是很難讓她的功能必須快速加載的-因?yàn)槎际钱惒降模哉l(shuí)會(huì)在意頁(yè)面底部過(guò)了幾秒才加載呢?如此反復(fù)幾次,整個(gè)站點(diǎn)讓人感覺(jué)滯后很抖動(dòng)
在server-side 應(yīng)用中,如果一個(gè)API調(diào)用很慢,整個(gè)頁(yè)面就會(huì)停滯直到徹底完成。這個(gè)不容忽視的server-side慢節(jié)奏很容易被測(cè)量并會(huì)公平地影響每一個(gè)人。但是在client-side應(yīng)用中很容易被忽略
你可以說(shuō),一個(gè)好的開發(fā)團(tuán)隊(duì)?wèi)?yīng)該避免這些錯(cuò)誤,并且client-side JS 框架不是罪魁禍?zhǔn)住J堑模琧lient-side JS框架提高了速度。這一點(diǎn)改變鼓勵(lì)了任何開發(fā)團(tuán)隊(duì)
下一步?
上面說(shuō)得都不是大問(wèn)題。我們已經(jīng)做了很多來(lái)減輕上述情況。
總而言之,上述種種以為這client-side JS 框架加大了我們開發(fā)的負(fù)擔(dān)。
而且要記住,每一個(gè)站點(diǎn)都是不同的。Sourcegraph是一個(gè)內(nèi)容站點(diǎn),他得頁(yè)面在加載后不會(huì)有太多的變化(相較于富JS應(yīng)用),我們依然愛(ài)著浙西技術(shù),但是他們不一定是構(gòu)建主站點(diǎn)的正確工具。
原文鏈接: Sourcegraph 翻譯: 伯樂(lè)在線 - 蔡蔡