服務(wù)端渲染之-ssr同構(gòu)

什么是同構(gòu)

一份代碼,先通過服務(wù)端渲染(server-side rendering,ssr),生成html字符串以及初始化數(shù)據(jù),客戶端拿到后,通過對(duì)html的dom進(jìn)行patch和事件綁定對(duì)dom進(jìn)行客戶端激活(client-side hydration,csh),這個(gè)整體的過程叫同構(gòu)渲染。

同構(gòu)產(chǎn)生的背景 / 同構(gòu)能夠解決單純客戶端渲染的哪些痛點(diǎn)?

1.客戶端渲染帶來的的首屏白屏?xí)r間過長(zhǎng):

? ? ? ? ?在 SPA 模式下,所有的數(shù)據(jù)請(qǐng)求和 Dom 渲染都在瀏覽器端完成,所以當(dāng)我們第一次訪問頁(yè)面的時(shí)候很可能會(huì)存在“白屏”等待,而服務(wù)端渲染所有數(shù)據(jù)請(qǐng)求和 html內(nèi)容已在服務(wù)端處理完成,瀏覽器收到的是完整的 html 內(nèi)容,可以更快的看到渲染內(nèi)容。

? ? ? ? ?2. 客戶端渲染不利于SEO:

? ? ? ? ?由于現(xiàn)階段大多搜索引擎采用的爬蟲算法是直接抓取頁(yè)面代碼分析,而SPA應(yīng)用只有一個(gè)入口文件而沒實(shí)質(zhì)內(nèi)容,SEO性能差。

適用的場(chǎng)景?

? ? ? ? ? 1.特別依賴搜索引擎流量的項(xiàng)目;

2.對(duì)首屏?xí)r間有特殊要求;

現(xiàn)有的的開源框架?

next.js、react server、Beidou(北斗)?、

核心原理及架構(gòu)流程圖?

? ? ? ? ? 借助虛擬DOM的特性,將一份代碼在服務(wù)端和客戶端各執(zhí)行一次:

1、服務(wù)端使用?react-dom包提供的 server端渲染api: renderToString (常用)或?renderToStaticMarkup直接渲染出包含頁(yè)面信息的靜態(tài) html字符串。

? ? ? ? ? 2、客戶端根據(jù)渲染出的靜態(tài) html 進(jìn)行二次渲染,做一些綁定事件等交互操作。

同構(gòu)的缺點(diǎn)?? ??

? ? ? ? ? 1.同構(gòu)會(huì)增加服務(wù)器的負(fù)載,對(duì)此一般推薦對(duì)于首屏和個(gè)別頁(yè)面進(jìn)行SSR服務(wù)端的渲染,此外仍保持應(yīng)用為客戶端SPA,充分利用瀏覽器特點(diǎn),達(dá)到最優(yōu)性能。

? ? ? ? ? 2.使原本簡(jiǎn)單的 React 項(xiàng)目變得非常復(fù)雜,項(xiàng)目的可維護(hù)性會(huì)降低,代碼問題的追溯也會(huì)變得困難。所以,使用 SSR 在解決問題的同時(shí),也會(huì)帶來非常多的副作用,有的時(shí)候,這些副作用的傷害比起 SSR 技術(shù)帶來的優(yōu)勢(shì)要大的多。

關(guān)鍵點(diǎn)?

?1.雙端框架選擇:

? ? ? ? ? ?客戶端:react(v16+)

? ? ? ? ? ?服務(wù)器端:koa/express

2.環(huán)境區(qū)分

? ? ? ? ? ?同一套代碼在客戶端和服務(wù)端執(zhí)行兩次,但因?yàn)榄h(huán)境不同,有些對(duì)象是不自帶的,要加以區(qū)分避免出現(xiàn)問題。像前端特有的 Window 對(duì)象,Ajax 請(qǐng)求 在后端是無法使用上的,后端需要去掉這些前端特有的對(duì)象? ? ? ? ? ? 邏輯或使用對(duì)應(yīng)的后端方案,如后端可以使用 http.request 替代 Ajax 請(qǐng)求,所以需要進(jìn)行平臺(tái)區(qū)分,主要有以下幾種方式:

? ? ? ? ? 1. 代碼使用前后端通用的模塊,如 isomorphic-fetch

? ? ? ? ? 2. 前后端通過 webpack 配置 resolve.alias 對(duì)應(yīng)不同的文件

? ? ? ? ? 3. 使用 webpack.DefinePlugin 在構(gòu)建時(shí)添加一個(gè)平臺(tái)區(qū)分的值

??3.react服務(wù)端提供的渲染API

??React 之所以可以做到服務(wù)端渲染 就是因?yàn)閞eact-dom/server提供了服務(wù)端渲染的API。

renderToString 同步地把一個(gè)react 元素轉(zhuǎn)換成帶html字符串,遇到復(fù)雜頁(yè)面時(shí)用戶等待時(shí)間也不短。

renderToNodeStream把渲染結(jié)果以‘流’的形式返回給瀏覽器端,用戶體驗(yàn)更友好。

后續(xù)為了客戶端在渲染組件時(shí),最大限度地保留在服務(wù)端使用 renderToString 生成的內(nèi)容結(jié)構(gòu),ReactDom 相應(yīng)的在客戶端提供了一個(gè)新的 API:hydrate。

4.路由同構(gòu)

首先需要抽離出一份路由組件文件routes.js:

客戶端使用 react-router-dom 下的?BrowserRouter?進(jìn)行前端路由控制。

服務(wù)端使用 react-router-dom 下的?StaticRouter?進(jìn)行靜態(tài)路由控制。

使用 react-router-config 下的 matchRoutes 匹配后端路由,使用 renderRoutes 渲染匹配到的路由。

使用 react-router-dom/server 下的 renderToString 方法,渲染出 html 字符串,并返回給前端。

使用 StaticRouter 中通過 context 可以和前端頁(yè)面通信,傳參。

數(shù)據(jù)交互與狀態(tài)同步?

可以選用redux實(shí)現(xiàn)數(shù)據(jù)狀態(tài)的同步:在服務(wù)端通過組件的靜態(tài)API方法獲取接口數(shù)據(jù)后創(chuàng)建store,再通過 window.store= store 傳遞給前端;此時(shí)應(yīng)用中的所有頁(yè)面都可以共享使用store中的數(shù)據(jù),可以使用dispatch方法進(jìn)行交互。

雙端打包差異?

客戶端打包:

? ? ? ? ? 服務(wù)端打包:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容