Статическая генерация сайтов (SSG)
Примеры
- Пример с WordPress(Демо)
- Блог-стартер с использованием markdown-файлов (Демо)
- Пример с DatoCMS (Демо)
- Пример с TakeShape (Демо)
- Пример с Sanity (Демо)
- Пример с Prismic (Демо)
- Пример с Contentful (Демо)
- Пример с Strapi (Демо)
- Пример с Prepr (Демо)
- Пример с Agility CMS (Демо)
- Пример с Cosmic (Демо)
- Пример с ButterCMS (Демо)
- Пример с Storyblok (Демо)
- Пример с GraphCMS (Демо)
- Пример с Kontent (Демо)
- Пример с Builder.io (Демо)
- Пример с TinaCMS (Демо)
- Static Tweet (Демо)
- Пример с Enterspeed (Демо)
Если страница использует статическую генерацию, её HTML генерируется во время сборки. Это означает, что в продакшене HTML страницы создаётся при выполнении команды next build
. Этот HTML затем повторно используется при каждом запросе и может кэшироваться CDN.
В Next.js вы можете генерировать страницы статически с данными или без них. Рассмотрим оба случая.
Статическая генерация без данных
По умолчанию Next.js выполняет предварительный рендеринг страниц с помощью статической генерации без получения данных. Вот пример:
function About() {
return <div>About</div>
}
export default About
Обратите внимание, что этой странице не требуется получать внешние данные для предварительного рендеринга. В таких случаях Next.js генерирует один HTML-файл для каждой страницы во время сборки.
Статическая генерация с данными
Некоторые страницы требуют получения внешних данных для предварительного рендеринга. Существует два сценария, и один или оба могут применяться. В каждом случае вы можете использовать предоставляемые Next.js функции:
- Содержимое вашей страницы зависит от внешних данных: используйте
getStaticProps
. - Пути вашей страницы зависят от внешних данных: используйте
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()
// Передача данных поста в страницу через пропсы
return { props: { post } }
}
Чтобы узнать больше о работе getStaticPaths
, ознакомьтесь с документацией по получению данных.
Когда следует использовать статическую генерацию?
Мы рекомендуем использовать статическую генерацию (с данными и без) везде, где это возможно, потому что ваша страница может быть собрана один раз и обслуживаться CDN, что делает её намного быстрее, чем рендеринг сервером при каждом запросе.
Статическую генерацию можно использовать для многих типов страниц, включая:
- Маркетинговые страницы
- Посты блога и портфолио
- Списки товаров в интернет-магазинах
- Справка и документация
Задайте себе вопрос: "Могу ли я предварительно отрендерить эту страницу до запроса пользователя?" Если ответ "да", то следует выбрать статическую генерацию.
С другой стороны, статическая генерация не подходит, если вы не можете предварительно отрендерить страницу до запроса пользователя. Возможно, ваша страница отображает часто обновляемые данные, и её содержимое меняется при каждом запросе.
В таких случаях можно сделать следующее:
- Использовать статическую генерацию с получением данных на стороне клиента: можно пропустить предварительный рендеринг некоторых частей страницы и затем использовать JavaScript на стороне клиента для их заполнения. Подробнее об этом подходе читайте в документации по получению данных.
- Использовать рендеринг на стороне сервера (SSR): Next.js выполняет предварительный рендеринг страницы при каждом запросе. Это будет медленнее, так как страница не может кэшироваться CDN, но предварительно отрендеренная страница всегда будет актуальной. Мы рассмотрим этот подход далее.