Next.js는 정적 사이트 생성(Static Site Generation, SSG)과 서버 측 렌더링(Server-Side Rendering, SSR)을 지원하는 React 기반 프레임워크입니다. 이 글에서는 정적 생성의 개념, 장점, 사용 방법, 그리고 실무에서의 활용 사례를 중심으로 자세히 설명하겠습니다.
목차
위의 목차를 클릭하면 해당 글로 자동 이동 합니다.
1. 정적 생성이란?
정적 생성(SSG)은 Next.js가 빌드 시점에 페이지의 HTML 파일을 미리 생성해 저장하는 렌더링 방식이기 때문입니다. 이렇게 생성된 HTML은 CDN으로 캐시가 되고 서버 요청 시 재사용되어 즉시 클라이언트에 전달되며, JavaScript를 통해 인터랙티브 기능이 추가됩니다.
이런 이유로 Next.js에서는 SSR보다 높은 성능을 갖는 SSG를 사용하는 것을 권장합니다.
2. 정정 생성(SSG)의 장점
뛰어난 성능
- 사전에 HTML 파일을 생성하기 때문에 페이지 로드가 매우 빠릅니다.
- CDN(Content Delivery Network) 배포로 전 세계 어디서든 빠른 응답 속도를 제공합니다.
SEO 최적화
- 모든 페이지가 미리 생성된 상태로 제공되므로 검색 엔진 크롤러가 쉽게 인덱싱할 수 있습니다.
효율적 비용 절감
- 동적 렌더링과 달리 서버에서 추가적인 작업이 없기 때문에 서버 비용을 절감할 수 있습니다.
안전성
- 콘텐츠가 빌드 시 생성되므로 런타임 중에 에러가 발생할 가능성이 낮습니다.
3. 정적 생성 사용 방법
Next.js는 기본적으로 모든 페이지를 정적으로 생성합니다. pages 디렉터리에 작성된 파일은 자동으로 정적 파일로 빌드됩니다.
// pages/index.js
export default function Home() {
return <h1>Static Site Generation</h1>;
}
getStaticProps를 활용한 데이터 사전 로딩
정적 생성에서 API 데이터를 사전 로딩하려면 getStaticProps를 사용합니다. 이 함수는 빌드 시 데이터 fetching을 수행합니다.
// pages/blog.js
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
props: {
posts, // 컴포넌트에 전달할 데이터
},
};
}
export default function Blog({ posts }) {
return (
<div>
<h1>Blog Posts</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
getStaticPaths를 활용한 데이터 사전 로딩
getStaticPaths를 사용하면 동적으로 생성된 경로를 기반으로 정적 페이지를 미리 생성할 수 있습니다.
// pages/posts/[id].js
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}));
return { paths, fallback: false };
}
export async function getStaticProps(context) {
const { params } = context
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
return { props: { post } };
}
export default function Post({ post }) {
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
ISR(Incremental Static Regeneration)를 활용한 정적 파일 재생성
Next.js는 빌드 이후에도 정적 파일을 재생성할 수 있는 ISR 기능을 제공합니다. 이는 데이터가 자주 업데이트되는 경우에 유용합니다.
// pages/products.js
export async function getStaticProps() {
const res = await fetch('https://api.example.com/products');
const products = await res.json();
return {
props: { products },
revalidate: 10, // 10초마다 데이터를 갱신
};
}
export default function Products({ products }) {
return (
<div>
<h1>Products</h1>
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</div>
);
}
4. getStaticPaths의 fallback 옵션
getStaticPaths의 fallback 옵션은 Next.js에서 동적 라우팅 페이지를 정적 생성할 때, 사전에 생성되지 않은 경로에 대해 어떻게 처리할지를 정의합니다. fallback에는 3가지 옵션이 있고, 이 옵션은 데이터가 많은 경우 효율적으로 정적 페이지를 생성하고 관리하는 데 매우 유용합니다.
fallback: false
동작 & 특징
- getStaticPaths에서 반환한 경로만 정적 생성됩니다.
- 반환되지 않은 경로에 대해 접근하면 404 페이지를 보여줍니다.
- 빌드 시 모든 경로를 생성해야 하므로 미리 정의된 페이지만 지원합니다.
- 데이터가 많거나 자주 추가되는 경우에는 사용이 어렵습니다.
export async function getStaticPaths() {
return {
paths: [
{ params: { id: '1' } },
{ params: { id: '2' } },
],
fallback: false,
};
}
export async function getStaticProps(context) {
const { params } = context;
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
return {
props: { post },
};
}
export default function Post({ post }) {
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
- /posts/1, /posts/2 : 정상적으로 렌더링 됩니다.
- /posts/3 : 404 페이지가 반환됩니다.
fallback: true
동작 & 특징
- getStaticPaths에서 반환되지 않은 경로로 요청이 들어오면 임시적으로 비어 있는 페이지를 반환하고, 해당 경로에 대한 HTML을 서버에서 생성한 후, 클라이언트에서 이를 업데이트합니다.
- 페이지는 CSR(Client-Side Rendering)으로 로드되며, 생성이 완료되면 사용자에게 완전한 콘텐츠가 보입니다.
- 데이터가 많아도 초기 빌드 시간을 단축할 수 있습니다.
- 비어있는 페이지가 노출되어 사용자 경험이 떨어질 수 있습니다. 비어 있는 페이지가 잠시 보이거나 로딩 상태를 구현해야 합니다.
export async function getStaticPaths() {
return {
paths: [{ params: { id: '1' } }],
fallback: true,
};
}
export async function getStaticProps(context) {
const { params } = context;
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
return {
props: { post },
};
}
export default function Post({ post }) {
if (!post) {
return <p>Loading...</p>;
}
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
- /posts/1 : 정적으로 생성된 페이지가 즉시 로드됩니다.
- /posts/2 : 클라이언트에 로딩 상태를 표시한 후, 페이지가 렌더링 됩니다.
- 새로 생성된 페이지는 캐시 되어 이후 요청부터는 정적으로 제공됩니다.
fallback: blocking
동작 & 특징
- getStaticPaths에서 반환되지 않은 경로로 요청이 들어오면, Next.js가 서버에서 해당 페이지를 동기적으로 생성합니다.
- 사용자는 완전히 생성된 HTML을 받을 때까지 기다리게 됩니다.
- 생성된 페이지는 캐시되어 이후 요청부터는 정적으로 제공됩니다.
- 로딩 상태를 처리할 필요가 없기 때문에 사용자 경험 측면에서 더 좋습니다.
- 생성이 완료되기 전까지는 응답이 지연될 수 있습니다.
export async function getStaticPaths() {
return {
paths: [{ params: { id: '1' } }],
fallback: 'blocking',
};
}
export async function getStaticProps(context) {
const { params } = context;
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
return {
props: { post },
};
}
export default function Post({ post }) {
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
- /posts/1 : 정적으로 생성된 페이지를 즉시 로드됩니다.
- /posts/2 : 사용자는 대기 중이며, 완전히 생성된 페이지가 반환됩니다.
fallback 모드 비교
옵션 | 정적 페이지 생성 시점 | 미리 정의되지 않은 경로 요청 | 사용자 경험 | 사용 사례 |
false | 빌드 시 생성 | 404 페이지 반환 | 빠름 | 데이터가 적고 고정적인 경우 |
true | 빌드 시 생성, 요청 시 생성 | 클라이언트에서 로딩 후 렌더링 | 비어 있는 페이지가 잠시 보일 수 있음 | 데이터가 많고 자주 업데이트 되는 경우 |
blocking | 빌드 시 생성, 요청 시 생성 | 완전한 HTML 생성 후 반환 | 대기 시간이 길어질 수 있음 | 데이터가 많고 SEO가 중요한 경우 |
Next.js의 정적 생성은 뛰어난 성능과 SEO를 제공하는 강력한 도구입니다. 특히, 데이터가 자주 변경되지 않는 경우에 최적의 선택이 될 수 있습니다. Next.js에서도 SSG의 사용을 권장하고 있으니 개발 시 고려해 봅시다.
정적 생성 활용 사례
- 블로그 및 마케팅 사이트: 콘텐츠가 자주 변경되지 않으며, SEO가 중요한 경우.
- 문서 사이트: Next.js의 정적 생성은 빠른 로딩과 사용자 경험을 제공.
- e-commerce: ISR을 활용하여 제품 정보를 최신 상태로 유지하며, 페이지 성능도 최적화.
추천글
'개발 공부 일지 > Next' 카테고리의 다른 글
[Next] ISR (+ On-Demand ISR) (4) | 2024.12.04 |
---|---|
[Next] Next.js 이미지 최적화(Image 컴포넌트) (2) | 2024.11.22 |
[Next] RSC(React Server Component)란? (4) | 2024.11.20 |
[Next] Next.js 리다이렉트(Redirect) (3) | 2024.11.19 |
[Next] Next.js 라우팅(Routing) (2) | 2024.11.18 |