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

Примеры

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

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

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

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

function About() {
  return <div>О нас</div>
}

export default About

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

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

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

  1. Содержимое вашей страницы зависит от внешних данных: используйте getStaticProps.
  2. Пути (paths) вашей страницы зависят от внешних данных: используйте 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, но предварительно отрендеренная страница всегда будет актуальной. Мы рассмотрим этот подход далее.