🧑‍💻개발

Next.js의 SSG fallback

Next.js의 SSG에서 지원하는 fallback 기능에 대해 알아보자구요 🥸

서론

Next.js 9.3 버전에 데이터 패칭 방식과 데이터 렌더링 방식이 변경되었다.

지금 보고 있는 이 블로그를 만들면서, 데이터 패칭 방식을 고민하고 여러 번 변경했었다. (이것도 나중에 글을 작성할 것이긴 한데, 이 블로그는 노션을 기반으로 한다.)

getServerSideProps를 사용하다가 getStaticProps으로 변경하면서, getStaticPaths에 있는 fallback 기능에 대해 알아보기로 했다.

🛠

getStaticPathsfallback옵션을 무조건 포함하여야 한다.

fallback 옵션

기본적으로 fallback은 데이터가 없을 때, 즉 404일 때 할 행동을 고르는 것이다.

원래라면 그냥 데이터가 없는 것이겠으나, 빌드 시 미리 데이터를 패칭하여 생성해놓는 Next.js는 빌드 이후에도 데이터를 생성할 수 있게 지원한다.

`fallback: false`

데이터가 없으면 404를 표시한다.

즉, 아무 것도 하지 않는다. API에서 새로운 데이터를 받아서 갱신하고 싶다면 새로 페이지를 빌드하여야 한다.

`fallback: true`

데이터가 없으면 비동기적으로 데이터를 받는다.

  • 기존에 getStaticPaths에서 지정한 페이지들은 빌드 시에 Pre-render 해놓았으므로 표시한다.
  • 데이터가 없다면(404), Next.js는 서버에서 데이터를 Fetch해본다. (isFallback: true)
    • Fetch 데이터가 존재한다면, Next.js는 HTML과 JSON을 정적으로 생성한다. 이 땐 getStaticProps가 다시 실행되는 것과 마찬가지다. (isFallback: false)
    • 데이터가 없다면 404를 표시한다. (isFallback: false)

과정 옆에 isFallback을 표시한 이유는, 이 과정이 서버에서 백그라운드로 (비동기적으로) 진행되기 때문이다. 우리가 isFallback을 따로 처리해주지 않는다면, 서버 단에서 넘어온 Props 데이터는 undefined로 표시될 것이다.

데이터가 undefined라면 당연히 표시하는 데이터는 오류가 발생할 것이다... (그리고 이것이 내가 이 글을 쓰는 주 된 이

`fallback: 'blocking'`

데이터가 없으면 동기적으로 데이터를 받는다.

이 옵션의 경우에는 true일 때와 비슷하게 동작하나, 모든 fallback 작업이 끝난 후에 페이지를 로딩한다는 점이 있다.

따로 isFallback 을 받아 처리하는 등의 작업이 필요 없기에 개발자는 편하지만, 그만큼 페이지 로딩 속도를 늦어진다. UX적으로 생각해보자면 당연히 비동기적인 작업이 권장될 것이다.

router.isFallback

그럼 fallback의 상태를 받을 수 있는 옵션도 살펴보자. (공식 Fallback Pages 링크도 참고)

// 소스 예제의 출처는 Next.js 공식 문서입니다.
// Route: /posts/{id}
function Post({ post }) {
const router = useRouter()
// 아직 페이지가 생성되지 않은 경우, 표시됩니다.
// getStaticProps()가 완료될 때까지 표시됩니다.
if (router.isFallback) {
return <div>Loading...</div>
}
// 생략...
}
// 이 함수는 빌드 시에 실행됩니다.
export async function getStaticPaths() {
return {
// 빌드 시에는 `/posts/1`과 `/posts/2`만 생성됩니다.
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
// 추가적인 페이지 생성(fallback) 을 켭니다.
// 예를 들자면: `/posts/3` 같은?
fallback: true,
}
}
// 이 함수도 빌드 시에 실행됩니다.
export async function getStaticProps({ params }) {
// params은 post의 `id`를 포함합니다.
// 라우트가 /posts/1이라면, params.id는 1이 됩니다.
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// 받은 post 데이터를 props로 넘깁니다.
return {
props: { post },
// 이 부분은 추후 다른 글에서 다룰, revalidate 기능입니다.
// 리퀘스트가 온 이후, 데이터를 재생성(re-generate)합니다.
revalidate: 1,
}
}

주의 할 점!

  • 위에서도 언급했지만, fallback: true라면 isFallback을 무조건 처리해주어야 한다. 안한다면 Pre-render 과정에서 바로 오류난다.
    • Error occurred prerendering page "/post/[slug]". Read more: https://err.sh/next.js/prerender-error
      TypeError: Cannot read property 'title' of undefined
  • Static HTML Export를 사용하는 경우, 당연하게도 서버리스 함수를 사용할 수 없기 때문에 fallback은 무시된다.
    • 여담이나 같은 이유로 ISR 같은 서버리스 함수가 필요한 다른 기능들도 사용할 수 없다.
2024 Dohyun Jung.
Made with ☕️.