最近在學習 React 的服務端渲染,因而使用 Express+React 寫了一個 Demo,用於對比和客戶端渲染的差別。github 地址css
先看一下效果吧:html
一、訪問 服務器端渲染 Online Demo前端
二、咱們能夠看到,首屏數據很快的就顯示出來了,但是頁面的進度條卻還在加載中(由於客戶端 js 很大)。node
三、當進度條加載完成後,頁面才能進行交互操做(切換路由,登陸等)。react
四、查看網頁源代碼,頁面內容都在頁面中。ios
效果不明顯的話,能夠打開控制檯,在 Network 欄 Disable cache,而後刷新。
經過此次簡單的訪問,咱們就能看出服務器端渲染的 2 大特色,首屏直出
,SEO 友好
。nginx
一、訪問 客戶端渲染 Online Demogit
二、咱們能夠看到,首屏至少等待了 6 秒才渲染出來,這對於通常的用戶,是難以容忍的。github
三、不過一旦渲染完成,頁面就當即可交互了(切換路由,登陸等)。redux
四、查看網頁源代碼,頁面只有一個空 div 容器,而沒有實際內容。
經過此次訪問,咱們就能看出客戶端渲染的特色,首屏加載時間長
,SEO 不友好
,但可見便可操做
。
其實咱們在訪問客戶端渲染的頁面時,請求到的只是一個 html 空殼,裏面引入了一個 js 文件,全部的內容都是經過 js 進行插入的,相似於這樣:
<!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> <div id="root"></div> <script src="bundle.js"></script> </body> </html>
正是由於頁面是由 js 渲染出來的,因此會帶來以下幾個問題:
一、頁面要等待 js 加載,並執行完成了才能展現,在這期間頁面展示的是白屏
。
二、爬蟲不能識別 js 內容,因此抓取不到任何數據,不利於 SEO 優化
。
爲了解決這 2 個問題,咱們可使用服務器端渲染。
以前說道,客戶端渲染的頁面,請求到的是一個 html 空殼,而後經過 js 去渲染頁面。那若是請求到的直接是一個渲染好的頁面,是否是就能夠解決這 2 個問題了呢?
沒錯,服務器端渲染就是這個原理。
一、服務器端使用 renderToString 直接渲染出包含頁面信息的靜態 html
。
二、客戶端根據渲染出的靜態 html 進行二次渲染
,作一些綁定事件等操做。
服務器端沒有 DOM,Window 等概念,因此只能渲染出字符串,不能進行事件綁定,樣式渲染等。只有第一次訪問頁面時才使用服務器端渲染,以後會被客戶端渲染接管。
接下來咱們一塊兒來寫一個 React 服務器端渲染 Demo。
這裏使用 react-router 對先後端代碼進行同構。
一、客戶端
使用 react-router-dom 下的 BrowserRouter
進行前端路由控制。
二、服務器端
使用 react-router-dom 下的 StaticRouter
進行靜態路由控制,具體操做以下:
使用 StaticRouter 中經過 context 能夠和前端頁面通訊,傳參。
在 React 中,咱們經常使用 redux 來存儲數據,管理狀態。
一、客戶端
使用 redux 進行狀態管理,使用 react-redux 提供的 Provider 爲組件注入 store。
二、服務器端
和客戶端同樣,但每一次接收到請求需產生一個新的 store,避免多個用戶操做同一個 store。
一、客戶端
使用 axios 在 componentDidMount 中請求數據。
二、服務器端
一樣使用 axios 去請求數據,可是服務器端不會觸發 componentDidMount 生命週期。咱們能夠在後端匹配到路由的時候,進行數據請求,並把數據存入 redux 中的 store,而後渲染出包含數據的 html 頁面,爲了不客戶端二次請求,服務器端向 window 中注入 REDUX_STORE 數據,客戶端直接使用此數據做爲客戶端 redux 的初始數據,以避免發生數據抖動。
具體操做以下:
一、客戶端
使用 css-loader,style-loader 打包編寫好的 css 代碼並插入到頁面中。
二、服務器端
因爲 style-loader 會插入到頁面,而服務器端並無 document 等概念,因此這裏使用 isomorphic-style-loader 打包 css 代碼。
SEO 主要是針對搜索引擎進行優化,爲了提升網站在搜索引擎中的天然排名,但搜索引擎只能爬取落地頁內容(查看源代碼時可以看到的內容),而不能爬取 js 內容,咱們能夠在服務器端作優化。
常規的 SEO 主要是優化:文字
,連接
,多媒體
因爲網頁上的文字,連接,圖片等信息都是產品設計好的,技術層面不能實現優化。咱們須要作的就是優化頁面的 title,description 等,讓爬蟲爬到頁面後可以展現的更加友好。
這裏藉助於 react-helmet 庫,在服務期端進行 title,meta 等信息注入。
如今,咱們成功地經過服務器端渲染解決了首次加載白屏時間
和 SEO 優化
。但也帶來了一些問題:
以上兩個問題歸根結底仍是錢的問題。服務器壓力大,能夠經過買更多的服務器來解決。可維護性增大,能夠招募更多人來維護。可是對於小型團隊來講,增長服務器,招募更多維護人員,都會額外增長的支出,因此在選擇服務器端渲染時,要權衡好利弊。
若是隻是想優化 SEO,不妨使用預渲染來實現,推薦使用 prerender 庫來實現。
prerender 庫的原理:先請求客戶端渲染的頁面,把客戶端渲染完成以後的結果,拿給爬蟲看
,這樣爬蟲獲取到的頁面就是已經渲染好的頁面。prerender 庫在使用時會開啓一個服務,經過傳遞 url 來解析客戶端渲染頁面,這就須要咱們對服務器端架構進行調整。
一、 nginx 判斷訪問類型
2.一、 用戶訪問 :直接走客戶端渲染2.二、 爬蟲訪問 :走預渲染
經過這個 Demo,讓我加深了對服務器端的理解,若有錯誤,麻煩多多指正,謝謝你們!
若是以爲有用得話給個 ⭐ 吧。react-ssr-demo