SSR(Server-Side Rendering)並非什麼新奇的概念,先後端分層以前很長的一段時間裏都是以服務端渲染爲主(JSP、PHP),在服務端生成完整的 HTML 頁面
(摘自前端渲染模式的探索)php
也就是說,歷經 SSR 到 CSR 的大變革以後,現在又從 CSR 出發去探索 SSR 的可能性……彷佛兜兜轉轉又回到了起點,在這之間發生了什麼?現在的 SSR 與當年的 JSP、PHP 又有什麼區別?css
回到論壇、博客、聊天室仍舊火熱的年代,行業最佳實踐是基於 JSP、PHP、ASP/ASP.NET 的動態網站html
以 PHP 爲例:前端
<?php if ( count( $_POST ) ): ?> <?php include WTG_INCPATH . '/wechat_item_template.php' ?> <div style="..."> <div id="wechat-post" class="wechat-post" style="..."> <div class="item" id="item-list"> <?php $order = 1; foreach ( $_POST['posts'] as $wechat_item_id ) { echo generate_item_list( $wechat_item_id, $order ); $order++; } ?> </div> <?php $order = 1; foreach ( $_POST['posts'] as $wechat_item_id ) { echo generate_item_html( $wechat_item_id, $order ); $order++; } ?> <fieldset style="..."> <section style="..."> <p style="...">若是心中仍有疑問,請查看原文並留下評論噢。(<span style="font-size:0.8em; font-weight:600">特別要緊的問題,能夠直接微信聯繫 ayqywx</span> )</p> </section> </fieldset> </div> <script> function refineStyle () { var post = document.getElementById('wechat-post'); // ul ol li var uls = post.getElementsByTagName('ul'); for (var i = uls.length - 1; i >= 0; i--) { uls[i].style.cssText = 'padding: 0; margin-left: 1.8em; margin-bottom: 1em; margin-top: -1em; list-style-type: disc;'; uls[i].removeAttribute('class'); }; } document.addEventListener('DOMContentLoaded', function() { refineStyle(); }); </script> </div> <?php endif ?>
(摘自ayqy/wechat_subscribers,一款用來自動生成微信公衆平臺圖文消息的 WordPress 插件)nginx
這一時期網頁內容徹底由服務端渲染,客戶端(瀏覽器)接收到的是融合了服務數據的 HTML,以及少許內聯的(表單)交互邏輯和樣式規則,支撐着早期大量動態網站的正是這種純 SSR 模式git
但隨着技術實踐的深刻,這種模式逐漸暴露出了一些問題:github
面對這些問題,兩個思路逐漸變得清晰起來,動靜分離與先後端分層,前者解決性能和機器成本的問題,後者解決開發/維護的問題後端
爲了充分利用 Web 服務器的靜態資源處理優點,同時減輕應用服務器的負擔,將資源分爲兩類:瀏覽器
兩種資源分開部署,把靜態資源部署至 Web 服務器或 CDN,應用服務器只部署動態資源。如此這般,靜態資源響應更快了(瀏覽器緩存、CDN 加速),應用服務器壓力更小了,皆大歡喜緩存
然而,視圖邏輯卻被咱們漏掉了,HTML 算做靜態資源仍是動態資源?
先後端分層就是爲了回答這個問題
視圖邏輯的特殊之處在於:
也就是說,HTML 視圖結構的建立和維護工做,能夠由服務端完成,也能夠在客戶端完成,都依賴服務數據。但與服務端相比,客戶端環境有一些優點:
所以,視圖邏輯劃分到了客戶端(即 CSR),以數據接口爲界,分紅先後端兩層:
自此,先後端各司其職,前端致力於用戶體驗的提高,後端專一業務領域,並行迭代,(不涉及接口變化時)互不影響
先後端分層以後,進入了 CSR 的黃金時代,探索出了功能插件、UI 庫、框架、組件等多種代碼複用方案,最終造成了繁榮的組件生態
組件化的開發方式之下,純 CSR 模式日益盛行:
<!DOCTYPE html> <html> <head> <title>My Awesome Web App</title> <meta charset="utf-8"> </head> <body> <div id="app"></div> <script src="bundle.js"></script> </body> </html>
這種模式下,幾乎全部的頁面內容都由客戶端動態渲染而來,包括建立視圖、請求數據、融合數據與模版、交互功能在內的全部工做,都交由一套數據驅動的組件渲染機制來全權管理,而沒必要再關注組件之下的 DOM 結構維護等工做,有效提升了前端的生產效率。但一些問題也隨之而來:
這些問題的根源在於目前的組件渲染流程是同步阻塞的,對首屏性能提出了挑戰:
CSR 雖然利用了用戶設備的計算資源,但同時也受其性能、網絡環境等不可控因素的制約。因而,你們又從新將目光彙集到了 SSR
SSR 模式下,首屏內容在服務端生成,客戶端收到響應 HTML 後可以直接呈現內容,而無需等到組件樹渲染完畢
雖然核心思想都是在服務端完成頁面渲染工做,但現在的 SSR 與先前大不相同,體如今:
也就是說,現在的 SSR 是爲了解決前端層的問題,結合 CSR 優化內容加載體驗,是在 CSR 多年積澱之上的擴展,與現有的前端技術生態保持着良好的相容性。而當年的 SSR 更多地是爲了實現功能,解決溫飽問題
再看當年 SSR 面臨的幾個問題:
引入 SSR 以後這些問題捲土重來,但這些年的技術發展爲解決這些問題提供了新的思路:
其中,Static Generation(也叫 SSG,Static Site Generation)是指在編譯時生成靜態 HTML(可部署至 CDN),避免實時渲染的性能開銷:
Static Generation (Recommended): The HTML is generated at build time and will be reused on each request.
但並不是全部頁面都能在編譯時靜態生成,一種可行的實踐方案是將 SSR 與 Static Generation 結合起來,只對內容依賴個性化數據、或者頻繁更新的頁面走 SSR,其他場景都走 Static Generation:
You should ask yourself: "Can I pre-render this page ahead of a user's request?" If the answer is yes, then you should choose Static Generation.
至此,沉寂多年的 SSR 又煥發出了新的活力
關注「前端向後」微信公衆號,你將收穫一系列「用心原創」的高質量技術文章,主題包括但不限於前端、Node.js以及服務端技術
本文首發於 ayqy.net ,原文連接:http://www.ayqy.net/blog/dife...