Next.js로 블로그 만들기 - 3
pre-rendering (사전 렌더링)
넥스트는 모든 페이지를 사전 렌더링한다
모든 자바스크립트를 하나의 html에 모두 불러오는 것이 아니라 각 페이지에 맞게 최소한의 js가 담겨있는 html을 미리 생성해둔다
이러한 사전 렌더링은 더 나은 성능과 SEO를 얻을 수 있다
사전 렌더링 종류
넥스트의 사전 렌더링은 두 가지 종류를 가지고 있다
Static-Generation (정적 생성) : 넥스트의 빌드시에 모든 html을 생성해놓고 요청이 들어오면 만들어둔 html을 재사용한다
Server-Side-Rendering (서버 사이드 렌더링) : 사용자의 요청이 들어올 때마다 새로운 html을 생성한다
하이브리드
넥스트는 이러한 두 가지 렌더링 방법을 선택적으로 사용할 수 있게 만들었다
필요한 페이지 마다 렌더링 방식을 개발자가 직접 고를 수 있는 것
언제 무엇을 써야할까?
넥스트 홈페이지에서는 리소스를 덜 사용하고, 기능적인면에서 우월하기 때문에 가능하면 정적 생성을 사용하기를 권하고 있다
우선 방법을 선택하는 법은 다음과 같은 질문을 던져보면 된다
'유저가 요청하기 전에 미리 페이지를 만들어 둘 수 있을까?'
yes라면 정적 생성을, no라면 서버 사이드 렌더링을 택해야 한다
정적 생성
정적 생성은 또 두 가지 경우로 나뉜다
생성할 페이지가 데이터를 포함하지 않는 경우
이때까지 우리가 만든 모든 페이지는 외부 데이터가 필요하지 않다
이런 페이지들은 넥스트 빌드시에 자동으로 정적 생성이 완료된다
하지만 모든 페이지가 이런식으로 데이터 없이 이루어져있는 것은 아니다
생성할 페이지가 데이터를 포함하는 경우
pages하위에 있는 파일들은 모두 컴포넌트를 내보내야한다 이때 getStaticProps라는 비동기 함수 또한 같이 내보내면 된다
getStaticProps 함수를 같이 내보내게 되면 빌드시에 함수가 실행된다
실행된 비동기 함수는 외부에서 데이터를 가져오고 가져온 데이터를 페이지의 props로 전달하게된다
getStaticProps 사용해 보기
getStaticProps를 사용하기 전에 페이지에 들어갈 외부 데이터를 먼저 만들자
최상위 디렉토리에 posts라는 폴더를 만들고 (pages가 아님) 마크다운 파일을 두개 만들어주자
posts/pre-rendering.md
---
title: 'Two Forms of Pre-rendering'
date: '2020-01-01'
---
Next.js has two forms of pre-rendering: **Static Generation** and **Server-side Rendering**. The difference is in **when** it generates the HTML for a page.
- **Static Generation** is the pre-rendering method that generates the HTML at **build time**. The pre-rendered HTML is then _reused_ on each request.
- **Server-side Rendering** is the pre-rendering method that generates the HTML on **each request**.
Importantly, Next.js lets you **choose** which pre-rendering form to use for each page. You can create a "hybrid" Next.js app by using Static Generation for most pages and using Server-side Rendering for others.
posts/ssg-ssr.md
---
title: 'When to Use Static Generation v.s. Server-side Rendering'
date: '2020-01-02'
---
We recommend using **Static Generation** (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request.
You can use Static Generation for many types of pages, including:
- Marketing pages
- Blog posts
- E-commerce product listings
- Help and documentation
You should ask yourself: "Can I pre-render this page **ahead** of a user's request?" If the answer is yes, then you should choose Static Generation.
On the other hand, Static Generation is **not** a good idea if you cannot pre-render a page ahead of a user's request. Maybe your page shows frequently updated data, and the page content changes on every request.
In that case, you can use **Server-Side Rendering**. It will be slower, but the pre-rendered page will always be up-to-date. Or you can skip pre-rendering and use client-side JavaScript to populate data.
이 마크다운들을 파싱해서 우리의 페이지넣게될 외부 데이터이고 상단에 존재하는 'title'과 'date' 메타데이터는 url로 사용될 것이다
마크다운들을 파싱하기위해서는 gray-matter라는 라이브러리를 설치해야한다
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
const postsDirectory = path.join(process.cwd(), 'posts')
export function getSortedPostsData() {
// Get file names under /posts
const fileNames = fs.readdirSync(postsDirectory)
const allPostsData = fileNames.map(fileName => {
// Remove ".md" from file name to get id
const id = fileName.replace(/\.md$/, '')
// Read markdown file as string
const fullPath = path.join(postsDirectory, fileName)
const fileContents = fs.readFileSync(fullPath, 'utf8')
// Use gray-matter to parse the post metadata section
const matterResult = matter(fileContents)
// Combine the data with the id
return {
id,
...matterResult.data
}
})
// Sort posts by date
return allPostsData.sort((a, b) => {
if (a.date < b.date) {
return 1
} else {
return -1
}
})
}
gray-matter을 이용한 posts 디렉토리에 있는 파일들을 파싱하는 모듈을 만들었다
이제 pages/index.js에 다음과 같은 코드를 추가하자
export async function getStaticProps(){
const allPostsData = getSortedPostsData();
return {
props: {
allPostsData
}
};
}
이렇게 getStaticProps라는 함수를 외부로 보내면 그 js에 있는 export default로 설정된 컴포넌트의 Props로 리턴값이 전달된다
여기서는 allPostsData가 전달되는셈, 전달되었다면 받아들이는 코드 또한 작성해야한다
export default function Home({allPostsData}) {
return (
...
</section>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<h2 className={utilStyles.headingLg}>Blog</h2>
<ul className={utilStyles.list}>
{allPostsData.map(({id, date, title})=>{
return (
<li className={`${utilStyles.listItem}`} key={id}>
{title}
<br/>
{id}
<br/>
{date}
</li>
)
})}
</ul>
</section>
...
)
}
이렇게하고 서버를 돌리면 posts에 있는 md파일을 파싱해서 출력하고 있는 것을 볼 수 있다
이로서 정적 생성의 두 가지 방법을 모두 알아봤다
getStaticProps 세부사항
받아올 수 있는 데이터의 종류
위에선 우리가 직접만든 모듈에서 데이터를 가져왔지만 외부 API에서 데이터를 받아올 수도 있고
데이터베이스에 쿼리를 날려서 데이터를 받아올 수도 있다
이는 getStaticProps가 서버사이드에서만 작동하기 때문이다 절대로 클라이언트 사이드에서는 작동하지 않는다
페이지에서만 사용 가능
다른 일반적인 js파일에서는 사용할 수 없고 넥스트의 pages 하위 폴더에 있는 페이지들만 getStaticProps을 사용할 수 있다
Server-Side Rednering (서버사이드 렌더링)
위와 같은 경우들이 아닌 사용자의 요청이 없다면 사전에 html을 만들어 둘 수 없는 페이지라면 정적 생성을 하기에는 무리가 있다
그럴 때 사용하는 것이 사용자가 요청할 때 마다 html을 생성하는 서버사이드 렌더링이다
이 때는 getStaticProps를 export하는 대신 getServerSideProps를 export해야한다