什麼是 SSR?為什麼要 SSR?
SSR 是 Sever-side Render 的縮寫,意思是指「在 Server 端就產生(Render)出畫面」。目前大概有幾種產生畫面的時機點:
- Server Side Render: 在後端接收到 Request 即產生 HTML 畫面,需要新的資料則需要重新傳送 Request ,也會產生一個新的畫面。後端的 Framework 通常都會有一個 HTML Template 的機制就是在產生畫面的動作。
- Client Side Render: 在前端進行 Render,後端作為資料供應的 API 層。當需要新的資料時,前端傳送 Request 後只需要部份更新畫面就好。
- Isomorphic: 網站能夠同時考慮 SSR 與 CSR 兩種方式,之前有整理過關於 Isomorphic 的介紹。
最早期的網站都是 SSR 的方式進行,但每次的重新 Render 會造成後端的負擔提升也讓使用者的體驗變差。而後來的 React/Vue 之類的 Framework 則是基於 CSR 的方式讓使用者體驗,並達到了前後端分離的優點。但 CSR 還是伴隨著幾個問題:
- 有些 CSR 的網站會造成爬蟲取得的頁面不是那麼完整,造成 SEO 的問題
- 第一次載入畫面是等到前端載入後,會有一段時間的空白
因此,如果能夠兼具 CSR 與 SSR 的 Isomorphic ,成了一條新的解法。以下我們講的 SSR 都是 Isomorphic 同時兼具兩種方式的 SSR。
Next.js
「Next.js is a lightweight framework for static and server‑rendered applications.」
Next 是一個基於 React 的 SSR 解決方案,更多的細節可以參考官網。
開始第一個 Next.js 專案吧!
方法 ①: 手動安裝
根據官方的教學,可以透過 NPM 的方式手動安裝:
$ npm install --save next react react-dom
複製程式碼
接著再把 package.json 中執行的方式改成 NEXT:
{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}
複製程式碼
然後建立一個頁面在 /pages/index.js 檔案:
export default () => <div>Welcome to next.js!</div>
複製程式碼
最後,執行指令就會將專案跑在 3000 PORT:
npm run dev
複製程式碼
方法 ②: create-next-app
許多人開發 React 會搭配 create-react-app 的 scaffold 來跳過複雜的環境設定,Next.js 也有:
$ npm install -g create-next-app
$ create-next-app my-app
$ cd my-app/
$ yarn start
複製程式碼
來看一個簡單 Isomorphic 範例
增加一個新頁面
Next 是根據 /pages 目錄作為 Route 的分配,舉例來說 /pages 的 index 就會對應到 Root URL。我們先在 /pages 目錄下建立一個 hello.js 的檔案:
const Hello = (props) => (
<div>
<h1>Hello Next</h1>
</div>
)
export default Hello
複製程式碼
此時就會多了一個 Route 在 /hello 。
兩個頁面彼此連結
在 Next 中提供了 Link 的 Component 讓我們可以進行頁面間的 Client Side 換頁:
import Link from 'next/link'
const Hello = (props) => (
<div>
<Link href={`/`}>
<a>index</a>
</Link>
<Link href={`/hello`}>
<a>hello</a>
</Link>
</div>
)
export default Hello
複製程式碼
CSR 與 SSR 判斷
我們現在有一個頁面,上面有連結。我們前面有說過 Next.js 是一個兼具 CSR 與 SSR 的框架,那他是怎麼處理的呢?先區分一下兩種來源:
- 如果直接點 Link 連結,是在 Client Side 換頁 => CSR
- 重新整理,或是第一次到這個畫面上,必須先發 Request 到後端 => SSR
Next 的做法是透過 getInitialProps 的方式,在 Render 之前就先透過 req 來判斷來源為何:
import Link from 'next/link'
const Hello = (props) => (
<div>
<h1>{props.text}</h1>
<Link href={`/hello`}>
<a>reload</a>
</Link>
</div>
)
Hello.getInitialProps = async function({req, query}) {
if (req)
return { text: 'hello server' }
return { text: 'hello client' }
}
export default Hello
複製程式碼
這樣執行之後,我們可以發現:
- 如果是 SSR 的話,會在 getInitialProps 取得 req
- 如果是 CSR 的話,getInitialProps 中不會得到 req
小結論
Next 可以優雅地替我們解決 Isomorphic 的複雜機制,達到同時有 SSR 與 CSR 的解法。透過了簡單的實作來了解如何開始,如果之後新專案有需要是直得考慮匯入的!
Reference
License
本著作由Chang Wei-Yaun (v123582)製作, 以創用CC 姓名標示-相同方式分享 3.0 Unported授權條款釋出。