[Next.js] Next.js의 프리 렌더링(SSR, SSG, ISR)
1. Next.js란?
React에서 사용가능한 오픈소스 자바스크립트 웹 프레임워크이며 리액트에서 서버 사이드 렌더링(SSR), 정적 사이트 생성(SSG)나 증분 정적 재생성(ISR)을 쉽게 구현할 수 있도록 도와준다.
2.1 Pre-rendering
Next.js는 기본적으로 클라이언트 사이드 자바스크립트로 모든 작업을 수행하는 대신 각 페이지의 HTML을 미리 만들어주는 Pre-rendering 방식과 클라이언트 사이드 렌더링(CSR)을 혼용하는 하이브리드 방식이며, Pre-rendering을 사용할 경우 검색엔진최적화(SEO)에 유리하다.
프리 렌더링을 사용할 경우와 사용하지 않을 경우
2.2 Static Generation(SSG)
Next.js의 프리렌더링은 Static Generation과 Server-Side Rendering 두가지로 나뉜다.
Static Generation은 빌드 시 HTML을 생성한다. Pre-rendering된 HTML은 그 다음 각 요청에서 재사용 된다.
서버로부터 받는 데이터가 없는 경우 설정이 없어도 SSG가 생성되기에 그냥 사용하면 되지만, 서버로부터 받는 데이터가 있을 경우 getStaticProps를 사용해야한다. 하지만 빌드할 때 페이지가 미리 생성되기 때문에 fetch시 데이터가 변경되더라도 다시 빌드하지 않는 이상 반영되지 않는다. 그렇기에 유저의 요청 이전에 페이지를 띄워야 하는(업데이트가 없는) 블로그같은 페이지에 자주 사용된다.
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
}
}
export default Blog
2.3 Server-Side Rendering(SSR)
Server-Side Rendering은 각 요청이 일어났을 때 HTML을 생성하는 방법이다. 그렇기때문에 주로 데이터가 자주 업데이트 돼야 하는 페이지에 사용된다.
업데이트가 일어날 때 마다 서버에 요청을 하기 때문에 서버에 부담을 줄 가능성이 있고, 서버의 네트워크 상태에 따라 사용자 경험이 안좋아질 가능성이 있다. 하지만 페이지가 사전에 렌더링 되기 때문에 HTML에 대한 정보가 처음부터 포함되어 있어 검색엔진이 데이터 수집할 때 유리하다. 즉, meta태그가 미리 정의되는 등의 이유로 SEO에 유리하다.
function Page({ data }) {
// Render data...
}
export async function getServerSideProps() {
const res = await fetch(`https://.../data`)
const data = await res.json()
return { props: { data } }
}
export default Page
Incremental Static Regeneration(ISR)
ISR은 SSG의 단점을 보완한 방식으로, 정적으로 생성된 페이지도 필요에 따라 업데이트가 가능하게 해준다. 설정한 특정 시간이 경과되면 자동으로 리빌드가 되는 방식이다.
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
revalidate: 10, // In seconds
}
}
export async function getStaticPaths() {
const res = await fetch('https://.../posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map((post) => ({
params: { id: post.id },
}))
return { paths, fallback: 'blocking' }
}
export default Blog