[Next.js] 사전 렌더링(Pre-rendering): Static Generation과 SSR
Next.js에서 사전 렌더링을 하는 방법은 크게 두 가지가 있다: Static Generation과 Server Side Rendering(SSR)이 그것이다.
1. Static Generation
- 유저의 요청(request)이 있기 전에 렌더링 대상이 되는 페이지를 사전에 렌더링해야되는 경우 사용한다.
- 보통 build time에 사전 렌더링을 해둔다.
1-1. 데이터가 없는 경우의 Static Generation
데이터가 없는 경우는, 서버로부터 fetch해 올 어떠한 데이터도 없기 때문에 Next.js에서는 build time에 HTML 형태로 사전 렌더링을 해둔다.
function About() {
return <div>About</div>
}
export default About
1-2. 데이터가 있는 경우의 Static Generation
- 페이지 컨텐츠가 외부 데이터에 의존할 경우:
getStaticProps
를 사용한다. - 페이지 경로가 외부 데이터에 의존할 경우:
getStaticPaths
를 사용하는데, 보통getStaticProps
와 함께 사용한다.
1-2-1. 페이지 컨텐츠가 외부 데이터에 의존하는 경우: getStaticProps
사용하기
예를 들면, CMS로부터 블로그 글들의 리스트를 가져오고 싶은 경우
const Blog = ({ posts }) => {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
);
};
// getStaticProps를 build time에 불러오기
export async function getStaticProps() {
// posts를 얻기위해 외부 API를 호출함
const res = await fetch("https://.../posts");
const posts = await res.json();
// { props: { posts } } 형태로 불러옴으로써 Blog 컴포넌트는 build time에 posts를 prop으로서 받게 된다.
return {
props: {
posts,
},
};
}
export default Blog;
1-2-1. 페이지 경로가 외부 데이터에 의존하는 경우: getStaticPaths
사용하기
function Post({ post }) {
// Render post
}
// getStaticPaths 함수는, 사전 렌더링 하고싶은 path를
// build time에 특정할 수 있게 해줌
export async function getStaticPaths() {
// 외부 API 엔드포인트를 불러와서 posts를 얻음
const res = await fetch("http://.../posts");
const posts = await res.json();
// posts에 기반하여, 사전 렌더링하고싶은 path를 얻음
const paths = posts.map((post) => ({
params: { id: post.id },
}));
// build time에만 이 path들을 (post.id) 사전 렌더링 할 것임
// { fallback: false }는 다른 라우트는 404를 띄워야 된다는 뜻
return { paths, fallback: false };
}
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();
// props를 통해 post 데이터를 페이지로 넘긴다.
return { props: { post } };
}
1-3. 어떤 경우에 Static Generation을 써야할까?
공식문서에서는 데이터가 있든 없든, 가능하다면 Static Generation을 사용할 것을 추천한다. 왜냐면 build time에 한 번 만들어지고나서 CDN에 의해 served 되는데, 이 경우는 매 요청시마다 페이지를 렌더링하는 SSR보다 더 빠르기 때문.. 예를 들면
- Marketing pages (판매 페이지)
- Blog posts (블로그 글)
- E-commerce product listings (온라인 커머스 및 상품 나열)
스스로에게 물어봤을 때, 유저의 요청 이전에 이 페이지를 띄워야되는지? 가 맞다면 Static Generation을 쓰면 되고, 그게 아니라면 SSR을 쓰면 된다.
- 예를 들면, 지속적으로 업데이트되는 페이지의 경우 유저의 요청이 있기 전에 사전 렌더링을 할 수 없으므로 이 경우에 Static Generation은 좋은 아이디어가 아니다. 이 경우 두 가지 방법 중 하나를 사용해야 한다.
- 페이지의 일부 부분에 대해 사전 렌더링을 스킵하고 클라이언트 사이드의 JavaScript 또는 TypeScript를 사용할 수 있다.2) SSR을 사용하기
- -> 2. Server Side Rendering(바로아래)에서
- 1) Static Generation과 Clien Side Rendering(CSR)을 사용하기
2. Server Side Rendering(SSR)
- 서버 사이드 렌더링을 사용할 경우, 각 요청시 마다 페이지를 사전 렌더링한다. 페이지가 CDN에 의해 캐싱될 수 없으므로 Static Generation에 비해서는 더 느릴 것이다.
- 그렇지만, 사전에 렌더링된 페이지들은 항상 최신 상태를 유지한다.
- For example, suppose that your page needs to pre-render frequently updated data (fetched from an external API). You can writegetServerSidePropswhich fetches this data and passes it toPagelike below:
- 만약 페이지가 (외부 API로부터 fetch해 오는) 업데이트되는 데이터를 항상 사전 렌더링해야 할 경우, 이 데이터를 받아와서 Page로 넘기는 getServerSideProps를 사용해야한다.
function Page({ data }) {
// Render data
}
// 매 요청시마다 아래 getServerSideProps 함수가 호출된다.
export async function getServerSideProps() {
// 외부 API로부터 값을 fetch 해온다.
const res = await fetch(`https://.../data`);
const data = await res.json();
// 이전과 마찬가지로, props를 통해 페이지에 데이터를 전송한다.
return { props: { data } };
}
export default Page;
getServerSideProps
는 getStaticProps
랑 비슷하긴 한데, 전자는 build time에 사전 렌더링이 되는 것이 아니라 매 요청시마다 사전 렌더링 된다는 차이점이 있다.
그래서 요악하자면..
1. Static Generation(추천): HTML이 build time에 생성이 되고, 매 요청시마다 재사용된다. Static Generation을 사용하려면 페이지 컴포넌트를 export하거나, getStaticProps
를(+ 필요하다면 getStaticPaths
까지) export해야 한다. 유저의 요청이 있기 전에 사전 렌더링이 될 수 있는 페이지들에 적절한 방식이다. 추가적으로 데이터를 가져오기 위해 Client Side Rendering을 사용할 수도 있음!
2. Server Side Rendering(SSR): HTML이 매 요청시마다 생성된다. 서버사이드 렌더링을 사용하는 페이지를 만들기 위해서는, getServerSideProps
를 export해야 된다. SSR의 퍼포먼스가 Static Generation보다 안좋기때문에, 진짜 꼭 필요한 경우에만 사용하자.
출처
Next.js 공식문서