什麼是ssr:server side render,服務端渲染php
不一樣於jsp,php等傳統服務端渲染(這種狀況下,先後端代碼是分開的,寫了兩份)html
目前的ssr是基於react vue等前端框架的同構渲染(即一份代碼,同時運行在server和client端),開發人員只關注業務實現便可前端
ssr的優缺點就不細說了,無非seo,首屏更快,學習成本變高,加大服務端資源開銷等vue
目前咱們項目都逐步採用ssr方案,基於nextjs重構,做爲開發人員,對原理比較好奇,研究一下node
大體的流程以下圖react
打包階段會將業務代碼打包兩次,一份部署在服務端,一份用於客戶端(可傳到cdn)git
而後啓動服務,基於用戶請求的路由決定render哪一個頁面,主要用到renderToStringapi將page組件轉化爲html標記github
最簡單的狀況,將html標記直接返回客戶端,渲染一個靜態頁面後端
但實際業務中,通常在服務端須要獲取數據,根據數據來生成html,這種狀況下,當在客戶端從新render時,如何保證數據一致呢,解決辦法是將服務端獲取到的數據以字符串的形式返回給客戶端,客戶端渲染的時候直接以該數據進行渲染,保證數據的一致性,進而保證了ui的一致性api
當在客戶端運行時,主要用hydrateapi將html標記與js代碼從新結合,以後就與服務端徹底不要緊了,能夠當spa的狀況處理
基於這個流程,簡單實現一個demo
服務端
客戶端
主要代碼實現:
// render頁面 async function render(Element) { // 獲取組件初始props,能夠在該方法內獲取數據 const props = await Element.getInitProps() const html = renderToString(<Element {...props} />) const __SSR_DATA__ = { props } return { html, __SSR_DATA__ } } router.get('/demo', async ctx => { // 將生成的標記和屬性都轉爲文本傳給客戶端 const { html, __SSR_DATA__ } = await render(Demo) ctx.body = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>ssr</title> </head> <body> <script> window.__SSR_DATA__ = ${JSON.stringify(__SSR_DATA__)} </script> <div id="root">${html}</div> <script src="http://localhost:9090/index.js"></script> </body> </html>` })
import { hydrate } from 'react-dom'; import Demo from './demo'; // 服務端將props數據掛載到window上,客戶端從新渲染時直接傳入該屬性 const { props } = window.__SSR_DATA__ // hydrate會根據html中已有的標記進行對比,決定是否要從新渲染dom hydrate( <Demo {...props} />, document.getElementById('root'), );
目前react ssr主要是用nextjs
nextjs實現原理與上面一致,增長了路由,緩存,打包,錯誤處理,頁面加載等一系列功能
生產中,除非很簡單,或者只爲了首屏,不考慮同構,能夠本身實現,正常狀況,直接使用nextjs便可
後續會記錄一下next源碼分析
待續...