---
# System prepended metadata

title: Server Side Rendering

---

# Server Side Rendering

- 일반적으로 외부에 알려진 장점 및 단점은 별도로 기술하지 않음.
- 토이/외주 프로젝트간 *Next.js* 및 *Nuxt.js* 실사용 후기

## 실제 사용시 장점

### html 태그를 렌더 시점에 변경 가능

`<meta>` 태그를 직접 프론트엔드 프레임워크를 통하여 변경할 수 있으므로 실제 페이지에 나타나는 자료와 SEO를 위한 태그가 어느정도 일치하게 됨.

### 서버를 프론트에서 직접 컨트롤

*express* 또는 *koa* 같은 *Node.js* 기반 서버 기능을 포함시킬 수 있어서 렌더링 시간을 크게 높이지 않는 작업에 한하여 서버 작업을 일부 프론트에서 처리할 수 있음. i.g.) 프론트엔드에서 자료 크롤링시 CORS이슈 해결이 좀더 간단함

### 특정 자료를 html에 심어서 보낼 수 있음

*react*나 *vue*의 경우 first meaningful paint 까지 사용자가 텅 빈 화면을 보게 되는 경우가 많으나, SSR은 자료를 html에 직접 렌더하여 보낼 수 있으므로 첫 로딩이 오래걸리더라도 최소한 어떤 내용인지정도는 살펴볼 수 있음.

## 실제 사용시 단점들 혹은 개발시 고려해야할 사항들

### `styled-jsx` 사용이 강제됨

SSR을 사용하는 가장 큰 이유는 결국 SEO확보 때문. [가디언지의 웹버전 운영 회고](https://able.bio/rhett/behind-the-screens-at-the-guardian--80gf2hy)에 적혀있듯이, `css`는 `js`와 더불어 퍼포먼스를 갉아먹는 주범. SSR을 사용하게 되었으면 모든 스타일링은 `styled-jsx` 를 사용해야하며 아주 소수의 공통 스타일링을 제외하고 모든 컴포넌트에 별도의 스타일을 직접 지정하여 최대의 퍼포먼스를 보여주어야 함. `nuxt.js` 의 경우 테스트해보지는 못했으나 `next.js` 의 경우 `styled-jsx` 이외의 스타일링은 권장되지 않고, 실제로 관련 라이브러리의 관리도 제대로 되지 않아 사용시 갑자기 스타일링이 깨진다거나 하는 오류가 발생할 수 있음.

### 컴포넌트간의 이동과 페이지의 이동을 분리해야 함

SPA의 경우 컴포넌트의 이동과 페이지의 이동을 분리할 필요 없이 모든 것을 컴포넌트로 보면 되지만, SSR의 경우 항상 최상단은 페이지가 되며 별도의 페이지 초기화 메서드를 가짐(next, nuxt 모두 동일). 따라서 `<router-link />` 같은 객체를 사용하거나 내부 라우터를 변경하여 다른 url로 이동할 수 없고, `<a href="..." />` 를 통하여 직접 페이지를 옮겨주어야 함. 따라서 페이지의 이동이 SPA에 비하여 매끄럽지 못하게 느껴질 수 있고, 페이지 이동 애니메이션을 구현하는 방식도 조금 더 번거로움. 반대로 컴포넌트 안에서도 어느 컴포넌트까지 페이지 데이터의 접근을 허용할 것인가를 명확히 이해하고 작업에 착수해야 하는 번거로움이 있음. 이는 단순히 여기서 그치지 않고 *vuex* 나 *redux* 같은 전역 상태관리 프레임워크 안에서도 각각 클라이언트와 서버에서만 사용 가능한 기능이 발생할 수 있음.

### 프론트엔드 캐싱을 신경쓰지 않을 경우 퍼포먼스가 SPA보다 더욱 떨어짐

SSR의 요점은 결국 프론트 서버에서 API서버에 직접 요청하여 데이터를 받고 렌더하여 html또는 js 엔트리파일로 제공하는 것. 따라서 프론트엔드에서 서버를 별도로 구현하여야 하고, 프론트의 브라우저에서 API호출을 하는 것이 아니라 프론트 서버에서 직접 API호출을 하게 되므로 첫 meaningful paint까지의 기본적인 퍼포먼스는 훨씬 내려감. 유저가 많을수록 더욱 느려지는 것은 당연함. 따라서 커스터마이징한 캐싱 시스템을 직접 `express`등을 통하여 서버쪽에서 구현해주어야 함. 즉 엔지니어링 요소가 이중으로 발생.

아래 도식이 제대로 표시되지 않을 경우 hackmd.io에 올려놓은 내용 참조.

#### SPA

```mermaid
graph LR;
subgraph SPA server side;
  routerproxy[router-proxy]
end;
routerproxy-->browser;
browser-->API;
API-->browser;
```

#### SSR

```mermaid
graph LR;
subgraph SSR server side;
express-->nn;
nn[next or nuxt]-->router-proxy;
end;
router-proxy-->browser;
express-->API;
API-->express;
```

### react 또는 vue 기반의 SSR은 .jsp나 .net이 아니다!

*react*나 *vue*는 모두 SSR을 염두에 두고 개발된 프레임워크가 아니고 본래 클라이언트의 역할만 하게 되어있던 프레임워크임. 따라서 개발중에 예상하지 못한 부작용을 발견할 가능성이 매우 높음. 또한 구조적으로도 하나의 페이지안에 클라이언트와 서버를 모두 품고있어야 하며, 이를 구분하는 것을 사용자가 직접 해야함. 따라서 클라이언트/서버 구분을 명확히 하면서 개발하지 않으면 서버에서 클라이언트 기능을 호출하여 오류가 발생하거나, 서버에서 클라이언트 기능을 호출하여 오류가 발생할 수 있음. 아직까지 이를 명확히 해결한 모델이 없기 때문에 현 시대의 SSR은 아직 과도기적인 상태를 가지고 있다고 보아야 함.

### 별도의 상태 보전(Store Persistence) 관리가 필요

모든 페이지가 실제로 다른 엔드포인트를 갖고 있고, 서로 연결고리 없는 별도의 페이지로 해석되기 때문에 *vuex* 또는 *redux* 를 통하여 전역 상태관리를 할 경우 다른 페이지로 넘어갈 때 상태가 유지되지 않음. 따라서 `redux-persist`나 `vuex-persist` 같은 별도의 라이브러리를 이용하여 전역상태관리되는 내용을 `localStorage` 등에 저장해 두었다가 복원(rehydrate) 하는 과정을 거쳐야 함. 큰 이슈는 아니지만 개념을 이해하고 있어야 할 필요 있음.

### Cookie와 localStorage 관리가 조금 더 까다롭다

클라이언트에서 cookie를 비울 때에는 `setCookie()`를 이용하면 되지만, 서버에서는 쿠키 삭제 요청을 헤더에 심어주어야 한다. 이처럼 관리가 클라이언트와 서버가 자료저장에 접근하는 방식이 완전히 다르기 때문에 회원 로그인 등의 처리가 조금 더 까다롭다. 외부 라이브러리를 사용하면 해결되기는 하는데 자료에 변경이 발생할 경우 그 시점이 명확하지 않다. 예를 들어 서버에서 쿠키 삭제를 명령하더라도 클라이언트에서 해당 페이지를 여는 첫 순간에는 쿠키가 변형되지 않은 상태일 수 있다.