# CSR, SSR 그리고 Pre-rendering

## 🖐🏻 들어가며

사실 Next.js 에서의 styled-component 를 사용하는 것과 관련해서 심각한 고민에 빠져있었어서 이 부분에 대한 트러블 슈팅을 작성하던 도중ㅋㅋㅋ 또크 털깎기로 CSR, SSR, Pre-rendering 에 대해 제대로 알고 가야겠단 생각이 들었…다 하하

React 공부를 처음 시작할 때 해당 부분에 대해 충분히 공부했다고 생각을 했었는데, 막상 이 부분에 대해 제대로 설명할 수 있는가? 를 스스로 질문해보니 그렇지 못했기에.. 이번 기회에 제대로 해야겠다는 생각에 다시 공부를 해봤다.

---

## 👩🏻‍💻 Client Side Rendering

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700041118159/9c988db0-c58d-4620-a275-5bea6860b272.png align="center")

출처 : [https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)

### ↔️ CSR process

---

1. 유저가 웹 사이트에 진입(request)한다.
    
2. CDN 은 최소한의 HTML 파일을 다운로드(response) 한다.
    
    * `index.html` : `script`, `meta`, `link` 등의 태그를 포함하며 빈 컨텐츠를 담고 있다.
        
3. 브라우저는 `index.html` 에 있는 JavaScript 번들 파일을 다운로드 한다.
    
4. api 요청을 수행해 동적 컨텐츠를 가져와 파싱하고 최종 컨텐츠를 렌더링한다.
    
5. 유저가 페이지를 이동한다면 서버에 추가 html 파일을 요청하지 않고 이미 받은 javaScript 를 이용해 렌더링한다.
    

---

## 🌐 Server Side Rendering

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700040956954/b2d05b38-5df7-401a-bb95-34e8a4938eee.png align="center")

출처 : [https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)

---

### 🌐 SSR Process

1. 유저가 웹 사이트에 진입(request)한다.
    
2. CDN 은 리소스를 확인하고 페이지 내에 있는 서버측 스크립트를 실행해 HTML 컨텐츠를 컴파일 및 준비한다.
    
3. 컴파일된 HTML 은 추가 렌더링 및 표시를 위해 클라이언트 브라우저로 전송된다.(response)
    
4. 브라우저는 HTML 을 다운로드하고 최종 사용자가 사이트를 볼 수 있게 한다.
    
5. 브라우저는 JavaScript 를 다운로드하고 실행하며 페이지를 interactive 하게 만든다.
    
6. 유저가 페이지를 이동하면 위 동작이 반복된다.
    

### 🤬 Uncanny Valley

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700041059037/9aad00c6-ccda-4703-aed5-9e1b8d37970c.png align="center")

출처: [https://crystallize.com/blog/frontend-performance-react-ssr-and-the-uncanny-valley](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)

SSR 방식으로 화면을 렌더링 했을 때, View 가 그려진 후 JavaScript 가 다운로드될 때 까지 인터랙션이 일어날 수가 없다. 만약 그 사이 다운로드가 완료되면 그 때부터 유저는 사이트와 인터랙션을 할 수 있는데, 뷰는 있지만 인터랙션이 안되는 구간을 **“Uncanny Valley(불쾌한 골짜기)”**라고 한다.

---

## 🤔 CSR vs SSR

CSR 과 SSR 의 렌더링 방식에서의 차이점은 결국 렌더링을 서버측에서 담당하는지, 클라이언트측에서 담당하는지이다. CSR 은 최소한의 html 파일을 받은 후, 앱에서 사용되는 모든 js 코드를 다운로드 받아 DOM 요소를 추가하는 방식이라면, SSR 은 페이지에 대한 모든 것들을 서버측에서 다운로드 받아 그려낸다.

CSR 의 경우는 **첫 진입 시 모든 js 코드를 로드해야하므로 초기 렌더링 시간이 오래 걸린다.** 하지만, 이후에는 추가적인 로드가 필요한 것이 아니기 때문에 부드러운 유저 경험을 제공한다. 화면 내에서 다른 페이지로 이동하는 경우라고 하더라도, **html 소스를 서버에서 받는 방식이 아닌 클라이언트 측에서 처리하므로 훨씬 빠른 편**이다.

그러나 처음 다운로드 받는 javaScript 번들 사이즈가 클 경우에는 초기 렌더링 속도가 현저히 느려질 수 있으므로 이에 대한 최적화 방법에 대해 계속 고민해야한다. 또한 html 을 미리 만들어두는 방식이 아니고 유저의 요청에 따라 생성되므로 **SEO(serach engine optimization : 검색 엔진 최적화) 대응이 어려운 편**이다.

SSR 의 경우는 CSR에서 발생하는 초기 렌더링 속도, 번들 사이즈, SEO 등의 문제점 개선을 위해 과거의 static site 로 돌아간 방식이다. CSR 과는 다르게 서버에서 html 을 만들어 제공한다. 그렇기 때문에 SEO 최적화가 잘 이루어지며 각 페이지별로 다운이 되므로 초기 렌더링 속도도 빠른 편이다.

---

## 🤨 CSR 과 SSR 선택은 어떤 것을 기준으로 잡으면 좋을까?

### SSR

* 느린 네트워크를 사용할 때 (SSR은 각 페이지별로 응답값을 받아오기 때문!)
    
* SEO 최적화를 필요로 할 때
    
* 빠른 초기 렌더링을 필요로 할 때
    
* 메인 스크립트가 크고 로딩이 매우 느릴 때
    
* 웹 사이트 내에서 상호작용이 별로 없을 때
    

### CSR

* 네트워크가 빠를 때
    
* 서버 성능이 좋지 않을 때
    
* 사용자에게 보여줘야 하는 데이터의 양이 많을 때
    
* 메인 스크립트가 가벼울 때
    
* SEO 최적화가 중요하지 않을 때
    
* 웹 사이트 내에서 상호작용이 많을 때
    

---

## 🚀 Pre-rendering

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700040954682/282c4262-a225-4c25-a4b0-9991e8a81829.png align="center")

출처 : [https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)

**Next.js 공식문서 도입부를 보면 아래와 같이 나와있다.**

> By default, Next.js **pre-renders** every page. This means that Next.js generates HTML for each page in advance, instead of having it all done by client-side JavaScript. Pre-rendering can result in better performance and SEO.
> 
> Each generated HTML is associated with minimal JavaScript code necessary for that page. When a page is loaded by the browser, its JavaScript code runs and makes the page fully interactive. (This process is called *hydration*.)

기본적으로 Next.js 는 모든 페이지를 pre-rendering 한다. 여기서 말하는 pre-rendering 은 Next.js 가 client-side javascript 로 모든 작업을 수행하는 대신, 미리 각 페이지에 대해 html 을 만들어두는 것을 의미한다. pre-rendering 은 SEO 에서 더 나은 퍼포먼스를 보여준다.

이렇게 생성된 html 은 페이지가 브라우저에 로드될 때 해당 JavaScript 코드가 돌아가고 완전한 interactive page가 되도록 만드는데, 이를 ***hydration***이라고 한다.

Next.js 에서의 ***Server-side rendering*** 과 ***Static Generation*** 은 모두 ***pre-rendering*** 방식이며 **필요한 data fetching 과 HTML 렌더링이 client 에 보내지기 전에 이미 수행이 된다.** 이를 통해서 **client 는 non-interactive 한 페이지를 빠른 시간에 전달**받을 수 있으며, **컴포넌트에 필요한 이벤트 리스너와 같은 interactive 한 속성들은 별도의 번들로 전달을 받아서 client 측에서 hydration** 이 이루어진 뒤에 우리가 사용하는 웹앱이 된다.

---

### 🌧️ hydration

pre-rendering 방식으로 구축된 초기 DOM은 동적인 이벤트가 없는 메마른 상태의 뼈대이다. 이 메마른 곳에 수분을 보충하는, HTML 과 JavaScript 를 서로 매칭시켜 동적인 웹 사이트를 브라우저에 렌더링 시키는 기술을 `Hydration` 이라고 한다. 아래의 그림을 참고하면 더 이해가 쉬울 것이다.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700040998300/eb5d2b89-1e19-4ec0-9af2-592046e7f615.jpeg align="center")

`render()` 함수와 `hydrate()` 함수도 비교를 해보자.

```javascript
ReactDOM.render(element, container, [callback]);
// 제공된 container 에 element 를 렌더하고, component에 대한 참조를 반환
// 기존 자식을 덮어쓰지 않고 기존 DOM 노드에 구성요소를 Insert
```

`ReactDOM.render()` 함수는 특정 컴포넌트를 두 번째 파라미더인 지정된 DOM 요소 하위로 주입해 렌더링을 처리해주는 함수이다. 렌더링이 완료되면 특정 이벤트를 처리할 콜 백 함수를 세 번째 파라미터로 넣을 수 있다.

```javascript
ReactDOM.hydrate(element, container, [callback]);
// 기존 마크업에 이벤트 리스너를 붙여주는 과정
```

`ReactDOM.hydrate()` 함수는 특정 컴포넌트를 두 번째 파라미터인 지정된 DOM 요소의 하위로 `hydrate` 처리만 담당한다. 렌더링을 통해 새로운 웹 페이지를 구성할 DOM 을 생성하는 것이 아닌, 기존 DOM Tree 에서 해당하는 DOM 요소를 찾아 정해진 javascript 속성들만 부착시킨다는 의미이다.

---

### 🥲 이해가 어려웠던 부분,

CSR 과 SSR 의 렌더링 방식의 차이점을 이야기하라고 하면 너무나 명확해서, 설명이 쉬웠는데 여기서 Pre-rendering 과 SSR의 차이는 무엇인지 처음에는 눈에 확 들어오지 않았다. 결국은 HTML 을 서버에서 그려주고 응답으로 내려주면, 이후에 JavaScript 코드가 돌면서 인터랙티브한 웹사이트가 된다는것 아닌가? 싶었기에..

하지만 이 두가지의 차이점이라고 한다면 **JavaScript 코드의 다운로드 시점**에 주목해야할 것 같다. 아래 그림들을 비교하면 **Pre-rendering 의 경우에는 JavaScript 는 서버에서 static HTML 을 보내주는 시점에 함께 전송**이 되지만, **SSR의 경우에는 HTML을 클라이언트 측에 보내어 렌더링을 끝낸 시점에 JavaScript 다운로드**가 이루어진다.

흠 그럼 SSR에서의 Pre-rendering 으로 ***Uncanny Valley*** 를 줄였다고 보면되는걸까..? Hoxy 잘못된 부분이 있다면 댓글달아주십쇼!

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700040954682/282c4262-a225-4c25-a4b0-9991e8a81829.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700040956954/b2d05b38-5df7-401a-bb95-34e8a4938eee.png align="center")

출처 : [https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)

---

## 👩🏻‍🌾 마무리

사실 공식문서를 보면서 응 그냥 이런게 있구나~ 하면서 넘겼던 부분들을 제대로 짚을 수 있어서 좋았다. 그리고 사실 이것들을 보기 전에 겪고있던 문제에 대해서 조금은 감이 좀 잡힌 것 같아서 얼른 다시 찾아봐야겠다. 내가 생각하는 부분이 맞는지…! 그리고 Next.js 에서의 여러가지 렌더링 방식도 조만간 제대로 정리를 해봐야겠다. 오늘도 공부할 것들 하나 지웠고, 두 개가 추가되었다! 😏

---

## 참고

* [https://nextjs.org/](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)
    
* [https://crystallize.com/blog/frontend-performance-react-ssr-and-the-uncanny-valley](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)
    
* [https://handhand.tistory.com/m/291](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)
    
* [https://velog.io/@xortm854/ReactDOM.hydrate](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)
    
* [https://rockcontent.com/blog/client-side-rendering-vs-server-side-rendering/](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)
    
* [https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/](https://www.blog.duomly.com/client-side-rendering-vs-server-side-rendering-vs-prerendering/)
