Загрузка...
Загрузка...
SSG (Static Site Generation) это стратегия рендеринга, при которой HTML-страницы генерируются один раз на этапе сборки (next build). После деплоя эти страницы раздаются как обычные статические файлы через CDN.
Next.js вызывает серверный компонент или getStaticProps, выполняет все запросы к API/БД и генерирует HTML-файлы для каждой страницы.
Готовые HTML-файлы размещаются на CDN. Сервер больше не участвует в генерации страниц.
Когда пользователь открывает страницу, CDN мгновенно отдает готовый HTML. Никакого ожидания сервера, никакого рендеринга в реальном времени.
В App Router (Next.js 13+) SSG является поведением по умолчанию. Если компонент не использует динамические данные, Next.js автоматически сгенерирует его статически:
// app/docs/page.tsx
// Эта страница будет сгенерирована статически при сборке
export default async function DocsPage() {
const res = await fetch('https://api.hackfrontend.com/docs')
const docs = await res.json()
return (
<ul>
{docs.map((doc: { slug: string; title: string }) => (
<li key={doc.slug}>{doc.title}</li>
))}
</ul>
)
}
По умолчанию fetch в серверных компонентах кеширует результат. Это эквивалент SSG: запрос выполняется один раз при сборке.
Для динамических страниц нужно заранее указать, какие пути генерировать. Для этого используется generateStaticParams:
// app/docs/[slug]/page.tsx
export async function generateStaticParams() {
const res = await fetch('https://api.hackfrontend.com/docs')
const docs = await res.json()
return docs.map((doc: { slug: string }) => ({
slug: doc.slug
}))
}
export default async function DocPage({
params
}: {
params: { slug: string }
}) {
const res = await fetch(
`https://api.hackfrontend.com/docs/${params.slug}`
)
const doc = await res.json()
return (
<article>
<h1>{doc.title}</h1>
<div>{doc.content}</div>
</article>
)
}
При сборке Next.js вызовет generateStaticParams, получит список slug'ов и сгенерирует отдельный HTML для каждого.
В Pages Router для SSG используется getStaticProps:
// pages/docs/index.tsx
export async function getStaticProps() {
const res = await fetch('https://api.hackfrontend.com/docs')
const docs = await res.json()
return {
props: { docs }
}
}
export default function DocsPage({ docs }) {
return (
<ul>
{docs.map(doc => (
<li key={doc.slug}>{doc.title}</li>
))}
</ul>
)
}
Для динамических роутов дополнительно используется getStaticPaths:
// pages/docs/[slug].tsx
export async function getStaticPaths() {
const res = await fetch('https://api.hackfrontend.com/docs')
const docs = await res.json()
return {
paths: docs.map(doc => ({ params: { slug: doc.slug } })),
fallback: false
}
}
export async function getStaticProps({ params }) {
const res = await fetch(
`https://api.hackfrontend.com/docs/${params.slug}`
)
const doc = await res.json()
return { props: { doc } }
}
Подходит:
Не подходит:
На собеседовании:
Частый вопрос: "А что если данные устарели после сборки?". Ответ: для этого существует ISR (Incremental Static Regeneration), который позволяет обновлять статические страницы без полной пересборки.