Next.js를 써보면서 가장 크게 느낀 건 CSR, SSR을 잘 이해하고 있다고 생각했는데, 실제로는 그렇지 않았다는 것이다. Next.js의 관점에서 CSR, SSR을 어떻게 봐야할지를 다시 한 번 공부해볼 필요가 있다고 생각됐다. 그래서 오늘은 CSR, SSG, SSR, ISG에 대해서 최대한 많은 내용들을 정리해보고자 한다.


정적 사이트 생성은 raw 데이터와 템플릿 세트를 바탕으로 완전히 정적인 HTML 웹 사이트를 생성하는 방법 즉, 웹 사이트의 모든 페이지를 미리 렌더링하고 클라이언트의 요청에 따라 페이지를 제공하는 방법이다.
SSG 렌더링 방식은 다음과 같은 특징이 있다.
- 미리 만들어져 있기 때문에 가장 빠른 형식의 웹 페이지
- 검색 엔진 최적화에 유리
- 데이터베이스 또는 서버 측 프로세스가 거의 필요하지 않은 완전히 정적인 HTML 기반 사이트를 생성할 수 있는 기능을 제공
- 콘텐츠를 업데이트하려면 사이트를 다시 빌드하고 테스트한 후 최종적으로 배포
- 대규모 웹 사이트의 경우 빌드가 오래 걸리고, 관리도 매우 번거로움
웹사이트와 같이 내용이 거의 변하지 않는 웹사이트의 경우에만 사용하는 것이 좋다. 약간의 동적 콘텐츠라도 포함하고 있는 사이트에서는 SSG를 절대 사용하지 않는 것이 좋다.
SSG에서 HTML은 빌드할 때 발생한다. 그 후에는 CDN으로 캐시 되어지고 매 요청마다 HTML을 재사용한다. React에서는 useEffect를 통해 렌더링 시 데이터를 가져오지만, Nextjs에서 SSG를 구현하려면 getStaticParams를 사용해야 한다.
서버를 전혀 사용하지 않고 정적인 페이지를 만들어 저렴한 비용으로 호스팅하는 방식. 즉, 모든 웹 페이지는 빌드 타임에 정적 페이지로 최적화되며 CDN으로부터 서빙되어 적은 비용으로 쉽게 관리된다.
JavaScript: Client의 모든 처리는 Javascript가 수행
API : 모든 기능 및 비지니스 로직은 재사용 가능한 API가 처리
Markup : SSG(Static Site Generator)나 Template Engine(Webpack 등)을 이용해서 Markup을 미리 생성
자바스크립트를 사용하여 브라우저에서 직접 페이지를 렌더링하는 방식으로 모든 로직과 데이터 패치, 템플릿 및 라우팅이 서버가 아닌 클라이언트에서 처리한다. 서버는 빈 HTML 페이지와 모든 로직을 처리하는 자바스크립트 번들을 반환한다. 최초에 HTML을 받는 것 외에는 페이지 렌더링을 위해서 별도의 HTTP 통신을 할 필요가 없어진다. 따라서 서버는 오직 Ajax를 통해 필요한 데이터를 주고 받는 역할만 수행한다.
사용자가 처음 페이지를 로드할 때, 모든 리소스(HTML, CSS, JS 등)를 한 번에 불러온다. 그 이후에는 페이지 간 이동 시 서버로부터 새로운 HTML을 받아오는 대신, 자바스크립트를 통해 필요한 데이터를 가져오고, 그 데이터를 기반으로 클라이언트 쪽에서 화면을 업데이트한다. 실제로는 하나의 페이지에서 작동하는 것처럼 보인다. 빠른 페이지 전환, 서버 요청을 줄여 사용자 경험을 향상시킨다.
CSR은 다음과 같은 특징이 있다.
- 동적 콘텐츠가 포함된 페이지를 만드는 데 사용
- SSG와 달리 서버 비용이 높지 않음
- 처음 로드한 후에는 다른 페이지를 로드하는 속도가 매우 빠름
- 검색 엔진 최적화가 잘 되지 않음 (최근에는 대부분의 웹 크롤러들이 클라이언트 사이드에서 필요로하는 자바스크립트를 실행하고 있어 이러한 문제들이 어느 정도 해소되기는 했으나 여전히 완벽하지는 않다.)
- 초기의 느린 로드 시간과 상호 작용하기 위한 시간이 성능 저하를 일으킴
Next.js에서는 useEffect를 통해 데이터를 CSR을 구현할 수 있다. 하지만 Next.js에서 CSR을 구현하려면 useEffect를 사용하기 보다는 SWR 훅을 사용하여 구현하는 것을 권장한다. CSR로 구현된 부분은 pre-render를 하지 않고 자바스크립트로 화면을 render한다.
데이터 가져오기를 위한 React Hooks 라이브러리로 먼저 캐시로부터 데이터를 반환한 후, fetch 요청을 하고, 최종적으로 최신화된 데이터를 가져오는 전략이다. SWR을 사용하면 컴포넌트는 지속적이며 자동으로 데이터 업데이트 스트림을 받게 되며 UI는 항상 빠르고 반응적이다.
브라우저에서 웹 페이지를 렌더링하는 대신 서버에서 웹 페이지를 생성하는 방법으로, 서버에서 완전히 렌더링 된 페이지를 클라이언트로 보내고, 클라이언트의 자바스크립트 번들이 SPA 프레임워크의 작동을 대신하는 방식.
직접적으로 웹 서버를 만들지 않아도 SSR이 동작하는데, 그 이유는 Next.js가 자체적으로 서버 역할을 수행하기 때문이다. 따라서, 서버 컴포넌트는 Next.js 서버에서 실행되어 데이터를 패칭하거나 로직을 처리하고, 그 결과를 HTML로 만들어 클라이언트에 반환한다. 이 서버 컴포넌트는 서버에서만 실행되며, 클라이언트는 이미 완성된 HTML을 받게 된다.
SSR은 아래와 같은 특징이 있다.
- 동적 콘텐츠가 포함된 페이지를 만드는 데 사용
- SSR은 SSG만큼 빠르지 않지만 페이지가 로드되는 즉시 콘텐츠가 나타나기 때문에 유저가 빠르게 콘텐츠를 확인 가능
- 검색 엔진 최적화에 유리
- 모든 요청이 서버에서 처리되기 때문에 서버의 높은 연산 능력 필요
- SSR 사이트는 공격할 수 있는 지점이 더 많아 보안을 유지하기가 더 어려움
- 캐싱에 복잡한 구성이 많이 필요
서버 컴포넌트에서는 데이터를 서버 측에서 직접 패칭할 수 있으며, 이를 위해 API 호출을 사용하거나 데이터베이스에서 직접 데이터를 가져올 수 있다. 만약 클라이언트 컴포넌트에서 데이터를 가져오고 싶다면, API 엔드포인트나 React의 useEffect 훅을 사용하여 클라이언트 측에서 데이터를 패칭할 수 있다.
전체 사이트를 재빌드할 필요 없이 페이지별로 정적 생성을 사용할 수 있는데, 정적 사이트의 이점을 유지하면서 수많은 페이지로 확장할 수 있다. SSG와 SSR의 장점이 합쳐진 방식으로 보다 효율적이고 확장 가능한 솔루션을 제공하기 때문에 매우 효과적인 렌더링이 가능하다. 다만 웹사이트에 방문한 도중에 업데이트 된다면 사용자는 업데이트 된 컨텐츠를 볼 수 없다.
ISR은 아래와 같은 특징이 있다.
- 페이지를 미리 렌더링하고 캐시하기 때문에 매우 굉장히 빠름
- 내용이 변경되어도 사이트를 다시 배포할 필요가 없음
- 검색 엔진 최적화에 유리
- 새로운 콘텐츠를 적절한 시점에 확인하지 못할 수 있음
특정 페이지를 일정 주기마다 재생성하여 최신 데이터를 반영한다. revalidate 옵션을 사용해 n초마다 페이지를 다시 생성한다. 최초 요청 시에는 캐시된 HTML을 반환하고, 그동안 백그라운드에서 새로운 HTML을 생성한다. 새로운 HTML 파일이 준비되면 그다음 요청 시에 사용되게 된다. 캐시를 자주 갱신하면 최신 데이터를 빠르게 반영할 수 있지만, 서버에 더 많은 부하가 걸릴 수 있고 반대로 캐시 갱신을 너무 드물게 하면, 최신 데이터가 느리게 반영되기 때문에 갱신주기에 신경을 써야 한다.

프론트엔드 렌더링 이해하기: SSG, ISG, SSR, CSR
Next.js와 함께 살펴보는 CSR, SSG, SSR, ISG
웹 렌더링 방식 (SSR, CSR, SSG) 알아보기