Skip to content

Instantly share code, notes, and snippets.

@coodoo
Created September 3, 2015 00:16
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save coodoo/59891964b06a603e2dc8 to your computer and use it in GitHub Desktop.
Save coodoo/59891964b06a603e2dc8 to your computer and use it in GitHub Desktop.
react isomorphic 原理
- 我想要挑戰isomorphic,但目前好像比較少redux配isomorphic又配上webpack的方案
- 這個範例可看,最近全部改寫過
- https://github.com/coodoo/react-redux-isomorphic-example
- 注意下面幾點
- js/bootClient.js 與 js/bootServer.js
- bootServer.js 負責做 server-render
- 它是一個 express middleware
- 負責參與 server routing 並處理路徑與頁面
- 真正的關鍵在於 react-router 內部可處理非同步的資料下載
// 這句就是 react-router 的指令,它會觸發 react-router 運行
// 並等它內部抓完資料後,才繪出畫面
Router.run( childRoutes, location, (error, initialState, transition)
- bootClient.js 是純 client 端運作
- 通常有 server-render 時,server 會將已撈好的資料打印在 html 頁面內一起返還當 browser
- #24 行就是在還原這些 server 預先送來的資料,以省去重新撈資料手續
- routes/routing.js
- 這裏負責宣告所有 react-router 要處理的 route
- 特別注意每個 childRoutes 內都有 onEnter handler
- 它會在每個頁面顯示前,先去撈回所需資料,因此畫面上不會先空白一片然後突然有東西跑出來
- 這個 onEnter 也是 server-render 時依賴的重要功能
- 不然 server 上可能沒等到資料取回,就先繪出畫面並返還,client 就會拿到一張空白頁面
- isomorphic到底怎麼做到的?
- 基本原理是把 server 當 browser 用,一樣生成頁面
- 例如你請求 foo.com/users/2
- server 知道即將要顯示 users 畫面(對應到 react 就是一個 <User> 元件)
- 它會先去 db 撈回 uid:2 的用戶資料
- 然後餵給 react 使用
- 最後跑 ReactDOM.renderToString 生出一份完整的 html 字串
- 再將這字串返還給 browser,用戶就會看到最終成品了
# 上述過程中最麻煩的地方有兩點
1. 於 server 要先撈回資料,才能傳入 react 內使用
- 最常見的目題是,撈資料這種操作通常是 async 的
- 因此必需等待操作完成才能進行下一步
- 以往很多 isomorphic 實作都在這裏遇到麻煩,沒等資料撈完就跑下一步
- 這會道致 server 最終生成一個空白頁面(因為資料沒撈回來自然無法顯示)
- 但現在有 react-router 的 onEnter callback 可用,因此能輕易的進行 async 操作並等它完成再跑下一步
2. 在 server 上將 react 元件轉換為 html 字串
- 這裏要先有 VDOM → DOM 的概念
- 平常寫的 <MyBox>some text</MyBox> 是 react VDOM
- 這個 VDOM 在 browser 裏最終是轉換為 <div class="myBox">some text</div> 這種 DOM
- 這時我們將 browser 稱為是 react 的 drawing backend (VDOM 最終轉換為 Browser DOM)
- 同樣的,server 也可以是 drawing backend
- 差別只是 server 上顯然沒有 DOM,那 VDOM 要轉換成什麼?
- 答案是 VDOM → String 就好
- 因為 server 的任務最終就是返還用戶請求的 html 頁面,它的內容本來就是純字串的
- 因此只要有個方法將 VDOM 轉換為 html 字串,將來用戶的 browser 就能處理
- 而這個方法就是 ReactDOM.renderToString(),它之前是叫 React.renderToString()
- client拿到完整的website以後,要怎麼知道react怎麼工作?
- client 拿到 server 返還的 html 頁面後,跑一樣的處理流程將頁面顯示出來
- 這包含頁面上的 react 元件系統也會啟動
- 差別在於原本 react 元件啟動後,要負責生成頁面上的 DOM element
- 但在 server-render 的情況下,這些 DOM element 已在 server 上生成好
- 因此 react 會判斷此事已完成,就不會再做重工
- 但它仍然會針對這些已生成好的 DOM element 掛上正確的 event listener
- 我知道有一個React轉成html string的功能,但我記得html上面會掛不少event listener,有點不懂他怎麼運作的
- 注意前面提過的,有一種 rendering backend 叫 server
- 它會用精簡的方式生成 html string,而忽略 DOM 專屬的事,例如 event listener
- webpack的即時修改、渲染是怎麼做到的
- 這功能叫 Hot Module Reload(HMR)
- webpack 是以 module 為單位來運行
- 平常寫 import foo from 'bar' 這個 bar 就是一個 module
- HMR 的運作原理是
- 網頁上有個 websocket 連回 webpack-dev-server
- webpack-dev-server 會監控檔案是否出現變化
- 有變化就立即重新編譯
- 然後透過 socket 通知網頁哪個 module 變動了
- 網頁可立即取得新版的 module 內容
- 然後原地置換掉舊版的 module
- 如此即可讓新版 module 立即顯示(渲染)在畫面上
- 背後原理是 webpack 在打包 module 時有在每支 module 內偷插入 scripts 來負責做些這事
- 所以關鍵就是
- websocket 持續通知網頁有變動
- module 內被偷插 script 負責更新 module 內容
@billy3321
Copy link

但現在有 react-router 的 onEnter callback 可用,因此能輕易的進行 async 操作並等它完成再跑下一步

  • 這邊有個小問題,如果是這樣的話,可能發生的問題會變成:

因為server要抓資料、要執行React轉成字串,返還html的時候就會更久。我記得之前在推API搭頁面的時候,
有一個說法是,這可以減輕部分Server負擔,但因為現在這個工作又回到Server上,是否Server的效能就會加
重?未來是不是就得做出cache的功能,加速這個過程呢?

@coodoo
Copy link
Author

coodoo commented Sep 3, 2015

server 負責抓資料、渲染頁面、返還 html 這三件事,其實在 rails 也得做不是嗎?以往會怎麼解決加速這問題,現在可依舊進行呀,加 cache 是個方式,前面掛 CDN 也是一種。

@billy3321
Copy link

剛剛找資料發現這篇解釋 HMR 解釋的很清楚,貼上來存參~

http://stackoverflow.com/questions/24581873/what-exactly-is-hot-module-replacement-in-webpack

@billy3321
Copy link

@amowu
Copy link

amowu commented Sep 22, 2015

您好,請問所以 isomorphic 其實已經不算是單頁面應用 (SPA) 了嗎?謝謝!

@jackypan1989
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment