Basic Features: Pages | Next.js
진행중인 프로젝트에서 next.js를 사용하기에, SSG와 SSR개념을 명확하게 이해하기 위해서 공식문서를 번역하여 공부한 내용입니다.
pages/
디렉토리에 .js
, .jsx
, .ts
, .tsx
으로 export된 파일pages/products/[id]
처럼 사용 가능함Next는 기본적으로 모든 페이지를 pre-render
한다.
hydration
(하이드레이션) : 페이지가 브라우저에 로드될때, 자바스크립트 코드는 실행되어서 그 페이지를 상호작용가능하게끔 만드는 것Static Generation
Server-side Rendering
→ HTML을 생성할 때 차이가 있음
Next.js 에서는 Pre-rendering 형태를 페이지마다 선택할 수 있게끔 한다. 두가지 방식을 페이지 별로 섞어서 사용하는 것도 가능하다.
다만 SSR보다 Static Generation을 권장하는 이유: 성능 이슈
** 참고 : 정적파일과 CDN 개념
정적파일
웹 사이트는 일반적으로 이미지, 자바스크립트, css 등의 여러가지 추가 파일을 제공해야 한다. 이것들을 흔히 정적 파일
이라고 부른다. 서버에서 직접 이 모든 정적 파일을 제공하는 방법을 택할 수도 있지만, 이런 경우는 단점이 많다.
1. 서버의 저장 용량은 상대적으로 비싸다.
2. 서버의 저장 용량은 증설하기 어렵다.
3. 그러나 많은 컴퓨팅 파워를 요구하지는 않는다.
따라서 위와 같은 정적 파일들은 일반적으로 클라우드 업체에서 제공하는 정적 파일 저장소를 사용한다. S3 등의 정적 파일 저장소는 위 단점들에 대한 완벽한 대안이 된다.
CDN
CloudFront
는 대표적인 CDN
중 하나로 Amazon에서 제공하고 있는 서비스이다. CDN은 Contents Delivery Network의 약어로, 지리적으로 분산된 여러 개의 서버이다. 수많은 이미지 콘텐츠의 빠른 전송, 대용량 콘텐츠의 초고속 다운로드, 미디어 콘텐츠의 끊김 없는 스트리밍 서비스 등 많은 분야에서 활용된다.
일반적으로 지역별로 여러 개의 서버를 두어 사용자의 요청을 가장 가까운 로컬 서버에서 처리하도록 한다. 이 과정에서 정적 파일 저장소에서 가까운 CDN 로컬 서버로 데이터를 전송해야 하는데, 해당 지역에 데이터가 들여있나 없나에 따라 사용자의 응답 속도에 차이가 난다.
CloudFront
의 경우 215개 이상의 엣지 로케이션을 가지고 있다. 또한 기본적인 로깅과 통계를 제공해 유용하게 사용할 수 있다.
next build
했을때 HTML이 생성됨을 의미function About() {
return <div>About</div>
}
export default About
💡 외부 데이터에 따라 페이지의 내용이 바뀌는 경우: getStaticProps
💡 외부 데이터에 따라 페이지의 경로가 바뀌는 경우: getStaticPaths
getStaticProps
// TODO: api로 'posts'라는 데이터 fetch
export default function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
데이터를 pre-rendering 하기 위해 getStaticProps
라는 async
함수를 export
→ 함수가 빌드 타임에 호출되어 pre-render 시점에 페이지의 프롭스에 데이터를 넘겨줄 수 있음export default function Blog({ posts }) {
// 렌더링할 내용 작성 ..
}
// 아래 함수는 빌드 시점에 호출됨
export async function getStaticProps() {
// 외부 api 호출
const res = await fetch('https://.../posts')
const posts = await res.json()
// { props: { posts } }를 리턴함으로써, Blog 컴포넌트는
// 'posts' 프롭스를 빌드타임에 받을 것
return {
props: {
posts,
},
}
}
getStaticPaths
pages/posts/[id].js
와 같은 다이나믹 라우팅 기능 사용시, 어떤 id로 pre-render할지는 외부 데이터에 의존할 수도 있음. 데이터를 pre-rendering 하기 위해 getStaticPaths
라는 async
함수를 export
→ 함수가 빌드타임에 호출되어 pre-render 하고싶은 경로를 특정할 수 있게 해줌// 아래 함수는 빌드타임에 호출됨
export async function getStaticPaths() {
// 외부 api호출로 posts불러오기
const res = await fetch('https://.../posts')
const posts = await res.json()
// post.id로 pre-render 하고싶은 경로 받아오기
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// return 하는 경로를 pre-render하는 것
// { fallback: false }는 path이외 경로는 404페이지로 설정하는 것
return { paths, fallback: false }
}
위 페이지에서 데이터의 id를 사용해 또 다른 데이터(게시글의 내용 등)를 호출, pre-rendering 해야하는 경우 → getStaticProps
export 하면 됨export default function Post({ post }) {
// 렌더링 내용 작성...
}
export async function getStaticPaths() {
// ...
}
// 아래 내용도 빌드타임에 호출됨
export async function getStaticProps({ params }) {
// params 은 post 의 `id`를 포함함.
// 만약 라우트가 like /posts/1 이라면, then params.id 는 1이 됨
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// props로 post data 던져주기
return { props: { post } }
}
가능한 모든 페이지에 Static Generation 사용하는 것을 권장함
반면, 사용자의 요청 전에 렌더링하고 싶지 않다면 SSG 써서는 안됨
자주 변하는 데이터에 대해서만 Clinet-side data fetching 사용
SSR : SSG보단 느리겠지만, pre-render된 페이지가 항상 최신상태 유지 가능함
HTML이 매 요청마다 생성된다.
getServerSideProps
라는 async
함수를 export
export default function Page({ data }) {
// 렌더링할 내용 작성..
}
// 아래 내용은 매 요청마다
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
getStaticProps
와 형태는 비슷하지만, pre-rendering 시점에 차이가 있음HTML이 빌드타임에 생성되고 매 요청마다 재사용된다.
SSG사용하는 페이지를 만들기 위해서는, 페이지를 export하거나, getStaticProps
를 사용할 수 있다.
유저의 요청 이전에 렌더링되어야하는 페이지를 만들 때 유용하다.
추가적인 데이터를 가져오기 위해서 CSR도 같이 사용할 수 있다.
HTML이 매 요청마다 생성된다.
SSR 페이지를 만들기 위해서는, getServerSideProps
를 export 하면 된다.
SSR은 SSG보다 성능이 좋지 않기 때문에, 필요할 때만 사용하는 것을 권장한다.