---
# System prepended metadata

title: '[Web] Compare muti & single page application (MPA v.s SPA) and client-side & server-side render (CSR v.s SSR)'
tags: [Web]

---

###### tags: `Web`

# [Web] Compare muti & single page application (MPA v.s SPA) and client-side & server-side render (CSR v.s SSR)

## Outline
- Muti Page Application (多頁面應用程式)-> MPA
- Single Page Application (單頁面應用程式)->SPA
- Client Side Render (客戶端渲染)->CSR
- Server-Side Render (伺服器端渲染)->SSR

## MPA v.s SPA
![](https://i.imgur.com/MUM08d3.png)

![](https://i.imgur.com/WyKntmp.png)

## MPA
- 指的是一般傳統開發方式, 一個畫面，一個 HTML 檔案
- Pros
    - SEO 可優化: 可針對每個頁面進行優化
    - 分析能力: 每個頁面獨立, google容易分析每個頁面的性能
- Cons
    - 效能和速度: 每次都要reload pages
    - 前後端緊密整合: 開發跟測試需要較長時間
    - 維護和更新: 要維護大量page與更新
- Examples
    - Amazon, eBay

## SPA
- 把所有資料都放在同一個頁面，**不需要換頁**，使用者可以在單一頁面裡瀏覽全部內容，也就是說只會有一個index.html 檔
- 透過 AJAX 技術，client 可以向 server 發出非同步請求，索取局部內容的資料進行抽換，降低每次請求與回應的資料量，提高瀏覽速度

![](https://i.imgur.com/w7ChyZO.png)

- Pros
    - 效能優
    - 使用者體驗優
    - 開發速度快
    - 容易debug
    - 數據可緩存: 向伺服器發出第一個請求後, 資訊緩存在catch, 較能有離線作業模式(GoogleDocs offline mode)
- Cons
    - SEO問題: 初始頁面空的
    - 下載內容時間: 如果平台複雜、龐大且優化不佳，用戶的瀏覽器要花很多時間來加載內容
    - 需要JS的支持: 如果沒有此功能，您將無法完全使用某個應用程序的完整功能。如果用戶在瀏覽器中禁用 JS，他們將無法充分利用該應用程序
- Examples
    - Gmail, Twitter, Facebook, Google Maps, Evernote, Airbnb, etc.

## CSR
### Flow
![](https://i.imgur.com/ji3OZQ4.png)
1. Client side 發出 request, sever 回傳幾乎不含任何內容的html
2. 瀏覽器 load JS bundle
3. 瀏覽器執行 React, fetch API 拿到 DATA，React 更新 UI
4. 頁面完整呈現且可互動

### Feature
- 畫面於 Runtime 時，==在 Client 製作==
- User 可以很快看到畫面，但畫面並非一次到位，而是批次到位，ex: 畫面顯示 loading 狀態
- 效能主要來自使用者身上，伺服器可以專心做資料處理負擔降低很多

### Code Example
Special Function: `useEffect`
```javascript=
// React.js
export default function CSRPage() {
  const [dateTime, setDateTime] = useState();

  useEffect(() => {
    axios
      .get('http://worldtimeapi.org/api/timezone/Asia/Taipei')
      .then((res) => {
        setDateTime(res.data.datetime);
      })
  }, []);

  return (
    <main>
      <div>{dateTime}</div>
    </main>
  );
}
```

### Pros
- 頁面資料是最新的：每次頁面請求會在 Client side 打 API 取得最新資料

### Cons
- SEO較差：HTML 檔案只有容器，內容透過 JS 後來才渲染的，爬蟲在爬取資料時可能會爬到空的 tag
- 需要靠 JS fetch data + render 頁面，所以 JS bundle較大，隨著專案擴充容易有效能問題

## SSR
### Flow
![](https://i.imgur.com/Jcf0pbo.png)
1. 當user進入頁面, client 向 server 發出 requests, 此時畫面才開始在 server 端製作，Build 出一個擁有完整內容的 HTML 檔案(含 React js css 以及 DATA)
2. client 端 browser load html, css, js file
3. 進行 Hydration, 在 Client 端把 Server 端渲染出的 DOM element 加上事件監聽器等屬性，讓 DOM element 變為動態且具有互動性
4. 頁面完整呈現且可互動

### Feature
- 畫面於 Runtime 時，==在 Server 製作==，當畫面製作完成傳回 Client 後才會 render
- 發出請求後到**看到畫面會有點小 delay，User 需要等待才會一次看到完整畫面**(不會有 Loading 指標)

### Code Example
- Special Function: `getServerSideProps`
- `getStaticProps` 會在執行 npm run build 的時候執行並抓取所需要的資料。伺服器跑完該 function 後，除了產生了 HTML 檔案，會另外產生 JSON 檔案。在 Client-side 瀏覽器會讀取該 JSON 檔案裡面的資料用來顯示 page 內容
- 每次 Client-side 發出 request 的時候在 Server side 執行, 產生html檔給Client-side show畫面 [demo](https://www.patterns.dev/posts/server-side-rendering/)
```javascript=
// Next.js
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
  }
}

export default Blog;
```

### Pros
- SEO優：在 Server 就製作好畫面，爬蟲爬到的是在 Server 建好並帶上完整資訊的 HTML 檔案
- 不需要使用 JS 來處理 render 頁面的部分，較不會造成 render blocking，JS 檔案較小

### Cons
- TTFB (Time to First Byte) 指標差，下列情形會導致 Server 的回應更慢：
    -  網速慢
    -  有大量 User request，sever 要夠強大
    -  Sever 端寫的程式碼太糞

## CSR V.S. SSR compare demo
- [CSR demo](https://theodorusclarence.com/blog/nextjs-fetch-method#demo)
- [SSR demo](https://theodorusclarence.com/blog/nextjs-fetch-method#demo-1)

## 總結
- CSR 通常是在講 SPA 居多
- SSR 通常是在講 MPA 居多

## Reference
[Multi-page Application](https://lvivity.com/single-page-app-vs-multi-page-app)
[Understanding Next.js Data Fetching (CSR, SSR, SSG, ISR)](https://theodorusclarence.com/blog/nextjs-fetch-method#introduction)
[getStaticProps](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
