Next 18장 - CSR, SSR, SSG, ISR 짚고 가기
포스트
취소

Next 18장 - CSR, SSR, SSG, ISR 짚고 가기

Next

  • ReduxNext에서 사용하기 전에 짚어보는 배경지식

CSR (Client Side Rendering)

  • 구동 방식이 사용자측에서 이루어진다.
  • React와 같은 SPA(Single Page Application)의 기본적인 구동 방식이다.
  1. 브라우저가 서버에 콘텐츠를 요청한다.
  2. 서버에 콘텐츠를 요청하게 되면 서버에서는 빈 뼈대의 HTML와 자바스크립트 링크를 보내준다.
  3. 사용자는 자바스크립트를 다운로드하고, 다운로드 된 자바스크립트가 빈 뼈대의 HTML에 DOM을 동적으로 생성하여 그려낸다.
  4. 사용자는 위의 모든 과정이 끝나야 화면을 볼 수 있기 때문에, 사용자 경험에 좋지 못하지만, 이후 중복되는 내용은 고정해두고 업데이트 돼야 할 콘텐츠만 동적으로 DOM을 그려내어 교체하기 때문에 이후의 렌더링은 SSR 방식보다 빠르다.

SSR (Server Side Rendering)

  • 구동 방식이 서버에서 이루어진다.
  1. 사용자가 페이지를 요청하면 서버에서는 페이지에 필요한 데이터를 모두 삽입하고 CSS까지 모두 적용해 렌더링 준비를 마친 HTML과 Javscript 코드를 브라우저에 전달한다.
  2. 모든 데이터가 담긴 HTML을 받았기 때문에 사용자는 빠르게 화면을 받아볼 수 있다.
  3. 하지만 해당 시점에서는 사용자가 버튼을 클릭하거나 이동하려고 할 때 아무 반응이 없는데, 이는 내용과 스타일이 입혀진 빈 껍데기인 HTML에 불과하고, 아직 자바스크립트가 실행되고 로직이 연결되기 전이다.
  4. 따라서 사용자가 보는 것과 사용자가 연결되기까지는 간극이 존재하며, 페이지를 이동할 때에 이와 같은 과정이 반복된다.
  5. 데이터가 전부 들어있는 완성된 HTML을 전송하기 때문에 SEO에 유리하다.
  6. 초기 구동 속도가 빨라 사용자는 빠른 화면을 볼 수 있게 되기에 사용자 경험에 좋으나, 과정을 매번 서버에서 반복하기 때문에 서버 부하가 높으며 이후 중복되는 부분 또한 다시 렌더링 받기 떄문에 초기 진입은 빨라도 이후의 렌더링은 CSR보다 느린 편이다.
  • 초기 렌더링만 SSR이 담당하고 이후 브라우저에서 CSR을 하게 된다.
  • 데이터를 가져올 때 useEffect를 사용했다면, getServerSideProps, getStaticProps, getStaticPaths 을 활용하여 데이터를 불러온다.

getServerSideProps

  • Next 초기 렌더링 중 getServerSideProps를 발견하면 컴포넌트 함수 호출 전에 getServerSideProps를 먼저 호출한다.
  • API 통신을 통해 받아온 데이터를 컴포넌트의 props로 전달하며, 함수는 매 호출마다 서버에서 실행된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export async function getServerSideProps(context) {
  const res = await fetch(`https://.../data`);
  const data = await res.json();

  return {
    props: {
      listData: data,
    },
  };
}

const Main = ({ listData }) => {
  <ul>
    {listData.map((item) => (
      <li key={item.id}>{item.title}</li>
    ))}
  </ul>;
};

SSG (Static Site Generation)

  • 빌드 시에 HTML이 생성되고 매 요청마다 HTML을 재사용한다.
  • 각각의 요청마다 HTML을 만드는 SSR보다 높은 성능을 가지기 때문에 권장된다.
  1. 어플리케이션을 서버에 배포해서 처음 빌드할 떄 렌더링된다. (…next build)
  2. 이 때, 동적인 데이터가 필요한 부분은 빌드 시에 사전에 요청하여 데이터를 포함한 HTML 파일을 생성한다.
  3. 사용자가 접속하여 페이지를 요청할 때, 빌드된 HTML 파일을 사용자에게 전달하고, 사용자는 이를 받아 페이지를 렌더링한다.
  4. 이후 CSR과 유사한 방식으로 동작하며, 렌더링된 페이지가 로드되면서 자바스크립트가 실행되고, 상호작용에 따라 필요한 데이터를 요청하고 업데이트된 콘텐츠를 동적으로 렌더링한다.
  • getStaticProps, getStaticPaths와 같은 함수를 사용하여 정적 페이지 생성을 설정해주어야 한다.
  • 정적인 페이지이기 떄문에 블로그 게시물과 같은 정적으로 생성된 정보를 요청마다 동일한 정보를 반환하는 경우에 사용된다.

getStaticProps

  • 서버 측에서만 실행되는 함수로 클라이언트에서는 실행되지 않는다.
  • API와 같은 외부 데이터를 받아서 정적 생성을 하기 위한 용도로 빌드 시에만 딱 한 번 호출되며, 정적 파일로 빌드된다.
  • Main 페이지가 호출되면 getStaticProps가 먼저 실행되며 props에 리턴 값을 담아 컴포넌트에 전달한다.
  • 이 함수가 담긴 페이지가 빌드 될 때 서버에서 API를 호출하여 데이터를 담고, 데이터가 담긴 HTML이 생성되게 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export async function getStaticProps() {
  const res = await fetch(`https://.../data`);
  const data = await res.json();

  return {
    props: {
      listData: data,
    },
  };
}

const Main = ({ listData }) => {
  <ul>
    {listData.map((item) => (
      <li key={item.id}>{item.title}</li>
    ))}
  </ul>;
};

getStaticPaths

  • 동적 라우터를 사용해서 pages/posts/[id].tsx란 파일을 만들었을 때, id에 따라서 다른 글을 보여주고 싶을 때의 예시이다.
  • path가 외부 데이터에 의존할 때, 빌드 시에 id=1, 2, 3에 해당하는 데이터를 가져와서 페이지를 생성한다.
  • getStaticPaths로 페이지 마다의 데이터를 getStaticProps로 전달하고, 이를 Detail로 전달하여 정적 페이지를 미리 생성한다.
  • fallback이라는 boolean & blocking 값을 통해, 빌드 시에 생성되지 않은 주소로 사용자가 요청을 할 때의 반환값을 말한다.
    • true : 빌드 시에 생성되지 않은 페이지로 요청할 때 fallback 페이지를 제공하고, 서버에서 정적 페이지를 생성하여 사용자에게 제공한다.
    • false : 빌드 시에 생성되지 않은 페이지의 요청에 404로 응답한다.
    • blocking : 빌드 시에 생성되지 않은 페이지로 요청할 때, SSR 방식으로 제작한 정적 페이지를 사용자에게 제공하며, 이후 해당 주소로 요청이 올 경우 정적 페이지로 응답한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
export const getStaticPaths = async () => {
  return {
    paths: [
      { params: { id: "1" } },
      { params: { id: "2" } },
      { params: { id: "3" } },
    ],
    fallback: true,
  };
};

export const getStaticProps = async ({ params }) => {
  const id = params.id;
  const res = await axios.get(`https://url/${id}`);

  return {
    props: {
      listData: res.data,
    },
  };
};

const Detail = ({ listData }) => {
  <ul>
    {listData.map((item) => (
      <li key={item.id}>{item.title}</li>
    ))}
  </ul>;
};

ISR (Incremental Static Regeneration)

  • SSG에 포함되는 개념이며, 설정한 시간마다 페이지를 새로 렌더링한다.
  • SSG는 빌드 시에 페이지를 생성하기 때문에 데이터가 변경되면 다시 빌드해야 하지만, 일정 시간마다 특정 페이지가 다시 빌드되어 페이지를 업데이트한다.
  • getStaticProps와 사용 방법은 같지만 revalidate에 명시된 (초)마다 페이지가 새로 렌더링 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export const getStaticProps = async ({ params }) => {
  const id = params.id;
  const res = await axios.get(`https://url/${id}`);

  return {
    props: {
      list: res.data,
    },
    revalidate: 20,
  };
};

const Detail = ({ list }) => {
  <ul>
    {list.map((item) => (
      <li key={item.id}>{item.title}</li>
    ))}
  </ul>;
};

Next.js 웹 서버

  • 서버를 따로 만든 적이 없음에도 서버에서 렌더링 로직을 처리한다.는 말처럼 자체적으로 웹서버를 가지고 있다.
  • 서버에서 실행된다는 getStaticProps, getStaticPaths Next 서버로 전달되어 실행되고 결과값을 컴포넌트에게 반환한다.
  • 함수들이 사용되고 있는 page 폴더는 프론트와 백엔드, 서버와 공유하고 있는 공간이며 getServerSideProps 함수는 Next 의 자체 서버에서 실행된다.

Hybrid Web App

  • 특정 목적을 달성하기 위해 이러한 렌더링 방식을 혼합하여 두 개 이상의 기능이나 요소를 결합한 것을 말한다.
  • 페이지 특징 별로 가장 최적화된 렌더링 방식을 선택해서 만들 수 있으며, 한 페이지 내에서도 부분별로 렌더링 방식을 혼합하여 하이브리드 방식으로 만들 수 있다.
1
2
3
4
home => ISR
about => SSG
profile => SSR/CSR
contact => CSR

정리

  • 웹 애플리케이션 개발 시, TTV(Time To View)와 TTI(Time To Interact)의 간극을 줄여, 사용자가 볼 수 있는 시간과 실제 사용할 수 있는 시간의 간극을 줄여나갈 수 있거나, 이 간극을 알려줄 수 있는 것이 중요하다.
  • SEO 적용이 크게 중요하지 않거나 데이터 pre-rendering이 필요없다면 CSR
  • 정적 문서로 충분한 화면이면서 빠른 HTML 문서 반환이 필요하다면 SSG
  • 컨텐츠가 동적이지만 자주 변경되지 않는 경우 ISR
  • 매 요청마다 화면이 달라지면서 서버 사이드로 렌더링을 하고자 한다면 SSR

  • 사용자의 로그인이 필요한가?
    • O => CSR, SSR, Hybrid(CSR/SSR)
    • X => 데이터가 변경되는가?
      • O => 자주 변경되는가?
        • O => SSR, Hybrid(CSR/SSG, SSR)
        • X => ISR
      • X => SSG

2024-03-29

  • React는 기본적으로 client 단에서 실행된다.
  • SEO에 최적화 되어 있지 않다는 것은, 소스 코드를 확인해보면 알 수 있는데, 자바스크립트 라이브러리인 리액트는 초기에 사용자측에서 자바스크립트를 다운로드 받아 코드를 실행시키기 때문에 소스 코드가 비어있는 것을 볼 수 있다.
    • 초기에 화면을 새로고침할 시 나타나는 깜빡임 또한 사용자측에서 자바스크립트가 실행되기까지의 간격이다.
  • Next.js 는 기본적으로 SSR이 된다.
    • 따라서 use client를 작성하였다고 해서, 클라이언트 측에서 렌더링 되는 것이 아니라 모든 컴포넌트는 우선적으로 서버 단에서 렌더링된다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.