最近1年多,前后端同構慢慢變成一個流行詞,也許很多人還停留在前后端分離的最佳實踐道路上,但實際上又有一批人已經從簡單的服務端渲染走向探索最佳前后端同構方案的路上了。不過,我只是膜拜后者的過客。
雖然大家可以去網絡搜索一下相關的概念解釋,但這里我還是簡單列舉一下,我理解的術語。
1、前端渲染:瀏覽器一側使用js,借助模版或vue、react、angular等框架做的DOM結構生成。
2、后端渲染:服務器一側,使用php、nodejs等技術實現DOM結構生成,並在HTTP請求中返回給瀏覽器。
3、同構:瀏覽器一側的JS、HTML和服務器一側使用的JS、HTML使用同樣的開發結構,同樣的開發思路,同樣的開發模式,盡可能實現代碼復用。
明確一點,作為有追求的前端開發,我們不應該盲目跟風,一切需要從實際出發。
那么,首先,我們需要了解為什么會有同構這個概念出現。
- Web開發的歷程是很有趣的,最初php、asp的年代,一切內容都是服務器渲染的;
- 再后來為了節省服務器資源,也更大限度利用客戶端緩存,又出現了前后端分離的模式,從而有了專業的前端開發和后台開發。此時Web的特點是,js和html放到靜態目錄,也可以CDN擴散,並以ajax方式獲取后台的數據,在前端進行DOM組裝。這種開發方式沿用至今,這是一個好的工作模式,專業的人做專業的事,確實有利於工作效率提高。
- 再而,隨着nodejs的流行,前端jser們又開始蠢蠢欲動,嘗試吞並web接入這個后台的前沿地盤,把后台推到更后。大概2014年后,又出現了很多nodejs直出的方案,把頁面數據都一次在HTML的請求中返回,無需瀏覽器端再發起ajax獲取數據,而且服務器端把DOM結構都渲染好,瀏覽器按trunk直接做圖形渲染即可。不得不說,這個方案帶來了很多好處:首屏速度更快,瀏覽器更省電。當然,隨之而來的,就是更復雜的工作模式,jser需要做服務器端的邏輯,甚至一些代碼需要同時用在瀏覽器和nodejs上。
- 針對前邊的問題,同構的探討就開始了。。。
百度搜一下前后端同構,清一色的vue、react。這些確實是同構,但我認為范圍太窄,同構不是框架帶來的問題,而是因為前后端獨立渲染這種架構層面帶來的問題。
當然,那些同構探討也是非常有價值的,但不在本文的討論范圍內,在這里我更想表達一下,如何從實際項目需求的角度來看,找出自己所需的同構之道。
畢竟,要知道,同構不是為了跟風耍酷,也不是為了跳槽面試的時候博點好感。同構,是為了提高用戶體驗的同時,提高團隊的工作效率。
接下來,我想根據項目的類型,說說自己的看法。
第一種,單頁面應用。
這個網站很類似一個APP,確實很有必要做成單頁應用,有助於提高用戶體驗。
如果第一步選擇了單頁面應用,這里就衍生了另外的問題——SEO。而react等框架做了服務器渲染,最大目的其實也是解決SEO。
既然瀏覽器端選擇了某個框架,例如React,而同時又考慮nodejs直出提高首屏的速度,那么就沒有討價還價的余地了,當然上react全家桶,前后端都用react。
這一種情況,也就是網上搜索到的各種文章的情況。
第二種,多頁面純數據展示,每一頁都比較簡單,沒有分屏的必要。
如果項目是這樣的情況,使用nodejs直出,無非就是提高打開速度。而前后端基本八竿子打不着,最多就是一些工具函數(轉換一下日期格式,輸入框校驗)要做復用。
此時,沒必要大費周折去考慮什么框架,因地制宜,想想自己需要什么即可。
要解決函數庫的前后端復用,可以簡單做commonjs/window的兼容。
如果瀏覽器端的代碼比較多,就可以考慮粒度化,使用webpack做瀏覽器端代碼打包,同時commonjs的寫法也可以復用到nodejs層。
第三種,多頁面而且每一頁不是那么簡單,首屏和次屏有一些HTML片段(模版)需要復用
之前我所在項目組也遇到這樣的情況,怎么處理,一時之間為了趕進度也沒太多考慮,使用了一些旁門左道,不好理解不好維護的方式,基於art-template做了一套有點奇怪的代碼,基本沒有同構一說。唯一同構的就是art-template支持瀏覽器和nodejs。
情況怎么惡心呢?大概是這樣:
- html模版,為了復用,拆開為多個小文件,如果前后端都用到,則一方面把這個模版內容不轉義不編譯地塞到最終HTML中,而另一方面利用這個模版做nodejs渲染。前端ajax加載數據后渲染次屏時,再讀取HTML中某個模版做處理。
- 對於處理數據的js,可封裝部分,則利用跟剛才第二種情況類似的方式,做了commonjs/window的方式;不好封裝的部分,基本等於寫了兩份。
- 前端的js,動態塞到http返回中輸出的HTML中,可能有若干個js。
回頭想想,當時情況確實很糟,其實可以利用已有的工具做得更優。
art-template是個好東西,這個沒必要去除。剛說的前兩點,表明這個項目有強烈的前后端代碼復用的必要,很有需要使用更全面的同構方案。
現在我覺得有更好的方式:
- 用webpack做前端打包,這樣前端各種代碼和后台代碼都是commonjs風格,可以二合一。而且發布前打包為一個大js文件,也省去nodejs每次請求動態合並js的消耗。
- html模版發布前先做預編譯,從html+模版語法,轉為純js代碼,隨着webpack打包到瀏覽器端大js文件中。
- 后端和前端都用到的代碼,基於commonjs,盡可能的抽離封裝。
- 最終合並的瀏覽器端大js還是動態合並到首屏HTML中。
引入了webpack到瀏覽器端,就能很好的解決了原先html模版傳播的尷尬。而模塊風格的統一,也有利於前后端代碼更好的復用。
至於最終瀏覽器js是否打包到首屏HTML中,還是單獨的部署CDN,這個其實就不是同構的問題了。不過對於移動端而言,還是建議合並在一起。
抽象一下,對於第三種項目情況,跳出我原先的項目。我認為,關鍵是要把前后端使用的模版統一為一個方式引入。
第四種,還是多頁面,瀏覽器端沒有模版拼裝的需求,第三種情況的變種。
或者說,這個不是一個單獨的項目情況,只是因為用的技術方案不同。跟第三種情況一樣,但次屏的渲染,我們不在瀏覽器端執行,而是繼續交給nodejs。瀏覽器端通過ajax把次屏html片段拉取回來,然后直接塞到body中。而且,除此之外,瀏覽器端沒有用戶交互會導致已有的DOM發生重繪,或者極少內容重繪,不需要動用到模版。
在這個情況下,瀏覽器端js更純粹的只關注事件處理。
我覺得這個又回到了第二種情況,只需要簡單把一些庫函數封裝一下,做成前后端共用即可。
第四種情況,因為徹底拋棄了瀏覽器渲染,整個情況就簡單多了,不需要考慮模版和很多邏輯js的前后端復用問題。