# Progressive Hydration 與 Streaming Server-Side Rendering ## 1. What is Hydration 儘管 Server-Side Rendering 已經有效改善 First Content Paint 但是不一定能提高好的 **Time To Interactive** ![](https://i.imgur.com/0i6oFVG.png) 網站看似好了,但實際上「Buy Now」其實還沒辦法跟 User 互動(Interactive) 原因:因為 JavaScript 還沒好 -> 還沒被載入 or 還沒被處理 ### 1.1 CSR ![https://web.dev/rendering-on-the-web/](https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&w=845) [reference](https://web.dev/rendering-on-the-web/) ![https://blog.saeloun.com/2021/12/16/hydration.html](https://d33wubrfki0l68.cloudfront.net/ae669b99cf5bbc70719de09b0aef758af7739d5e/7623d/images/useid/client_side_rendering.png) [reference](https://blog.saeloun.com/2021/12/16/hydration.html) ### 1.2 SSR ![https://web.dev/rendering-on-the-web/](https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&w=845) [reference](https://web.dev/rendering-on-the-web/) ![https://blog.saeloun.com/2021/12/16/hydration.html](https://d33wubrfki0l68.cloudfront.net/e6ad06d55ad27ac78bc0165b02fddb425e5d21d7/7c69b/images/useid/server_side_rendering.png) [reference](https://blog.saeloun.com/2021/12/16/hydration.html) ### 1.3 (Re)hydration 與恐怖谷(Uncanny valley) ```jsx= // App.js const App = (props) =>( <button onClick={()=>alert(`Hi ${props.name}`)}>{props.name}</button> ) // index.js // CSR ReactDOM.render(<App name="Ken"/>, document.getElementById('root')); // SSR ReactDOM.hydrate(<App name="Ken"/>, document.getElementById('root')); // server.js res.send(ReactDOMServer.renderToString(<App name="Ken" />) ``` > hydrate() is the same as render() but is used to hydrate a container whose HTML contents were rendered by ReactDOMServer. React will attempt to attach event listeners to the existing markup. [reference](https://blog.saeloun.com/2021/12/16/hydration.html) #### hydration: 把 eventListener, handler 加到既有的 HTML Markup 上 hydrate 完成後,用戶才能跟網頁互動 ![](https://i.imgur.com/rKvSouA.png) ![](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Mori_Uncanny_Valley_zh-tw.svg/1024px-Mori_Uncanny_Valley_zh-tw.svg.png) [reference](https://zh.m.wikipedia.org/zh-tw/%E6%81%90%E6%80%96%E8%B0%B7%E7%90%86%E8%AE%BA) ![](https://1.bp.blogspot.com/-eFF7IVzcxww/U1_yV1eFRwI/AAAAAAAADik/gExcJ7FNVtY/s1600/uncanny-valley.jpg) [reference](https://www.therobotreport.com/our-relationship-with-the-uncanny-valley/) ![https://www.ranker.com/list/creepy-uncanny-valley-pictures/ashley-reign](https://imgix.ranker.com/user_node_img/50061/1001216142/original/1-photo-u1?auto=format&q=60&fit=crop&fm=pjpg&dpr=2&w=375) ![https://www.ranker.com/list/creepy-uncanny-valley-pictures/ashley-reign](https://imgix.ranker.com/user_node_img/50061/1001216145/original/1-photo-u1?auto=format&q=60&fit=crop&fm=pjpg&dpr=2&w=375) ### 有好感 -> 厭惡 -> 有好感 #### Ken 的解釋:有點太像,又有點不符合期待 -> 厭惡、排斥 ### 1.4 hydration 的問題 1. 雖然可以很快看到畫面,但延後了使用者可以開始互動的時機 > (可能比使用者雖然晚看到、但能立即使用的體驗更差) 2. 高層次上的重複(見下圖) ![https://web.dev/rendering-on-the-web/](https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&w=845) ### 1.5 解法 Progressive rehydration Streaming server rendering and etc... ## 2.Progressive Hydration ![](https://i.imgur.com/g1vV4CW.png) ![](https://i.imgur.com/C7FZZWs.png) ### 達成要素須滿足 1. 所有的 component 都能使用 SSR 2. 代碼分割(code splitting)可以下至一個 component 或更小的 chunk 3. 這些 chunk 在 client side 能依照開發者的定義的順序進行 Hydration 4. 不阻斷已 hydrated 完成的 user input 5. 當延遲的 Hydration 進行時,可以有某些指標 (loading) 來使用 #### React Concurrent mode 會直指、盡力實作滿足以上目標 1. lazy Suspense (declarative loading 指標與延遲載入) 3. Server Components (React Server Components 是透過網路請求來重新 render 他負責的子 Tree,可以結合其他既有的 Client Components 來保留 State。)[reference](https://chentsulin.medium.com/react-%E6%96%B0%E6%A6%82%E5%BF%B5-server-components-d632f9a18463) 但如各位所知,Concurrent 還在逐漸朝fully Production Ready 的路上 業界目前有 Partial hydration 可以使用,但 Partial hydration 也面臨一些實作、實務上的困難。 ![](https://i.imgur.com/Hr8IimD.png) ### Pros and Cons 1. 提倡、有助於代碼分割(code splitting) 2. 可根據需求、使用頻率決定載入 3. 有效降低 bundle size ,加速 FCP, TTI 的完成時間 ---- ## 3. Streaming Server-Side Rendering ### 3.1 What is streaming? ![](https://imgs.developpaper.com/imgs/752404867-5e8d3a4526787_articlex.png) [reference](https://developpaper.com/how-to-use-grpc-stream-effectively-in-nodejs/) ![](https://i.imgur.com/iR0FTzK.png) [reference](https://ithelp.ithome.com.tw/articles/10221119) #### 概念:同步拿取資料,但一次不要拿太大,分成小塊小塊的拿 ### 3.2 與 React 的關係是...? #### V16 版後,React 官方提供了 Stream 對應的 API ```jsx= ReactDOMServer.renderToNodeStream(element) // (Deprecated) ReactDOMServer.renderToStaticNodeStream(element) ``` `ReactDOMServer.renderToNodeStream(element)`(Deprecated) 效果等同於 `ReactDOMServer.renderToString(element)` 不過 output 會是 Node.js readablestream 的格式 讓 client 端透過 stream 不斷接收到小小 chunk 然後呼叫 hydrate ---- `ReactDOMServer.renderToStaticNodeStream(element)` 則對應於 `ReactDOMServer.renderToStaticMarkup(element)` 產出 HTML 的 stream 格式,可以用在非互動的靜態頁面上。 ![](https://i.imgur.com/7QU6rQN.png) ![](https://i.imgur.com/932126G.png) ### Pros and Cons 1. 提升效能 2. Backpressure 的處理,可能使網站製作更具挑戰 3. stream 格式也被瀏覽器爬蟲所認可,可支持 SEO ![](https://i.imgur.com/AMbSoUP.png) ## 4. Recap #### 兩者的目標:都是希望加速 TTI 改善使用者體驗 #### 兩者的差別:一次「要」一點、一次 “讀”一點 (---vs---) 一次 “讀” 一點、一次 “讀” 一點 ![](https://i.imgur.com/rKvSouA.png) ![](https://i.imgur.com/C7FZZWs.png) ![](https://i.imgur.com/932126G.png) ## 5. Reference [web.dev: Rendering on the Web](https://web.dev/rendering-on-the-web/) [Understanding Hydration in React applications(SSR)](https://blog.saeloun.com/2021/12/16/hydration.html) [Hydration: Server-side rendering + Client-side rendering (下)](https://blog.timtnlee.me/post/development/ssr-hydrate-2) [Joy 的 hackmd 筆記](https://hackmd.io/aCjbg0QtQrqCYoe_wugfBw) [Emma 的 hackmd 筆記](https://hackmd.io/XSZKpM2-SwO-jwFhcVXmsw?view) #### 導讀章節 1. [Patterns.Dev - Progressive Hydration](https://www.patterns.dev/posts/progressive-hydration/) 2. [Patterns.Dev - Streaming Server-Side Rendering](https://www.patterns.dev/posts/ssr/)