週末在網上衝浪, 看到個消息:NextJS 9.3 將靜態站點生成功能引入了NextJS平臺。
html
靜態站點生成
, 也就是所謂的 SSG : Static Site Generation
。react
喝了口水,順便回憶了下如今的幾種渲染模式:web
SSR
(Server Side Rendering)SSG
(Static Site Generation)SSR With hydration
CSR with Pre-rendering
CSR
(Client Side Rendering)Trisomorphic Rendering
都不是什麼新鮮玩意, 就總結複習一下, 順便分享給你們, 但願能給各位帶來一些啓發。瀏覽器
SSR, 服務端渲染。緩存
服務器呈現響應於導航爲服務器上的頁面生成完整的HTML。這樣能夠避免在客戶端進行數據獲取和模板化的其餘往返過程,由於它是在瀏覽器得到響應以前進行處理的。服務器
服務器渲染一般會產生快速的 First Paint (FP)和 First Contentful Paint (FCP)。網絡
在服務器上運行頁面邏輯和呈現能夠避免向客戶端發送大量JavaScript,這有助於實現快速的交互時間 (TTI)。ide
這是有道理的,由於使用服務器渲染,實際上只是將文本和連接發送到用戶的瀏覽器。工具
這種方法能夠在很大範圍的設備和網絡條件下很好地工做,而且能夠帶來有趣的瀏覽器優化,例如流文檔解析。post
流程:
瀏覽器 --> 服務器 --> 服務器執行渲染 --> index.html(實時渲染的內容)) --> Render --> bundle.js + images --> Render
window
或者 document
。SSG:靜態網站生成。
靜態網站生成相似於服務器端渲染,不一樣之處在於您在構建時而不是在請求時渲染頁面。
與服務器渲染不一樣,因爲沒必要動態生成頁面的HTML,所以它還能夠實現始終如一的快速到第一字節的時間。
一般,靜態呈現意味着提早爲每一個URL生成單獨的HTML文件。
藉助預先生成的HTML響應,能夠將靜態渲染器部署到多個CDN,以利用邊緣緩存的優點。
window
或者 document
。hydration, 直譯爲水合
。
讓人一臉懵逼。
簡單點講, 將功能放回到已經在服務器端中呈現的HTML中的整個過程,稱爲水合。
換句話說就是,對曾經渲染過的HTML進行從新渲染的過程稱爲水合。
此方法試圖經過同時進行客戶端渲染和服務器渲染,達到一種平衡。
導航請求(例如整頁加載或從新加載)由服務器處理,該服務器將應用程序呈現爲HTML,而後將JavaScript和用於呈現的數據嵌入到生成的文檔中。
理想狀態下,就能夠像服務器渲染同樣實現快速的First Contentful Paint,而後經過使用稱爲(re)hydration的技術在客戶端上再次渲染來修補
。
這是一個新穎的解決方案,可是它也可能具備一些至關大的性能缺陷。
帶水合的SSR的主要缺點是:
即便改進了First Paint
,它也可能對可交互時間
產生重大負面影響。
SSR的頁面一般看起來具備欺騙性,而且具備交互性,可是在執行客戶端JS並附加事件處理程序以前,實際上沒法響應輸入
。
在移動設備上可能要花費幾秒鐘甚至幾分鐘。
原理示意:
與JS致使的延遲互動相比,這個模型形成的問題可能會更加嚴重:
服務器響應導航請求返回了應用程序UI的數據描述。同時,但它還返回了用於組成該UI的源數據以及該UI的實現的完整腳本,該腳本隨後在客戶端啓動。
僅在bundle.js完成加載和執行後,該UI纔會變爲可交互。
舉個例子:
藍色部分包含了初始的3個checkbox, 以及須要加載的bundle.js,
一開始, 你會當即看到UI, 等bundle加載並執行完成以後, 頁面纔會更新, 進入可交互狀態。
從真實網站中收集的效果指標代表, 使用SSR水合模式效果並很差,強烈建議不要使用它。
緣由歸結爲用戶體驗:最終很容易使用戶陷入怪異的山谷
。
Pre-render
原理是: 在構建階段就將html頁面渲染完畢,不會進行二次渲染。
也就是說,當初打包時頁面是怎麼樣,那麼預渲染就是什麼樣。
等到JS下載並完成執行,若是頁面上有數據更新,那麼頁面會再次渲染。這時會形成一種數據延遲的錯覺。
Pre-render
利用 Chrome
官方出品的 Puppeteer
工具,對頁面進行爬取。
它提供了一系列的 API, 能夠在無 UI 的狀況下調用 Chrome
的功能, 適用於爬蟲、自動化處理等各類場景。
它很強大,因此很簡單就能將運行時的 HTML 打包到文件中。
原理是: 在 Webpack
構建階段的最後,在本地啓動一個 Puppeteer
的服務,訪問配置了預渲染的路由,而後將 Puppeteer
中渲染的頁面輸出到 HTML
文件中,並創建路由對應的目錄。
以此, 達到預渲染的目的。
流程:瀏覽器 --> 服務器 --> index.html(預渲染的內容) --> Render --> bundle.js + images --> Render
CSR, 顧名思義, 客戶端渲染。
客戶端渲染,意味着: 直接使用JavaScript在瀏覽器中渲染頁面
。
全部邏輯,數據獲取,模板和路由均在客戶端而不是服務器上處理
。
CSR 示意圖:
流程:瀏覽器 --> 服務器 --> index.html(白屏) --> bundle.js --> images --> Render
若是你能夠結合Service-Worker
, 則三態渲染
模式也可能派上用場。
在三態渲染模型中,可使用服務器流式渲染進行初始導航,而後讓service worker 在 html加載完成後,繼續進行導航html的渲染。
這樣可使緩存的組件和模板保持最新狀態,並啓用SPA樣式的導航,以在同一會話中呈現新視圖。
若是能夠在服務器,客戶端頁面和service worker之間共享
相同的模板和路由代碼時,這種方法十分有效。
三態渲染模型:
服務器渲染會爲每一個URL按需生成HTML,比僅提供靜態渲染內容要慢。
同時,也有一些優化空間: 服務器渲染+ HTML緩存能夠大大減小服務器渲染時間。
服務器渲染的優點在於:與靜態渲染相比,它可以提取更多"實時"數據並響應更完整的請求集。
從 SSR -> CSR, 以及中間不一樣的渲染模式, 都在圖裏:
本文中介紹的6種渲染模式,至於如何選擇, 這裏也給出一些不成熟的建議:
對操做需求比較多
的項目,好比一些管理後臺系統,建議使用 CSR。由於只有在執行完bundle以後, 頁面才能交互,單純能看到元素, 卻不能交互, 意義不大, 並且SSR 會帶來額外的開發和維護成本。無數據
,或者是純靜態
頁面,建議使用pre-render。 由於這是一種經過預覽打包的方式構建頁面,也不會增長服務器負擔。SSR
。好了,天都黑了,大概就是這麼多。
才疏學淺, 若有錯誤, 歡迎留言指正。
週末在研究 Reciol.js, 以爲挺有意思, 後面大概會出一篇分析的文章, 敬請期待哦。