Статическая генерация сайтов (SSG)

Примеры

Если страница использует статическую генерацию, HTML-код страницы создаётся во время сборки. Это означает, что в production HTML-код страницы генерируется при выполнении команды next build. Этот HTML затем повторно используется при каждом запросе и может кэшироваться CDN.

В Next.js вы можете статически генерировать страницы с данными или без них. Рассмотрим оба случая.

Статическая генерация без данных

По умолчанию Next.js предварительно рендерит страницы с помощью статической генерации без получения данных. Вот пример:

function About() {
  return <div>About</div>
}

export default About

Обратите внимание, что для предварительного рендеринга этой страницы не требуется получать внешние данные. В таких случаях Next.js генерирует один HTML-файл для каждой страницы во время сборки.

Статическая генерация с данными

Некоторые страницы требуют получения внешних данных для предварительного рендеринга. Есть два сценария, и один или оба могут применяться. В каждом случае вы можете использовать предоставляемые Next.js функции:

  1. Содержимое вашей страницы зависит от внешних данных: используйте getStaticProps.
  2. Пути вашей страницы зависят от внешних данных: используйте getStaticPaths (обычно вместе с getStaticProps).

Сценарий 1: Содержимое страницы зависит от внешних данных

Пример: ваша страница блога может нуждаться в получении списка постов из CMS (системы управления контентом).

// TODO: Необходимо получить `posts` (вызовом API)
//       перед предварительным рендерингом этой страницы.
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

Для получения этих данных при предварительном рендеринге Next.js позволяет вам экспортировать async функцию getStaticProps из того же файла. Эта функция вызывается во время сборки и позволяет передать полученные данные в props страницы при предварительном рендеринге.

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,
    },
  }
}

Чтобы узнать больше о работе getStaticProps, ознакомьтесь с документацией по получению данных.

Сценарий 2: Пути страниц зависят от внешних данных

Next.js позволяет создавать страницы с динамическими маршрутами. Например, вы можете создать файл pages/posts/[id].js для отображения отдельного поста блога по id. Это позволит вам показывать пост с id: 1 при переходе на posts/1.

Чтобы узнать больше о динамической маршрутизации, ознакомьтесь с документацией по динамическим маршрутам.

Однако, какие id вы хотите предварительно отрендерить во время сборки, может зависеть от внешних данных.

Пример: предположим, вы добавили в базу данных только один пост блога (с id: 1). В этом случае вы захотите предварительно отрендерить только posts/1 во время сборки.

Позже вы можете добавить второй пост с id: 2. Тогда вы также захотите предварительно отрендерить posts/2.

Таким образом, пути страниц, которые предварительно рендерятся, зависят от внешних данных. Для обработки этого Next.js позволяет вам экспортировать async функцию getStaticPaths из динамической страницы (в данном случае pages/posts/[id].js). Эта функция вызывается во время сборки и позволяет указать, какие пути нужно предварительно отрендерить.

// Эта функция вызывается во время сборки
export async function getStaticPaths() {
  // Вызов API для получения постов
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Получаем пути для предварительного рендеринга на основе постов
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // Мы предварительно рендерим только эти пути во время сборки.
  // { fallback: false } означает, что другие маршруты должны вернуть 404.
  return { paths, fallback: false }
}

Также в pages/posts/[id].js вам нужно экспортировать getStaticProps, чтобы получить данные о посте с этим id и использовать их для предварительного рендеринга страницы:

export default function Post({ post }) {
  // Рендеринг поста...
}

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

// Эта функция также вызывается во время сборки
export async function getStaticProps({ params }) {
  // params содержит `id` поста.
  // Если маршрут /posts/1, то params.id будет 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  // Передача данных поста в страницу через props
  return { props: { post } }
}

Чтобы узнать больше о работе getStaticPaths, ознакомьтесь с документацией по получению данных.

Когда следует использовать статическую генерацию?

Мы рекомендуем использовать статическую генерацию (с данными и без) везде, где это возможно, потому что ваша страница может быть собрана один раз и обслуживаться через CDN, что делает её намного быстрее, чем рендеринг на сервере при каждом запросе.

Вы можете использовать статическую генерацию для многих типов страниц, включая:

  • Маркетинговые страницы
  • Посты блога и портфолио
  • Списки товаров в электронной коммерции
  • Справка и документация

Задайте себе вопрос: "Могу ли я предварительно отрендерить эту страницу до запроса пользователя?" Если ответ "да", то следует выбрать статическую генерацию.

С другой стороны, статическая генерация не подходит, если вы не можете предварительно отрендерить страницу до запроса пользователя. Возможно, ваша страница отображает часто обновляемые данные, и её содержимое меняется при каждом запросе.

В таких случаях вы можете сделать следующее:

  • Использовать статическую генерацию с получением данных на стороне клиента: вы можете пропустить предварительный рендеринг некоторых частей страницы и затем использовать JavaScript на стороне клиента для их заполнения. Чтобы узнать больше об этом подходе, ознакомьтесь с документацией по получению данных.
  • Использовать рендеринг на стороне сервера (SSR): Next.js предварительно рендерит страницу при каждом запросе. Это будет медленнее, так как страница не может кэшироваться CDN, но предварительно отрендеренная страница всегда будет актуальной. Мы рассмотрим этот подход ниже.