Next.js 의 SSG, SSR, ISR 적절하게 적용하기

김상두·2023년 2월 21일
0

트러블슈팅

목록 보기
4/12
post-thumbnail

시작하며

Next js 는 react를 기반으로 몇가지 편리한 기능이 추가된 프레임워크입니다. 파일 기반의 routing시스템,webpack 및 bable의 자동 적용등 몇가지 편리한 점이 있지만 이번 포스트에서는 pre-render에 대해서 자세히 알아보고 이를 어떤 방식으로 적용하면 좋을지 고민해 봅니다.

pre-render 이란?

일반적으로 react 프로젝트는 모든 자바스크립트 파일을 불러온뒤 이를 브라우저에서 해석하여 html파일로 만드는 클라이언트 사이드 렌더링을 이용합니다. 하지만, 이로인해 처음 받는 html 파일에는 root를 위한 div 태그하나만 있기 때문에, 검색엔진에의해 노출될 가능성이 낮아지고, 초기 빈페이지를 보는 시간이 길어지기 때문에 사용자 유입이 떨어질수 있습니다.

이를 방지하기 위해서 미리 서버에서 html 파일을 만들고 이를 전송해주는 서버사이드 렌더링 방식이 사용됩니다. next.js 에서는 이를 pre-render라고 이야기하며, 이를 사용하게 되면 내용이 들어있는 html을 받을수 있기 때문에 위에서 언급한 문제를 해결할수 있습니다. next.js 에서는 pre-render를 위해 4가지 방식을 제공하고 있습니다.

static page

page에 어떠한 pre-render 함수를 명시하지 않으면 기본적으로 Next.js는 페이지를 html 파일로 만들어 정적 파일형태로 보관하고 이후 요청시 해당 파일을 제공합니다. 따라서 이는 pre-render의 기본값이라고 볼수 있습니다

SSG

빌드 타임에 html 파일을 생성하여 사용자가 요청시 해당 html을 내려주므로 초기 렌더링 속도가 굉장히 빠릅니다. next.js 팀에서는 해당 방식을 기본으로 권장하고 있습니다.

export default function SSG({ data }: SSGPageProps) {
  return (
    <main>
      <div>{data}<div>
    </main>
  );
}

export const getStaticProps: GetStaticProps = async () => {
  const res = await axios.get('http://localhost:8000');

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

SSR

빌드 타임이 아닌 사용자가 요청할때 데이터를 pre-render 하여 html을 동적으로 생성하여 내려주기 때문에, 속도가 느리지만, 항상 최신의 데이터를 내려줄수 있습니다. next js 팀에서는 최신의 데이터 pre-render가 필요한 상황에서만 사용하라고 권장하고 있습니다.

export default function SSR({ data }: SSRPageProps) {
  return (
    <main>
      <div>{data}<div>
    </main>
  );
}

export const getServerSideProps: GetServerSideProps = async () => {
  const res = await axios.get('http://localhost:8000');

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

ISR

빌드 시점에 페이지를 렌더링 한 후, 설정한 시간 마다 페이지를 새로 렌더링 하는 방식으로, ssg의 일종인데, 일정 시간마다 데이터를 최신으로 유지할수 있는 장점이 추가된 방식입니다. ssg와 동일한 함수를 사용하며 revalidate에 갱신하고자하는 시간을 초단위로 명시해주면된다.

export default function ISR({ data }: SSRPageProps) {
  return (
    <main>
      <div>{data}<div>
    </main>
  );
}

export const getStaticProps: GetStaticProps = async () => {
  const res = await axios.get('https://worldtimeapi.org/api/ip');

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

pre-render 적절하게 사용하기

ssr 대신 isr을 사용할수 있는지 고려하기

기본적으로 isr은 빌드이후 데이터를 주기적으로 최신화 할수있는 ssg입니다. 따라서 해당 방식을 채택할경우 초기렌더링 성능에있어서 ssg 만큼의 성능을 보장받을수 있습니다. 데이터 최신화가 필요하지만, 매번 필요한것은 아닌경우 (실시간 검색 랭킹 등) isr을 채택한다면 속도 측면에서 큰 이점을 가져올수 있습니다. 따라서 ssr을 사용하는 곳에서 isr을 사용해도 무방하다면 isr을 사용하는것이 좋습니다.

pre-render가 꼭 필요한곳에 ssr 사용하기

next.js 공식문서에서 권고하고있는 방식입니다. ssr은 미리 데이터를 받아 html 만들어 받아오기 때문에 아무래도 느릴수 밖에 없습니다. ssr 이라는 방식 자체가 검색엔진에 보다 노출이 잘되도록 하기 위해 적용하는 방식이기 때문에 마이페이지 같이 검색엔진에 노출이 필요없는 곳에는 ssr 대신, 기존에 react에서 사용하던 방식 처럼 data-fetching을 하는것이 좋습니다.

ssr 적용시 로딩 사용하기

앞서 언급한 이야기를 고려하였는데도 ssr을 적용해야한다면, 로딩처리가 필요합니다. 기본적으로 ssr은 서버에서 api를 응답받고 html 만들어 내려보내기 때문에 api요청 응답에 걸리는 시간이 길면 길수록 사용자는 변경되지 않은 ui를 보고있어야 하고, 이는 렉이 걸린것처럼 보이므로 사용자 경험을 크게 저해하게 됩니다. 따라서 페이지 이동시 페이지를 만들고 있음을 알려주기 위해서 ssr적용시에는 반드시 로딩을 적용해야합니다.

// page의 _app.tsx(jsx) 파일에 적용해야합니다. 왜냐하면 모든 페이지 컴포넌트가 이 컴포넌트를 거쳐서 렌더링 되기 때문입니다.
 function MyApp({ Component, pageProps }: AppProps) {
  const [loading, setLoading] = useState(false);
  useEffect(() => {
    const showRoute = ["/postlist", "/postdetail"];
    const start = (url: string) => {
      if (showRoute.find((route) => String(url).includes(route))) {
        setLoading(true);
      }
    };
    const end = (url: string) => {
      if (showRoute.find((route) => String(url).includes(route))) {
        setLoading(false);
      }
    };
    Router.events.on("routeChangeStart", start);
    Router.events.on("routeChangeComplete", end);
    Router.events.on("routeChangeError", end);
    return () => {
      Router.events.off("routeChangeStart", start);
      Router.events.off("routeChangeComplete", end);
      Router.events.off("routeChangeError", end);
    };
  }, []);
  return <>{loading ? <h1>Loading...</h1> : <Component {...pageProps} />}</>;
}

위 코드에서는 여러페이지에 공통으로 적용되는 로딩 스피너를 만들었지만, start, end 이벤트 리스너와 state를 수정해서 여러페이지 각각에 적용되는 로딩스피너를 만들수도 있습니다.

마치며

Next.js는 react에서 서버 사이드 렌더링을 보다 편리하게 할수 있도록 도와주는 프레임워크입니다. react에서는 꽤 복잡하게 설정해야하는 SSG, ISR 같은 방식을 함수로 제공하고 있기 때문입니다. 따라서 react에서 서버사이드 렌더링을 계획하고있고 여건이 된다면 Next.js로 마이그레이션하는것을 추천드립니다.

참고자료

https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
https://velog.io/@hwon3814/NextJS-SSR-%EB%A1%9C%EB%94%A9-%EC%8A%A4%ED%94%BC%EB%84%88
https://www.tiluckdave.in/blog/ssr-ssg-isr

profile
프론트엔드 개발자 김상두입니다

0개의 댓글