[Next.js] SSR, CSR, ISR의 차이에 대해 알아보자.
2023-02-28
SSR vs CSR vs ISR

계속 헷갈렸던 getStaticProps와 getServerSideProps의 차이를 확실히 알게 되었다.

내가 이 차이점을 확실히 해야 했던 이유는, 하고 있는 프로젝트에서 가장 중요한 부분이 SEO이기 때문이다.


모든 페이지가 SEO가 잘 되어야 했고, 동적 라우팅을 사용하고 있고, 데이터 변화가 자주 일어날 것 같은 페이지와

어느정도 정적일 것 같은 페이지들이 혼합되어 있는 구조였기에 Next.js 공식문서를 꼼꼼하게 읽으며 어떻게 개발

할 지 구상해보았다.


getStaticProps와 getServerSideProps의 가장 큰 차이는

getStaticProps는 SSG 방식, getServerSideProps는 SSR 방식이다.

SSG와 SSR은 모두


Next js 에서 pre-render는 각각의 페이지들에 대해서 사전에 HTML파일을 만드는 것을 말한다.

순수 React 에서 클라이언트 사이드에서 js 가 구동되면서 페이지를 렌더링 하는 방식과는 다르다.

브라우저는 이미 다 렌더링이 된 HTML를 받기 때문에 SEO가 잘 되는 것이다.


그리고 이 Pre-render에서도 SSG 방식과 SSR 방식으로 나뉘어지는 것이다.

Static Generation
Sever-side Rendering

Static Generation (SSG)
데이터 패칭이 필요 없을 경우

서버로부터 데이터 패칭이 필요 없을 경우, 즉 컨텐츠 변화가 없을 경우에는 getStaticProps를 사용할 필요도 없다.


데이터 패칭이 필요한 경우

서버로부터 데이터를 받아와서 이를 html 파일에 실어 보내고 싶을 경우이다. getStaticProps 메소드를 사용해야 하고, 이 메소드는 빌드 타임에 실행이 될 것이다.

그리고 패칭한 데이터를 해당 페이지 컴포넌트에 props로 return한다.


데이터 패칭이 필요하고, dynamic routing을 하고 있을 때

만약

이 경우에는 getStaticPaths 와 getStaticProps 메소드를 함께 사용하여야 한다.


getStaticPaths에서는 현존하는 모든 post들의 id값을 받아 path로 설정해주어야 한다. 모든 post 목록을 리턴해주는 api 를 호출하면 될 것이다. 그리고 그 id 값을 params 에 넣어 return 해준다.

fallback 이라는 값도 설정해줄 수 있다. fallback은 빌드 타임에 생성해두지 않은 path에 대해서 어떻게 처리할 것인지에 대한 설정값이라고 생각하면 된다.


fallback: false

getStaticPaths로 설정해둔 path가 아니라면, 404페이지를 보여준다.

fallback: true

getStaticPaths로 설정해둔 path가 아니라면, 404페이지를 리턴하지 않고 fallback version page를 return한다.


여기서 fallback version 이란, page의 props가 empty이고, 이는 useRouter를 사용해 fallback 값이 true임을 감지할 수 있다. 그리고 페이지 컴포넌트 내에서 fallback 이 true일 때 로딩 컴포넌트를 띄워주는 등의 조치를 취할 수 있다.

즉, 생성되지 않은 static path에 대해 새로운 path를 요청한다면, 404페이지나 빈 페이지를 보여주지 않고, 로딩 페이지를 보여줄 수 있는 것이다.


그럼 매번 사용자는 로딩 페이지를 보게 되는 걸까 ? 아니다.

동시에 background 에서 Next.js 는 새로운 path에 대한 밑작업을 시작한다. 해당 path에 대한 HTML파일과 JSON 파일을 생성한다. 그리고 getStaticProps를 실행하여 Full Page를 만든다.

유저 입장에서는 Fallback page에서 Full page 로 전환되는 것을 보게 된다.

그리고 이 새롭게 생성된 Full page 를 프리렌더링된 페이지 리스트에 추가한다.

이 path에 대한 2번째 request부터는 이 프리렌더링 페이지 리스트의 Fullpage 를 반환하는 것이다.


fallback: blocking

fallback: true일 때와는 다르게 로딩 페이지를 보여주지 않고 새 페이지를 만들 때 까지 기다리게 한다.


revalidate

getStaticProps를 사용한다고 절대 페이지가 변경되지 않는 것은 아니다. revalidate 속성을 통해 언제 페이지를 다시 re-generate 할 지 결정할 수 있다. 이를 ISR (Incremental Static Regeneration) 이라고 하는데, 전체 site를 재생성하는 것이 아니라, 페이지 단위로 재생성할 수 있게 도와준다.

만약 revalidate: 60으로 설정해둔다면, 첫 프리 렌더링이 이루어지고, 60초간의 request들에 대해서는 캐시해둔 페이지를 보여줄 것이다. 그러나 60초 이후 부터의 request에 대해서는 새로 regenerate한 페이지를 보여주어 data update 를 가능하게 하는 것이다. 만약 regenerate에 실패한다면, cached page 를 반환한다.

fallback 시 Full page 반환하는 과정과 동일하다.


Next 12.2 update 이후, on-demand revalidate (ODR) 가 가능하게 되었다. ODR은 API 로 부터 revalidate을 수동으로 커스텀 할 수 있도록 한다. 어떤 상황에서 필요할까 ?


예를 들어 revalidate 를 10초로 잡았을 때, 컨텐츠가 10초안에 100개가 새로 등록되었는데도 10초동안은 업데이트가 되지 않을 것이다. 따라서 API 요청을 통해 게시물 개수의 변화를 알고 revalidate를 수동으로 할 수 있어야 한다. 이 경우에 ODR 을 통해 해결 할 수 있다.


Next js 12 update와 함께 달라진 fallback: true

기존에 fallback: true와 fallback: blocking 의 차이점은 로딩 페이지를 보여주냐 아니냐의 차이였다.

유저 입장에서는 당연히 흰 화면보다는 로딩 페이지를 보는 것이 적절하겠지만

SEO 의 관점에서 바라보았을 때, Web Crawler 가 로딩 페이지를 보다가 페이지가 Fullpage 로 변환된다면

SEO에는 문제가 있을 것이다. 따라서 SEO를 위해서는

그러나, Next 12 업데이트와 함께 SEO에 조금 더 최적화 되도록 User가 일반 유저인지, WebCrawler 인지를 판별하여 Crawler일 경우에는 로딩 페이지를 보지 않고 컨텐트를 바로 보도록 하고, 일반 유저의 경우 로딩 페이지를 보도록 업데이트 되었다.


Server-Side Rendering (SSR)

빌드 시 html 파일을 한 번 만드는 SSG 와 달리 ( ISR 고려 안함 ) SSR 방식은 매 요청마다 HTML 파일을 만든다. 따라서 변화가 시시각각 많은 페이지의 경우 SSR 방식을 사용하는 것이 적절하다.

Next.js 공식 문서에서도 SEO가 중요하지 않고, 변화가 없는 페이지에서는 SSG 와 CSR 사용을 권장하고 있다.

SSR 방식은 페이지를 생성할 때, CDN에 캐시하지 않고, 매번 새로운 html 을 만들어내기 때문에 부하가 크다.

cache-control


나는 일단 리뷰를 작성하고, 불러오고, pagination을 처리해야 하는 리뷰 목록 페이지의 경우 SSR을 하려고 한다.

빌드 시 SSG 로 pagination을 일부 페이지 몇 개만 미리 받아온 뒤, 리뷰가 등록될 때마다 혹은 그 이상 페이지 넘버를 접속할 때마다 ISR 로 처리하는 방식도 있는데 어떤 방식이 더 좋을 지는 안 해봐서 잘 모르겠다.