Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#25] docs: static-site-generation 번역 #59

Merged
merged 4 commits into from
Jul 31, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,40 @@ title: Static Site Generation (SSG)
description: Use Static Site Generation (SSG) to pre-render pages at build time.
---

{/* TODO: 번역이 필요합니다. */}

# Static Site Generation (SSG)

<details>
<summary>Examples</summary>

- [WordPress Example](https://github.com/vercel/next.js/tree/canary/examples/cms-wordpress)([Demo](https://next-blog-wordpress.vercel.app))
- [Blog Starter using markdown files](https://github.com/vercel/next.js/tree/canary/examples/blog-starter) ([Demo](https://next-blog-starter.vercel.app/))
- [DatoCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-datocms) ([Demo](https://next-blog-datocms.vercel.app/))
- [TakeShape Example](https://github.com/vercel/next.js/tree/canary/examples/cms-takeshape) ([Demo](https://next-blog-takeshape.vercel.app/))
- [Sanity Example](https://github.com/vercel/next.js/tree/canary/examples/cms-sanity) ([Demo](https://next-blog-sanity.vercel.app/))
- [Prismic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-prismic) ([Demo](https://next-blog-prismic.vercel.app/))
- [Contentful Example](https://github.com/vercel/next.js/tree/canary/examples/cms-contentful) ([Demo](https://next-blog-contentful.vercel.app/))
- [Strapi Example](https://github.com/vercel/next.js/tree/canary/examples/cms-strapi) ([Demo](https://next-blog-strapi.vercel.app/))
- [Prepr Example](https://github.com/vercel/next.js/tree/canary/examples/cms-prepr) ([Demo](https://next-blog-prepr.vercel.app/))
- [Agility CMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-agilitycms) ([Demo](https://next-blog-agilitycms.vercel.app/))
- [Cosmic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-cosmic) ([Demo](https://next-blog-cosmic.vercel.app/))
- [ButterCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-buttercms) ([Demo](https://next-blog-buttercms.vercel.app/))
- [Storyblok Example](https://github.com/vercel/next.js/tree/canary/examples/cms-storyblok) ([Demo](https://next-blog-storyblok.vercel.app/))
- [GraphCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-graphcms) ([Demo](https://next-blog-graphcms.vercel.app/))
- [Kontent Example](https://github.com/vercel/next.js/tree/canary/examples/cms-kontent-ai) ([Demo](https://next-blog-kontent.vercel.app/))
- [Builder.io Example](https://github.com/vercel/next.js/tree/canary/examples/cms-builder-io) ([Demo](https://cms-builder-io.vercel.app/))
- [TinaCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-tina) ([Demo](https://cms-tina-example.vercel.app/))
- [Static Tweet (Demo)](https://static-tweet.vercel.app/)
- [Enterspeed Example](https://github.com/vercel/next.js/tree/canary/examples/cms-enterspeed) ([Demo](https://next-blog-demo.enterspeed.com/))
<summary>예제</summary>

- [WordPress 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-wordpress)([데모](https://next-blog-wordpress.vercel.app))
- [마크다운 파일을 활용한 블로그 시작하기](https://github.com/vercel/next.js/tree/canary/examples/blog-starter) ([데모](https://next-blog-starter.vercel.app/))
- [DatoCMS 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-datocms) ([데모](https://next-blog-datocms.vercel.app/))
- [TakeShape 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-takeshape) ([데모](https://next-blog-takeshape.vercel.app/))
- [Sanity 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-sanity) ([데모](https://next-blog-sanity.vercel.app/))
- [Prismic 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-prismic) ([데모](https://next-blog-prismic.vercel.app/))
- [Contentful 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-contentful) ([데모](https://next-blog-contentful.vercel.app/))
- [Strapi 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-strapi) ([데모](https://next-blog-strapi.vercel.app/))
- [Prepr 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-prepr) ([데모](https://next-blog-prepr.vercel.app/))
- [Agility CMS 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-agilitycms) ([데모](https://next-blog-agilitycms.vercel.app/))
- [Cosmic 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-cosmic) ([데모](https://next-blog-cosmic.vercel.app/))
- [ButterCMS 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-buttercms) ([데모](https://next-blog-buttercms.vercel.app/))
- [Storyblok 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-storyblok) ([데모](https://next-blog-storyblok.vercel.app/))
- [GraphCMS 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-graphcms) ([데모](https://next-blog-graphcms.vercel.app/))
- [Kontent 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-kontent-ai) ([데모](https://next-blog-kontent.vercel.app/))
- [Builder.io 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-builder-io) ([데모](https://cms-builder-io.vercel.app/))
- [TinaCMS 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-tina) ([데모](https://cms-tina-example.vercel.app/))
- [Static Tweet (데모)](https://static-tweet.vercel.app/)
- [Enterspeed 예제](https://github.com/vercel/next.js/tree/canary/examples/cms-enterspeed) ([데모](https://next-blog-demo.enterspeed.com/))

</details>

If a page uses **Static Generation**, the page HTML is generated at **build time**. That means in production, the page HTML is generated when you run `next build`. This HTML will then be reused on each request. It can be cached by a CDN.
만약 페이지가 **정적 생성**을 사용한다면, 페이지 HTML은 **빌드 타임**에 생성됩니다. 즉, 운영 환경에서 페이지 HTML은 `next build`를 실행할 때 생성됩니다. 이 HTML은 각 요청에서 재사용됩니다. 이는 CDN에 의해 캐시될 수 있습니다.

In Next.js, you can statically generate pages **with or without data**. Let's take a look at each case.
Next.js에서는 **데이터를 사용하거나 사용하지 않고** 페이지를 정적으로 생성할 수 있습니다. 각 경우를 살펴보겠습니다.

### Static Generation without data

By default, Next.js pre-renders pages using Static Generation without fetching data. Here's an example:
기본적으로, Next.js는 데이터를 가져오지 않고 정적 생성을 사용하여 페이지를 미리 렌더링합니다. 다음은 예제입니다:

```jsx
function About() {
Expand All @@ -48,22 +46,22 @@ function About() {
export default About
```

Note that this page does not need to fetch any external data to be pre-rendered. In cases like this, Next.js generates a single HTML file per page during build time.
이 페이지는 미리 렌더링하기 위해 외부 데이터를 가져올 필요가 없다는 점을 주목합니다. 이와 같은 경우, Next.js는 빌드 타임에 페이지당 하나의 HTML 파일을 생성합니다.

### Static Generation with data

Some pages require fetching external data for pre-rendering. There are two scenarios, and one or both might apply. In each case, you can use these functions that Next.js provides:
몇몇 페이지는 미리 렌더링을 위해 외부 데이터를 가져와야 합니다. 두 가지 시나리오가 있으며, 둘 중 하나 또는 둘 다 적용될 수 있습니다. 각 경우에, Next.js가 제공하는 다음 함수를 사용할 수 있습니다:

1. Your page **content** depends on external data: Use `getStaticProps`.
2. Your page **paths** depend on external data: Use `getStaticPaths` (usually in addition to `getStaticProps`).
1. 페이지 **콘텐츠**가 외부 데이터에 의존하는 경우: `getStaticProps`를 사용합니다.
2. 페이지 **경로**가 외부 데이터에 의존하는 경우: `getStaticPaths`를 사용합니다(`getStaticProps`와 함께 사용하는 경우가 많습니다).

#### Scenario 1: Your page content depends on external data

**Example**: Your blog page might need to fetch the list of blog posts from a CMS (content management system).
**예제**: 블로그 페이지가 CMS(콘텐츠 관리 시스템)에서 블로그 포스트 목록을 가져와야 할 수 있습니다.

```jsx
// TODO: Need to fetch `posts` (by calling some API endpoint)
// before this page can be pre-rendered.
// TODO: 페이지가 미리 렌더링되기 위해 (API 엔드포인트를 호출함으로써)
// `posts`를 가져와야 합니다.
export default function Blog({ posts }) {
return (
<ul>
Expand All @@ -75,21 +73,21 @@ export default function Blog({ posts }) {
}
```

To fetch this data on pre-render, Next.js allows you to `export` an `async` function called `getStaticProps` from the same file. This function gets called at build time and lets you pass fetched data to the page's `props` on pre-render.
프리 렌더링 과정에서 데이터를 가져오기 위해, Next.js는 동일한 파일에서 `getStaticProps`라는 `비동기` 함수를 `export`할 수 있도록 합니다. 이 함수는 빌드 타임에 호출되며, 가져온 데이터를 페이지의 `props`로 전달할 수 있습니다.

```jsx
export default function Blog({ posts }) {
// Render posts...
// posts 렌더링...
}

// This function gets called at build time
// 이 함수는 빌드 타임에 호출됩니다
export async function getStaticProps() {
// Call an external API endpoint to get posts
// posts를 가져오기 위해 외부 API 엔드포인트를 호출합니다
const res = await fetch('https://.../posts')
const posts = await res.json()

// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
// { props: { posts } }를 리턴함으로써, Blog 컴포넌트는
// 빌드 타임에 `posts`를 prop으로 받게 됩니다
return {
props: {
posts,
Expand All @@ -98,81 +96,81 @@ export async function getStaticProps() {
}
```

To learn more about how `getStaticProps` works, check out the [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/get-static-props).
`getStaticProps`가 어떻게 작동하는지 자세히 알아보려면, [Data Fetching 문서](/docs/pages/building-your-application/data-fetching/get-static-props)를 확인합니다.

#### Scenario 2: Your page paths depend on external data

Next.js allows you to create pages with **dynamic routes**. For example, you can create a file called `pages/posts/[id].js` to show a single blog post based on `id`. This will allow you to show a blog post with `id: 1` when you access `posts/1`.
Next.js는 **동적 경로**를 사용하여 페이지를 생성할 수 있습니다. 예를 들어, `id`에 기반하여 단일 블로그 포스트를 보여주는 `pages/posts/[id].js` 파일을 만들 수 있습니다. 이렇게 하면 `posts/1`에 접근할 때 `id: 1`의 블로그 포스트를 보여줄 수 있습니다.

> To learn more about dynamic routing, check the [Dynamic Routing documentation](/docs/pages/building-your-application/routing/dynamic-routes).
> 동적 라우팅에 대해 더 알아보려면, [동적 라우팅 문서](/docs/pages/building-your-application/routing/dynamic-routes)를 확인합니다.

However, which `id` you want to pre-render at build time might depend on external data.
그러나, 빌드 타임에 어떤 `id`를 프리 렌더링하려는지는 외부 데이터에 따라 달라질 수 있습니다.

**Example**: suppose that you've only added one blog post (with `id: 1`) to the database. In this case, you'd only want to pre-render `posts/1` at build time.
**예제**: 데이터베이스에 블로그 포스트 하나만 추가했다고 가정해보겠습니다(`id: 1`). 이 경우, 빌드 타임에 `posts/1`만 프리 렌더링하려고 할 것입니다.

Later, you might add the second post with `id: 2`. Then you'd want to pre-render `posts/2` as well.
이후, `id: 2`를 가진 두 번째 포스트를 추가할 수 있습니다. 이 경우 `posts/2`도 프리 렌더링하려고 할 것입니다.

So your page **paths** that are pre-rendered depend on external data. To handle this, Next.js lets you `export` an `async` function called `getStaticPaths` from a dynamic page (`pages/posts/[id].js` in this case). This function gets called at build time and lets you specify which paths you want to pre-render.
따라서, 프리 렌더링될 페이지 **경로**는 외부 데이터에 따라 달라집니다. 이를 처리하기 위해, Next.js는 동적 페이지(여기서는 `pages/posts/[id].js`)에서 `getStaticPaths`라는 `비동기` 함수를 `export`할 수 있도록 합니다. 이 함수는 빌드 타임에 호출되며 프리 렌더링하고 싶은 경로를 지정할 수 있습니다.

```jsx
// This function gets called at build time
// 이 함수는 빌드 타임에 호출됩니다
export async function getStaticPaths() {
// Call an external API endpoint to get posts
// posts를 가져오기 위해 외부 API 엔드포인트를 호출합니다
const res = await fetch('https://.../posts')
const posts = await res.json()

// Get the paths we want to pre-render based on posts
// posts를 기반으로 프리 렌더링하고 싶은 경로를 가져옵니다
const paths = posts.map((post) => ({
params: { id: post.id },
}))

// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
// 빌드 타임에 이 경로들만 프리 렌더링합니다.
// { fallback: false }는 다른 경로는 404가 되어야 함을 의미합니다.
return { paths, fallback: false }
}
```

Also in `pages/posts/[id].js`, you need to export `getStaticProps` so that you can fetch the data about the post with this `id` and use it to pre-render the page:
또한 `pages/posts/[id].js`에서, 이 `id`에 대한 포스트 데이터를 가져와서 페이지를 프리 렌더링할 수 있도록 `getStaticProps`를 `export`해야 합니다:

```jsx
export default function Post({ post }) {
// Render post...
// post 렌더링...
}

export async function getStaticPaths() {
// ...
}

// This also gets called at build time
// 이 함수 또한 빌드 타임에 호출됩니다
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
// params에는 포스트 `id`가 포함됩니다.
// 만약 경로가 /posts/1 이라면, params.id는 1입니다.
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()

// Pass post data to the page via props
// 페이지에 post 데이터를 props로 전달합니다
return { props: { post } }
}
```

To learn more about how `getStaticPaths` works, check out the [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/get-static-paths).
`getStaticPaths`가 어떻게 작동하는지 자세히 알아보려면, [Data Fetching 문서](/docs/pages/building-your-application/data-fetching/get-static-paths)를 확인합니다.

### When should I use Static Generation?

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.
가능한 경우 **정적 생성**을 사용(데이터 포함 또는 미포함)하는 것을 권장합니다. 이렇게 하면 페이지가 한 번 빌드되고 CDN에 의해 제공되므로, 매 요청마다 서버가 페이지를 렌더링하는 것보다 훨씬 빠릅니다.

You can use Static Generation for many types of pages, including:
정적 생성을 많은 유형의 페이지에 사용할 수 있습니다:

- Marketing pages
- Blog posts and portfolios
- 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 cases like this, you can do one of the following:
이런 경우, 다음 중 하나를 수행할 수 있습니다:

- Use Static Generation with **Client-side data fetching:** You can skip pre-rendering some parts of a page and then use client-side JavaScript to populate them. To learn more about this approach, check out the [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/client-side).
- Use **Server-Side Rendering:** Next.js pre-renders a page on each request. It will be slower because the page cannot be cached by a CDN, but the pre-rendered page will always be up-to-date. We'll talk about this approach below.
- **클라이언트 사이드 데이터 페칭**과 함께 **Static Generation** 사용: 페이지의 일부를 미리 렌더링하지 않고 클라이언트 사이드 JavaScript를 사용하여 채울 수 있습니다. 이 접근 방식에 대해 자세히 알아보려면 [데이터 페칭 문서](/docs/pages/building-your-application/data-fetching/client-side)를 확인합니다.
- **서버 사이드 렌더링** 사용: Next.js는 각 요청에 대해 페이지를 미리 렌더링합니다. CDN에 의해 캐시될 수 없기 때문에 느릴 수 있지만, 미리 렌더링된 페이지는 항상 최신 상태가 됩니다. 이 접근 방식에 대해 아래에서 더 자세히 이야기하겠습니다.
Loading