Next.js - SSG, ISR의 기능 정리

RumbleBi·2024년 11월 19일
0

next.js 14v 정리

목록 보기
3/12
post-thumbnail

Next.js 에서 제공하는 렌더링 기법중 SSR이 유명하지만, 웹사이트의 성능을 최적화 하는데는 SSG, ISR의 기법이 중요하다고 생각한다. 이는 서버에서 웹 페이지에 대한 요청을 하지 않고 프로젝트의 빌드타임에서 HTML파일이 생성되고 페이지를 요청할 시 서버를 거치지않고 Next서버에서 반환해주기 때문에 사용자에게 보이는 속도가 빠른 장점이 있다.

SSG를 동적경로에 설정

getStaticProps를 사용할 경우 staticPath가 필요하다. 왜냐하면 SSG는 빌드타임에서 사전렌더링을 하기위해 어느 페이지로 이동할지 알려줘야 페이지를 생성할 수 있기 때문이다.

export const getStaticPaths = () => {
  return {
    paths: [{params: {id: "1"}},
            {params: {id: "2"}},
            {params: {id: "3"}}], // 반드시 문자열로 설정
    fallback: false // (default) 404페이지로 이동
  }
}

여기서 fallback 옵션은 예외처리를 위한 옵션을 설정하는 것이다.

fallback 옵션의 추가기능

fallback: blocking 이 방식은 SSR의 방식처럼 사전렌더링을 하여 빌드타임에 생성되지 않은 페이지도 사용 가능하게 한다. 만약 접속한 페이지가 book/100 인데, 빌드타임에 book/100 이 만들어져 있지 않았다면, SSR방식으로 렌더링 후에, book/100 페이지에 대해 next.js 서버에서 정적 html 파일을 생성하여 book/100페이지를 다시 재진입 시 static 하게 동작시킬 수 있다.

blocking 옵션의 주의사항: 만약 백엔드서버에 추가적인 데이터 요청이 필요할 경우, 사전 렌더링이 길어지므로 브라우저에 넥스트 서버가 아무것도 반환하지 않기때문에 로딩이 길어질 수 있다.

이 문제를 해결하기 위해 fallback: true 로 설정하면, props가 없는 페이지를 반환시키게된다. getStaticProps로 전달받은 데이터가 없는 상태의 UI만 반환 후, 나중에 props값을 받으면 그때 데이터를 다시 브라우저에서 렌더링한다.

추가적으로, 만약 백엔드서버에 없는 데이터를 불러오는 경우라면, getStaticProps내부에

const data = await fetch(api);

if(!data) {
  return {
    notFound: true,
  }
}

not found 옵션을 사용하여 404페이지로 이동시킬 수 있다.

SSG방식으로 했을경우 주의점 SEO 태그 설정 주의점

fallback: true 로 SSG페이지를 구성했다면, meta 태그들에 들어가는 content가 서버에서 받아온 데이터를 삽입하게 되는 경우, client 단에서 렌더링하는 컴포넌트에서 router.isFallback 상태일때 따로 return 문에 SEO의 세멘틱 태그들을 작성해주어야 한다. 만약 설정해주지 않으면, 새로 페이지를 가져올때 SEO에 대한 메타 태그들이 전송되지 않기 때문이다.


// ...code

export default function Page({
  book,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  const router = useRouter();
  
  if (router.isFallback) {
    return (
      <title>{title}</title>
      <meta property="og:image" content="/thumbnail.png" />
      <meta property="og:title" content="한입북스" />
      <meta property="og:description" content="한입 북스에 등록된 도서들을 만나보세요" />
    )
  } 
  
  
  return (
    <>
      <Head>
        <title>{title}</title>
        <meta property="og:image" content={coverImgUrl} />
        <meta property="og:title" content={title} />
        <meta property="og:description" content={description} />
      </Head>
      // ...code
    </>
    )
}

if(router.isFallback){

return <>

...

}

이런식으로 넣어줘야한다.

ISR의 기능

ISR은 SSG와 SSR의 장점들을 합친 기능이라고 할 수 있다. 특정 시간, 트리거를 기반으로 동안 빌드타임에 생성한 HTML파일을 사용자에게 next서버단에서 빠르게 보여주거나, 특정 시간, 트리거가 HIT하게 되면, 새로 데이터를 백엔드서버에서 받아오거나 할 수 있는 것이다.

ISR의 페이지 재생성 방식은

빌드타임때 페이지 생성 -> revalidate 설정한 시간이 지나면 새롭게 데이터 fetching이 된 페이지 재생성 및 반환, 시간이 안지났다면 이전 빌드타임에 저장된 페이지 반환

export const getStaticProps = () => {
  // ...code
  
  return {
    props: {
      // ...code
    },
    revalidate: 60 // (sec)
  }
}

이런식으로 ISR을 적용할 수 있다.

On-Demand 방식의 ISR

특정 시간 사이클마다 페이지를 재생성하는 방식은, 시간과 관계없이 사용자의 행동에 따라 데이터가 업데이트되는 페이지(게시판) 같은 경우에는 적용하기가 어려워 보인다. 그래서 SSR방식을 사용해야하는가 싶지만, 그렇게 되면 매번 요청이 들어올 때마다 사전 렌더링을 수행하기 때문에 접속자가 많을 경우 서버에 부담이 갈 수 있다. 그러므로 최대한 정적인 페이지로 하는것이 좋은 방법이다.

이러한 한계를 커버할 수 있는 방법이 시간을 기준으로 하는것이 아닌 요청을 받을 때마다 생성하는 On-Demand 방식의 ISR을 사용할 수 있다.

예로, 사용자가 게시글을 수정해서 새로운 페이지가 필요할 경우 수정된 페이지를 보여주도록 요청할 수 있다는 것이다.

// api/revalidate.ts

export default async function handler(req, res) {
  try {
  // revalidate할 페이지 경로 설정
  await res.revlidate('/home')
  // 응답 성공시 임의 값 반환
  return res.json({ revalidate: true })
  } catch(err) {
  res.status(500).send("Revalidation Failed")
  }
}

next.js에서 제공하는 api 폴더로 사용자의 행동이나 조건에 따라 업데이트를 할 때, 작성해둔 api 파일안의 함수를 호출하여 트리거 할 수 있다.

이러한 On-Demand 방식의 렌더링을 페이지 라우터에서 많이 사용하고 있다고 하는데, 아직 SSG, SSR 방식만 써왔던 나에게 이러한 개념들만 알고 있다가 ISR 방식을 직접 경험해보면서 next.js의 부족했던 경험들을 채워줄 수 있었다.

profile
기억보다는 기록하는 개발자

0개의 댓글