markdownpad2 html渲染组件出错_「万字长文」一文吃透React SSR服务端同构渲染
寫在前面
前段時間一直在研究 react ssr技術,然后寫了一個完整的 ssr開發骨架。今天寫文,主要是把我的研究成果的精華內容整理落地,另外通過再次梳理希望發現更多優化的地方,也希望可以讓更多的人少踩一些坑,讓更多的人理解和掌握這個技術。
相信看過本文(前提是能對你的胃口,也能較好的消化吸收)你一定會對 react ssr服務端渲染技術有一個深入的理解,可以打造自己的腳手架,更可以用來改造自己的實際項目,當然這不僅限于 react ,其他框架都一樣,畢竟原理都是相似的。
為什么要服務端渲染(ssr)
至于為什么要服務端渲染,我相信大家都有所聞,而且每個人都能說出幾點來。
首屏等待
在 SPA 模式下,所有的數據請求和 Dom 渲染都在瀏覽器端完成,所以當我們第一次訪問頁面的時候很可能會存在“白屏”等待,而服務端渲染所有數據請求和 html內容已在服務端處理完成,瀏覽器收到的是完整的 html 內容,可以更快的看到渲染內容,在服務端完成數據請求肯定是要比在瀏覽器端效率要高的多。
沒考慮SEO的感受
有些網站的流量來源主要還是靠搜索引擎,所以網站的 SEO 還是很重要的,而 SPA 模式對搜索引擎不夠友好,要想徹底解決這個問題只能采用服務端直出。改變不了別人(搜索yinqing),只能改變自己。
SSR + SPA 體驗升級
只實現 SSR 其實沒啥意義,技術上沒有任何發展和進步,否則 SPA 技術就不會出現。
但是單純的 SPA又不夠完美,所以最好的方案就是這兩種體驗和技術的結合,第一次訪問頁面是服務端渲染,基于第一次訪問后續的交互就是 SPA 的效果和體驗,還不影響 SEO 效果,這就有點完美了。
單純實現 ssr 很簡單,畢竟這是傳統技術,也不分語言,隨便用 php 、jsp、asp、node 等都可以實現。
但是要實現兩種技術的結合,同時可以最大限度的重用代碼(同構),減少開發維護成本,那就需要采用 react 或者 vue 等前端框架相結合 node(ssr) 來實現。
本文主要說 ReactSSR技術 ,當然 vue 也一樣,只是技術棧不同而已。
核心原理
整體來說 react 服務端渲染原理不復雜,其中最核心的內容就是同構。
node server 接收客戶端請求,得到當前的 req url path,然后在已有的路由表內查找到對應的組件,拿到需要請求的數據,將數據作為 props 、 context或者 store 形式傳入組件,然后基于 react 內置的服務端渲染api renderToString()orrenderToNodeStream() 把組件渲染為 html字符串或者 stream流, 在把最終的 html 進行輸出前需要將數據注入到瀏覽器端(注水),server 輸出(response)后瀏覽器端可以得到數據(脫水),瀏覽器開始進行渲染和節點對比,然后執行組件的 componentDidMount 完成組件內事件綁定和一些交互,瀏覽器重用了服務端輸出的 html節點,整個流程結束。
技術點確實不少,但更多的是架構和工程層面的,需要把各個知識點進行鏈接和整合。
這里放一個架構圖
react ssr
從 ejs 開始
實現 ssr 很簡單,先看一個 node ejs的栗子。
// index.html react ssr //node ssr const ejs = require('ejs'); const http = require('http');http.createServer((req, res) => { if (req.url === '/') { res.writeHead(200, { 'Content-Type': 'text/html' }); // 渲染文件 index.ejs ejs.renderFile('./views/index.ejs', { title: 'react ssr', data: '首頁'}, (err, data) => { if (err ) { console.log(err); } else { res.end(data); } }) }}).listen(8080);jsx 到字符串
上面我們結合 ejs模板引擎 ,實現了一個服務端渲染的輸出,html 和 數據直接輸出到客戶端。
參考以上,我們結合 react組件 來實現服務端渲染直出,使用 jsx 來代替 ejs,之前是在 html 里使用 ejs 來綁定數據,現在改寫成使用 jsx 來綁定數據,使用 react 內置 api 來把組件渲染為 html 字符串,其他沒有差別。
為什么react 組件可以被轉換為 html字符串呢?
簡單的說我們寫的 jsx 看上去就像在寫 html(其實寫的是對象) 標簽,其實經過編譯后都會轉換成 React.createElement方法,最終會被轉換成一個對象(虛擬DOM),而且和平臺無關,有了這個對象,想轉換成什么那就看心情了。
const React = require('react');const { renderToString} = require( 'react-dom/server');const http = require('http');//組件class Index extends React.Component{ constructor(props){ super(props); } render(){ return{this.props.data.title}
}}//模擬數據的獲取const fetch = function () { return { title:'react ssr', data:[] }}//服務http.createServer((req, res) => { if (req.url === '/') { res.writeHead(200, { 'Content-Type': 'text/html' }); const data = fetch(); const html = renderToString(); res.end(html); }}).listen(8080);ps:以上代碼不能直接運行,需要結合babel 使用 @babel/preset-react 進行轉換
npx babel script.js --out-file script-compiled.js --presets=@babel/preset-react引出問題
在上面非常簡單的就是實現了 react ssr ,把 jsx作為模板引擎,不要小看上面的一小段代碼,他可以幫我們引出一系列的問題,這也是完整實現 react ssr 的基石。
- 雙端路由如何維護?
首先我們會發現我在 server 端定義了路由 '/',但是在 react SPA 模式下我們需要使用 react-router來定義路由。那是不是就需要維護兩套路由呢?
- 獲取數據的方法和邏輯寫在哪里?
發現數據獲取的 fetch 寫的獨立的方法,和組件沒有任何關聯,我們更希望的是每個路由都有自己的 fetch 方法。
- 服務端 html 節點無法重用
雖然組件在服務端得到了數據,也能渲染到瀏覽器內,但是當瀏覽器端進行組件渲染的時候直出的內容會一閃而過消失。
好了,問題有了,接下來我們就一步一步的來解決這些問題。
同構才是核心
react ssr 的核心就是同構,沒有同構的 ssr 是沒有意義的。
所謂同構就是采用一套代碼,構建雙端(server 和 client)邏輯,最大限度的重用代碼,不用維護兩套代碼。而傳統的服務端渲染是無法做到的,react 的出現打破了這個瓶頸,并且現在已經得到了比較廣泛的應用。
路由同構
雙端使用同一套路由規則, node server 通過 req url path 進行組件的查找,得到需要渲染的組件。
//組件和路由配置 ,供雙端使用 routes-config.js
class Detail extends React.Component{ render(){ return detail }}class Index extends React.Component { render() { return index }}const routes = [ { path: "/總結
以上是生活随笔為你收集整理的markdownpad2 html渲染组件出错_「万字长文」一文吃透React SSR服务端同构渲染的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# 解决串口接收数据不完整
- 下一篇: flink 写kafka_网易云音乐基于