정적 데이터 생성 (SSG)
Next.js의 정적 사이트 생성(Static Site Generation, SSG) 기능은 빌드 시 페이지를 미리 생성하여 성능을 최적화하고 서버 부하를 줄이는 강력한 도구입니다.
이 절에서는 SSG의 구현 방법과 장점에 대해 자세히 알아보겠습니다.
SSG의 장점
- 빠른 페이지 로드 : 미리 생성된 HTML을 제공하므로 매우 빠릅니다.
- 서버 부하 감소 : 요청마다 페이지를 생성할 필요가 없습니다.
- SEO 최적화 : 검색 엔진이 정적 컨텐츠를 쉽게 크롤링할 수 있습니다.
- 보안 : 동적 서버 없이 정적 파일만 제공할 수 있습니다.
generateStaticParams 함수 사용
generateStaticParams
함수는 동적 라우트에 대한 정적 페이지를 생성할 때 사용됩니다.
이 함수는 빌드 시 실행되어 생성할 페이지의 매개변수를 결정합니다.
예시
export async function generateStaticParams() {
const posts = await getPosts() // 모든 포스트 데이터 가져오기
return posts.map((post) => ({
slug: post.slug,
}))
}
export default function BlogPost({ params }) {
// params.slug를 사용하여 포스트 데이터 가져오기
return <div>{/* 포스트 내용 렌더링 */}</div>
}
이 예제에서 generateStaticParams
는 모든 블로그 포스트에 대한 정적 페이지를 생성합니다.
정적 데이터와 동적 데이터의 조합
SSG를 사용하면서도 일부 동적 데이터를 포함할 수 있습니다.
예를 들어, 포스트 내용은 정적으로 생성하고 댓글은 클라이언트 사이드에서 동적으로 불러올 수 있습니다.
// app/blog/[slug]/page.js
import { Suspense } from 'react'
import Comments from './Comments'
export async function generateStaticParams() {
// ... (이전과 동일)
}
async function getPostData(slug) {
// 포스트 데이터 가져오기 (빌드 시 실행)
}
export default async function BlogPost({ params }) {
const postData = await getPostData(params.slug)
return (
<article>
<h1>{postData.title}</h1>
<div>{postData.content}</div>
<Suspense fallback={<div>Loading comments...</div>}>
<Comments postId={postData.id} />
</Suspense>
</article>
)
}
여기서 Comments
컴포넌트는 클라이언트 사이드에서 동적으로 데이터를 불러옵니다.
빌드 시 정적 페이지 생성 과정
next build
명령 실행- 페이지 컴포넌트 분석
generateStaticParams
함수 실행 (있는 경우)- 각 경로에 대해 페이지 렌더링 및 HTML 생성
- 정적 파일 생성 (HTML, JSON 등)
빌드 로그를 통해 어떤 페이지가 정적으로 생성되었는지 확인할 수 있습니다.
15장 배포와의 연결
SSG로 생성된 페이지는 15장에서 다루는 배포 과정과 밀접하게 연관됩니다.
정적으로 생성된 페이지는 CDN에 쉽게 배포할 수 있으며, 서버리스 환경에서도 효율적으로 운영할 수 있습니다.
이는 확장성과 비용 효율성 측면에서 큰 이점을 제공합니다.
실습 : 포스트 목록, 페이지 SSG 구현
다음 요구사항을 만족하는 블로그 시스템을 SSG로 구현해보세요.
- 블로그 포스트 목록 페이지
/blog
- 개별 블로그 포스트 페이지
/blog/[slug]
- 각 포스트는 제목, 내용, 작성일을 포함
- 최소 5개의 샘플 블로그 포스트 데이터 사용
구현 예시
export const posts = [
{ id: 1, title: 'First Post', content: '...', date: '2023-01-01', slug: 'first-post' },
// ... 더 많은 포스트
]
export async function getAllPosts() {
return posts
}
export async function getPostBySlug(slug) {
return posts.find(post => post.slug === slug)
}
import Link from 'next/link'
import { getAllPosts } from '@/lib/posts'
export default async function BlogList() {
const posts = await getAllPosts()
return (
<div>
<h1>Blog Posts</h1>
<ul>
{posts.map(post => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
</div>
)
}
import { getAllPosts, getPostBySlug } from '@/lib/posts'
export async function generateStaticParams() {
const posts = await getAllPosts()
return posts.map(post => ({
slug: post.slug,
}))
}
export default async function BlogPost({ params }) {
const post = await getPostBySlug(params.slug)
return (
<article>
<h1>{post.title}</h1>
<p>Published on: {post.date}</p>
<div>{post.content}</div>
</article>
)
}
이 실습을 통해 Next.js의 SSG 기능을 사용하여 블로그 시스템을 구현하는 방법을 경험할 수 있습니다.
이는 성능 최적화와 SEO 향상이 중요한 실제 프로젝트에서 매우 유용한 패턴입니다.