什麼是 SSR?為什麼要 SSR?

SSR 是 Sever-side Render 的縮寫,意思是指「在 Server 端就產生(Render)出畫面」。目前大概有幾種產生畫面的時機點:

  1. Server Side Render: 在後端接收到 Request 即產生 HTML 畫面,需要新的資料則需要重新發送 Request ,也會產生一個新的畫面。後端的 Framework 通常都會有一個 HTML Template 的機制就是在產生畫面的動作。
  2. Client Side Render: 在前端進行 Render,後端作為資料供應的 API 層。當需要新的資料時,前端發送 Request 後只需要部份更新畫面就好。
  3. Isomorphic: 網站能夠同時考慮 SSR 與 CSR 兩種方式,之前有整理過關於 Isomorphic 的介紹。

最早期的網站都是 SSR 的方式進行,但每次的重新 Render 會造成後端的負擔提升也讓使用者的體驗變差。而後來的 React/Vue 之類的 Framework 則是基於 CSR 的方式讓使用者體驗,並達到了前後端分離的優點。但 CSR 還是伴隨著幾個問題:

  1. 有些 CSR 的網站會造成爬蟲取得的頁面不是那麼完整,造成 SEO 的問題
  2. 第一次載入畫面是等到前端載入後,會有一段時間的空白

因此,如果能夠兼具 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 的方式手動安裝:

1
$ npm install --save next react react-dom

接著再把 package.json 中執行的方式改成 NEXT:

1
2
3
4
5
6
7
{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}

然後建立一個頁面在 /pages/index.js 檔案:

1
export default () => <div>Welcome to next.js!</div>

最後,運行指令就會將專案跑在 3000 PORT:

1
npm run dev

方法 ②: create-next-app

許多人開發 React 會搭配 create-react-app 的 scaffold 來跳過複雜的環境設定,Next.js 也有:

1
2
3
4
5
$ 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 的檔案:

1
2
3
4
5
6
7
const Hello =  (props) => (
<div>
<h1>Hello Next</h1>
</div>
)

export default Hello

此時就會多了一個 Route 在 /hello 。

兩個頁面彼此連結

在 Next 中提供了 Link 的 Component 讓我們可以進行頁面間的 Client Side 換頁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 來判斷來源為何:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

[1] Next.js
[2] create-next-app


License


本著作由 Chang, Wei-Yaun (v123582) 製作,
創用CC 姓名標示-相同方式分享 3.0 Unported授權條款釋出。