PromleeBlog
sitemap
aboutMe

posting thumbnail
Next.js의 Incremental Static Regeneration(ISR) 완벽 가이드
Comprehensive Guide to Incremental Static Regeneration (ISR) in Next.js

📅

🚀

들어가기 전에 🔗

최근 웹 개발을 공부하다 보면 페이지를 렌더링하는 방식에 대한 고민이 많아집니다. Next.js 에서는 크게 네 가지의 렌더링 방식이 있습니다. 정적 사이트 생성(SSG), 서버 사이드 렌더링(SSR), 클라이언트 사이드 렌더링(CSR), 그리고 Incremental Static Regeneration(ISR)입니다. 이 중에서 ISR은 SSG와 SSR의 장점을 모두 활용할 수 있는 기능으로, 많은 개발자들에게 주목받고 있습니다. 간략하게 표로 정리해 보면,
방식렌더링 시점SEO속도적합한 경우
CSR클라이언트 실행 시불리함중간로그인 후 개인화 UI 등
SSR매 요청마다 서버 렌더링유리함느림자주 바뀌는 데이터
SSG빌드 시유리함빠름정적 콘텐츠 (블로그 등)
ISR빌드 후 + 일정 주기유리함빠름업데이트 간격이 있는 콘텐츠
이 표를 참고하면 각 렌더링 방식의 장단점을 이해하는 데 도움이 될 것입니다. 특히 ISR은 정적 페이지를 일정 주기로 백그라운드에서 재생성할 수 있는 기능으로, 정적 사이트 생성(SSG)과 서버 사이드 렌더링(SSR)의 장점을 결합한 것입니다. 제가 운영하는 블로그는 지금까지는 SSR 방식으로 구현되어 있었습니다. Vercel의 Edge Function과 캐싱을 적극 활용하는 SSR을 구현했지만, Vercel의
Cold Start
문제로 인해 첫 실행 시 페이지 로딩 속도가 느려지는 문제가 있었습니다. 그래서 ISR을 도입하여 페이지를 정적으로 생성하고, 일정 주기로 백그라운드에서 재생성하는 방식을 적용해 보았습니다. 이 글에서는 ISR의 개념부터 구현 방법, 고급 기능까지 자세히 알아보겠습니다.
👨‍💻
SSG를 사용하지 않는 이유는 제 블로그의 업데이트가 없진 않으며, 추가 콘텐츠가 비교적 빠르게 생성되기 때문입니다.

🚀

ISR이란 무엇인가요? 🔗

ISR을 조금 더 자세히 알아보겠습니다.
ISR은 Next.js에서 제공하는 기능으로, 이미 생성된 정적 페이지를 특정 시간 간격으로 백그라운드에서 재생성하여 최신 데이터를 반영할 수 있게 합니다. 이를 통해 전체 사이트를 다시 빌드하지 않고도 개별 페이지의 콘텐츠를 업데이트할 수 있습니다. 예를 들어, 블로그 게시물이 추가되었을 때 전체 사이트를 다시 빌드하지 않고도 새로운 게시물이 포함된 페이지를 자동으로 갱신할 수 있습니다.

🚀

ISR 구현 방법 🔗

ISR을 구현하기 위해서는 Next.js의 generateStaticParams함수와 revalidate 속성을 사용합니다. 이 두 가지를 조합하여 ISR을 구현할 수 있습니다.
먼저, getStaticProps를 사용하여 정적 페이지를 생성할 파라미터 목록을 정의합니다. 예를 들어, 블로그 게시물의 ID 목록을 배열로 만들어 각 게시물에 대한 정적 페이지를 생성할 수 있습니다.
그런 다음, revalidate 속성을 사용하여 페이지가 재생성되는 주기를 설정합니다. 이 속성은 초 단위로 설정되며, 지정된 시간 간격으로 페이지가 백그라운드에서 재생성됩니다.
export const revalidate = 60; // 60초마다 페이지를 재생성
export const dynamicParams = true; // 동적 파라미터를 사용
 
export async function generateStaticParams() {
  const posts = await fetch('https://jsonplaceholder.typicode.com/posts').then(res => res.json())
 
  return posts.map((post) => ({
    id: String(post.id), // id를 문자열로 변환
  }))
}
 
const PostPage = async ({ params }: { params: Promise<{ id: string }> }) => {
  const { id } = await params;
	// const additionalData = await fetchAdditionalData(id); // 추가 데이터 fetch
 
	return (
		<div>
			{/* <h1>{additionalData.title}</h1> 추가 데이터의 제목 표시 
			<p>{additionalData.body}</p> 추가 데이터의 본문 표시 */}
			<p>게시물 ID: {id}</p> {/* 게시물 ID 표시 */}
		</div>
	)
}
export default PostPage;
자 이제 빌드를 시작해 보겠습니다.
npm run build
빌드 도중, Generating static pages (0/20)와 같은 메시지가 출력됩니다. 이 메시지는 ISR을 사용하여 페이지를 생성하고 있다는 것을 나타냅니다. 페이지의 개수는 generateStaticParams에서 반환한 개수에 따라 달라집니다. 예를 들어, 20개의 게시물이 있다면 Generating static pages (0/20)와 같은 메시지가 출력됩니다. 이 메시지는 페이지가 정적으로 잘 생성되고 있음을 나타냅니다.
promleeblog의 static pages
promleeblog의 static pages
그 후, prerendered as static HTML (uses generateStaticParams) 와 같은 메시지가 출력됩니다. 이 메시지는 페이지가 정적으로 잘 생성되었음을 나타냅니다.
image
이제 start 후 페이지를 열어보면, posts/1과 같은 URL로 접근할 수 있습니다. 이 URL은 generateStaticParams에서 반환한 게시물 ID에 따라 달라집니다. 예를 들어, posts/1 URL로 접근하면 첫 번째 게시물의 내용을 확인할 수 있습니다.

revalidateTag로 특정 리소스만 갱신하기 🔗

Next.js는 태그 기반 캐시 무효화 기능도 제공합니다.
import { revalidateTag } from 'next/cache'
 
export async function POST() {
  revalidateTag('posts') // 'posts' 태그를 가진 모든 캐시 무효화
  return new Response('OK')
}

unstable_cache로 캐시 세부 설정 🔗

import { unstable_cache } from 'next/cache'
 
const getData = unstable_cache(async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts')
  return res.json()
}, ['posts'], { revalidate: 30 })

🚀

결론 🔗

Next.js의 ISR은 정적 페이지와 동적 콘텐츠의 장점을 동시에 취할 수 있는 매우 유용한 기능입니다. 특히 많은 수의 페이지를 가진 블로그, 커머스, 문서 사이트 등에 적합하며, 최신 데이터를 유연하게 반영할 수 있도록 돕습니다.

🚀

더 생각해 보기 🔗

이러한 고급 사용법들은 프로젝트에 따라 유용하게 활용될 수 있으며, 다음 글에서 다뤄볼 예정입니다.

🚀

참고 🔗