最近1年多,前后端同構(gòu)慢慢變成一個(gè)流行詞,也許很多人還停留在前后端分離的最佳實(shí)踐道路上,但實(shí)際上又有一批人已經(jīng)從簡(jiǎn)單的服務(wù)端渲染走向探索最佳前后端同構(gòu)方案的路上了。不過(guò),我只是膜拜后者的過(guò)客。

 

雖然大家可以去網(wǎng)絡(luò)搜索一下相關(guān)的概念解釋?zhuān)@里我還是簡(jiǎn)單列舉一下,我理解的術(shù)語(yǔ)。

1、前端渲染:瀏覽器一側(cè)使用js,借助模版或vue、react、angular等框架做的DOM結(jié)構(gòu)生成。

2、后端渲染:服務(wù)器一側(cè),使用php、nodejs等技術(shù)實(shí)現(xiàn)DOM結(jié)構(gòu)生成,并在HTTP請(qǐng)求中返回給瀏覽器。

3、同構(gòu):瀏覽器一側(cè)的JS、HTML和服務(wù)器一側(cè)使用的JS、HTML使用同樣的開(kāi)發(fā)結(jié)構(gòu),同樣的開(kāi)發(fā)思路,同樣的開(kāi)發(fā)模式,盡可能實(shí)現(xiàn)代碼復(fù)用。

 

明確一點(diǎn),作為有追求的前端開(kāi)發(fā),我們不應(yīng)該盲目跟風(fēng),一切需要從實(shí)際出發(fā)。

 

那么,首先,我們需要了解為什么會(huì)有同構(gòu)這個(gè)概念出現(xiàn)。

  • Web開(kāi)發(fā)的歷程是很有趣的,最初php、asp的年代,一切內(nèi)容都是服務(wù)器渲染的;

  • 再后來(lái)為了節(jié)省服務(wù)器資源,也更大限度利用客戶(hù)端緩存,又出現(xiàn)了前后端分離的模式,從而有了專(zhuān)業(yè)的前端開(kāi)發(fā)和后臺(tái)開(kāi)發(fā)。此時(shí)Web的特點(diǎn)是,js和html放到靜態(tài)目錄,也可以CDN擴(kuò)散,并以ajax方式獲取后臺(tái)的數(shù)據(jù),在前端進(jìn)行DOM組裝。這種開(kāi)發(fā)方式沿用至今,這是一個(gè)好的工作模式,專(zhuān)業(yè)的人做專(zhuān)業(yè)的事,確實(shí)有利于工作效率提高。

  • 再而,隨著nodejs的流行,前端jser們又開(kāi)始蠢蠢欲動(dòng),嘗試吞并web接入這個(gè)后臺(tái)的前沿地盤(pán),把后臺(tái)推到更后。大概2014年后,又出現(xiàn)了很多nodejs直出的方案,把頁(yè)面數(shù)據(jù)都一次在HTML的請(qǐng)求中返回,無(wú)需瀏覽器端再發(fā)起ajax獲取數(shù)據(jù),而且服務(wù)器端把DOM結(jié)構(gòu)都渲染好,瀏覽器按trunk直接做圖形渲染即可。不得不說(shuō),這個(gè)方案帶來(lái)了很多好處:首屏速度更快,瀏覽器更省電。當(dāng)然,隨之而來(lái)的,就是更復(fù)雜的工作模式,jser需要做服務(wù)器端的邏輯,甚至一些代碼需要同時(shí)用在瀏覽器和nodejs上。

  • 針對(duì)前邊的問(wèn)題,同構(gòu)的探討就開(kāi)始了。。。

 

百度搜一下前后端同構(gòu),清一色的vue、react。這些確實(shí)是同構(gòu),但我認(rèn)為范圍太窄,同構(gòu)不是框架帶來(lái)的問(wèn)題,而是因?yàn)榍昂蠖霜?dú)立渲染這種架構(gòu)層面帶來(lái)的問(wèn)題。

當(dāng)然,那些同構(gòu)探討也是非常有價(jià)值的,但不在本文的討論范圍內(nèi),在這里我更想表達(dá)一下,如何從實(shí)際項(xiàng)目需求的角度來(lái)看,找出自己所需的同構(gòu)之道。

畢竟,要知道,同構(gòu)不是為了跟風(fēng)???,也不是為了跳槽面試的時(shí)候博點(diǎn)好感。同構(gòu),是為了提高用戶(hù)體驗(yàn)的同時(shí),提高團(tuán)隊(duì)的工作效率。

 

接下來(lái),我想根據(jù)項(xiàng)目的類(lèi)型,說(shuō)說(shuō)自己的看法。

 

第一種,單頁(yè)面應(yīng)用。

這個(gè)網(wǎng)站很類(lèi)似一個(gè)APP,確實(shí)很有必要做成單頁(yè)應(yīng)用,有助于提高用戶(hù)體驗(yàn)。

如果第一步選擇了單頁(yè)面應(yīng)用,這里就衍生了另外的問(wèn)題——SEO。而react等框架做了服務(wù)器渲染,最大目的其實(shí)也是解決SEO。

既然瀏覽器端選擇了某個(gè)框架,例如React,而同時(shí)又考慮nodejs直出提高首屏的速度,那么就沒(méi)有討價(jià)還價(jià)的余地了,當(dāng)然上react全家桶,前后端都用react。

這一種情況,也就是網(wǎng)上搜索到的各種文章的情況。

 

第二種,多頁(yè)面純數(shù)據(jù)展示,每一頁(yè)都比較簡(jiǎn)單,沒(méi)有分屏的必要。

如果項(xiàng)目是這樣的情況,使用nodejs直出,無(wú)非就是提高打開(kāi)速度。而前后端基本八竿子打不著,最多就是一些工具函數(shù)(轉(zhuǎn)換一下日期格式,輸入框校驗(yàn))要做復(fù)用。

此時(shí),沒(méi)必要大費(fèi)周折去考慮什么框架,因地制宜,想想自己需要什么即可。

要解決函數(shù)庫(kù)的前后端復(fù)用,可以簡(jiǎn)單做cmd和window全局模式的兼容。

如果瀏覽器端的代碼比較多,就可以考慮粒度化,使用webpack做瀏覽器端代碼打包,同時(shí)CMD的寫(xiě)法也可以直接復(fù)用到nodejs層。

 

第三種,多頁(yè)面而且每一頁(yè)不是那么簡(jiǎn)單,首屏和次屏有一些HTML片段(模版)需要復(fù)用

之前我所在項(xiàng)目組也遇到這樣的情況,怎么處理,一時(shí)之間為了趕進(jìn)度也沒(méi)太多考慮,使用了一些旁門(mén)左道,不好理解不好維護(hù)的方式,基于art-template做了一套有點(diǎn)奇怪的代碼,基本沒(méi)有同構(gòu)一說(shuō)。唯一同構(gòu)的就是art-template支持瀏覽器和nodejs。

情況怎么惡心呢?大概是這樣:

  • html模版,為了復(fù)用,拆開(kāi)為多個(gè)小文件,如果前后端都用到,則一方面把這個(gè)模版內(nèi)容不轉(zhuǎn)義不編譯地塞到最終HTML中,而另一方面利用這個(gè)模版做nodejs渲染。前端ajax加載數(shù)據(jù)后渲染次屏?xí)r,再讀取HTML中某個(gè)模版做處理。

  • 對(duì)于處理數(shù)據(jù)的js,可封裝部分,則利用跟剛才第二種情況類(lèi)似的方式,做了cmd和window兼容的方式;不好封裝的部分,基本等于寫(xiě)了兩份。

  • 前端的js,動(dòng)態(tài)塞到http返回中輸出的HTML中,可能有若干個(gè)js。

回頭想想,當(dāng)時(shí)情況確實(shí)很糟,其實(shí)可以利用已有的工具做得更優(yōu)。

art-template是個(gè)好東西,這個(gè)沒(méi)必要去除。剛說(shuō)的前兩點(diǎn),表明這個(gè)項(xiàng)目有強(qiáng)烈的前后端代碼復(fù)用的必要,很有需要使用更全面的同構(gòu)方案。

現(xiàn)在我覺(jué)得有更好的方式:

  • 用webpack做前端打包,這樣前端各種代碼和后臺(tái)代碼都是CMD風(fēng)格,可以二合一。而且發(fā)布前打包為一個(gè)大js文件,也省去nodejs每次請(qǐng)求動(dòng)態(tài)合并js的消耗。

  • html模版發(fā)布前先做預(yù)編譯,從html+模版語(yǔ)法,轉(zhuǎn)為純js代碼,隨著webpack打包到瀏覽器端大js文件中。

  • 后端和前端都用到的代碼,基于CMD,盡可能的抽離封裝。

  • 最終合并的瀏覽器端大js還是動(dòng)態(tài)合并到首屏HTML中。

引入了cmd和webpack到瀏覽器端,就能很好的解決了原先html模版?zhèn)鞑サ膶擂?。而cmd風(fēng)格的統(tǒng)一,也有利于前后端代碼更好的復(fù)用。

至于最終瀏覽器js是否打包到首屏HTML中,還是單獨(dú)的部署CDN,這個(gè)其實(shí)就不是同構(gòu)的問(wèn)題了。不過(guò)對(duì)于移動(dòng)端而言,還是建議合并在一起。

 

抽象一下,對(duì)于第三種項(xiàng)目情況,跳出我原先的項(xiàng)目。我認(rèn)為,關(guān)鍵是要把前后端使用的模版統(tǒng)一為一個(gè)方式引入。

 

第四種,還是多頁(yè)面,瀏覽器端沒(méi)有模版拼裝的需求,第三種情況的變種。

或者說(shuō),這個(gè)不是一個(gè)單獨(dú)的項(xiàng)目情況,只是因?yàn)橛玫募夹g(shù)方案不同。跟第三種情況一樣,但次屏的渲染,我們不在瀏覽器端執(zhí)行,而是繼續(xù)交給nodejs。瀏覽器端通過(guò)ajax把次屏html片段拉取回來(lái),然后直接塞到body中。而且,除此之外,瀏覽器端沒(méi)有用戶(hù)交互會(huì)導(dǎo)致已有的DOM發(fā)生重繪,或者極少內(nèi)容重繪,不需要?jiǎng)佑玫侥0妗?/p>

在這個(gè)情況下,瀏覽器端js更純粹的只關(guān)注事件處理。

我覺(jué)得這個(gè)又回到了第二種情況,只需要簡(jiǎn)單把一些庫(kù)函數(shù)封裝一下,做成前后端共用即可。

第四種情況,因?yàn)閺氐讙仐壛藶g覽器渲染,整個(gè)情況就簡(jiǎn)單多了,不需要考慮模版和很多邏輯js的前后端復(fù)用問(wèn)題。

 

kenkofox@qq.com https://github.com/kenkozheng 歡迎投簡(jiǎn)歷給我,力推騰訊工作機(jī)會(huì)

分類(lèi): HTML/JS/CSS

http://www.cnblogs.com/kenkofox/p/7015795.html