계속 헷갈렸던 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 방식으로 나뉘어지는 것이다.
서버로부터 데이터 패칭이 필요 없을 경우, 즉 컨텐츠 변화가 없을 경우에는 getStaticProps를 사용할 필요도 없다.
서버로부터 데이터를 받아와서 이를 html 파일에 실어 보내고 싶을 경우이다. getStaticProps 메소드를 사용해야 하고, 이 메소드는 빌드 타임에 실행이 될 것이다.
그리고 패칭한 데이터를 해당 페이지 컴포넌트에 props로 return한다.
만약
이 경우에는 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 을 통해 해결 할 수 있다.
기존에 fallback: true와 fallback: blocking 의 차이점은 로딩 페이지를 보여주냐 아니냐의 차이였다.
유저 입장에서는 당연히 흰 화면보다는 로딩 페이지를 보는 것이 적절하겠지만
SEO 의 관점에서 바라보았을 때, Web Crawler 가 로딩 페이지를 보다가 페이지가 Fullpage 로 변환된다면
SEO에는 문제가 있을 것이다. 따라서 SEO를 위해서는
그러나, Next 12 업데이트와 함께 SEO에 조금 더 최적화 되도록 User가 일반 유저인지, WebCrawler 인지를 판별하여 Crawler일 경우에는 로딩 페이지를 보지 않고 컨텐트를 바로 보도록 하고, 일반 유저의 경우 로딩 페이지를 보도록 업데이트 되었다.
빌드 시 html 파일을 한 번 만드는 SSG 와 달리 ( ISR 고려 안함 ) SSR 방식은 매 요청마다 HTML 파일을 만든다. 따라서 변화가 시시각각 많은 페이지의 경우 SSR 방식을 사용하는 것이 적절하다.
Next.js 공식 문서에서도 SEO가 중요하지 않고, 변화가 없는 페이지에서는 SSG 와 CSR 사용을 권장하고 있다.
SSR 방식은 페이지를 생성할 때, CDN에 캐시하지 않고, 매번 새로운 html 을 만들어내기 때문에 부하가 크다.
cache-control
나는 일단 리뷰를 작성하고, 불러오고, pagination을 처리해야 하는 리뷰 목록 페이지의 경우 SSR을 하려고 한다.
빌드 시 SSG 로 pagination을 일부 페이지 몇 개만 미리 받아온 뒤, 리뷰가 등록될 때마다 혹은 그 이상 페이지 넘버를 접속할 때마다 ISR 로 처리하는 방식도 있는데 어떤 방식이 더 좋을 지는 안 해봐서 잘 모르겠다.