Что такое ISR?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
ISR (Incremental Static Regeneration) в Next.js
ISR — это одна из самых мощных фишек Next.js для создания высокопроизводительных статических сайтов, которые автоматически обновляются. Это гибрид между статическим сайтом и динамическим приложением.
Что такое ISR?
ISR (Incremental Static Regeneration) — это стратегия кэширования в Next.js, которая позволяет:
- Генерировать статические страницы при билде
- Автоматически регенерировать эти страницы в background
- Обновлять только те страницы, которые изменились
- Не требует перестройки всего проекта
Задача была решена в Next.js 9.5, и это революционизировало подход к dynamic контенту.
Как работает ISR
// pages/blog/[slug].tsx
export async function getStaticProps({ params }) {
const post = await fetchBlogPost(params.slug);
return {
props: {
post,
},
revalidate: 60, // ISR: регенерировать каждые 60 секунд
};
}
export async function getStaticPaths() {
// На время билда генерируем популярные посты
const posts = await fetchPopularPosts();
return {
paths: posts.map(p => ({ params: { slug: p.slug } })),
fallback: 'blocking', // Новые посты генерируются on-demand
};
}
export default function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
Режимы ISR
1. Time-based ISR (Самый популярный)
return {
props: { data },
revalidate: 3600, // Регенерировать каждый час
};
Это означает:
- Первый пользователь получает кэшированную версию
- На background запускается регенерация
- Следующие пользователи через час получат новую версию
2. On-demand ISR (API-triggered)
// pages/api/revalidate.ts
export default async function handler(req, res) {
// Проверка секретного токена
if (req.query.secret !== process.env.REVALIDATE_SECRET) {
return res.status(401).json({ message: 'Invalid token' });
}
try {
// Регенерировать конкретную страницу
await res.revalidate('/blog/my-post');
return res.json({ revalidated: true });
} catch (err) {
return res.status(500).send('Error revalidating');
}
}
Так можно регенерировать страницу по запросу (например, после обновления в CMS):
# Когда пост обновлен в CMS, вызываем
curl -X POST "https://example.com/api/revalidate?secret=TOKEN" \
-H "Content-Type: application/json" \
--data '{"path": "/blog/updated-post"}'
3. Fallback режимы
return {
paths: somePages,
fallback: false, // 404 если страницы нет
fallback: true, // SSR если страницы нет, потом кэшируется
fallback: 'blocking', // SSR на сервере, потом кэшируется
};
Практические примеры
Пример 1: Блог с часто обновляемыми постами
export async function getStaticProps({ params }) {
const post = await db.posts.findBySlug(params.slug);
// Популярные посты (очень часто читаемые) обновляются каждые 5 минут
const isPopular = post.views > 10000;
const revalidate = isPopular ? 300 : 3600; // 5 min или 1 hour
return {
props: { post },
revalidate,
};
}
Пример 2: E-commerce каталог товаров
export async function getStaticProps({ params }) {
const product = await fetchProduct(params.id);
// Цены часто меняются — 15 минут
// Описание редко меняется — 1 день
return {
props: { product },
revalidate: 15 * 60,
};
}
Пример 3: Интеграция с CMS
// pages/api/revalidate-webhook.ts
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).end();
}
// Webhook от Sanity CMS при обновлении контента
const { slug } = req.body;
try {
await res.revalidate(`/blog/${slug}`);
return res.json({ message: `Revalidated /blog/${slug}` });
} catch (e) {
return res.status(500).send('Error revalidating');
}
}
Теперь в Sanity настраиваем webhook на этот endpoint, и при каждом обновлении поста он автоматически регенерируется.
ISR vs SSR vs SSG
| Подход | Build time | Runtime | Cache | Best for |
|---|---|---|---|---|
| SSG (Static Generation) | Долго | Быстро | forever | Static контент |
| ISR | Быстро | Быстро | revalidate | Dynamic контент с кэшем |
| SSR (Server-Side Render) | - | Медленно | none | Real-time контент |
Преимущества ISR
- Скорость — статические файлы раздаются из CDN со скоростью света
- Масштабируемость — не нужно вычислять для каждого пользователя
- Отказоустойчивость — если БД упадет, старая версия все еще работает
- SEO — поисковики видят готовый HTML, а не JavaScript
- Cost — статический хостинг намного дешевле, чем server-render
Недостатки ISR
- Delay — между обновлением и появлением на сайте есть lag
- Сложность — нужно управлять revalidate интервалами
- Build size — для сайта с миллионом страниц problematic
- On-demand limited — не безлимитные регенерации (на Vercel есть лимиты)
ISR vs On-Demand ISR
Time-based ISR:
revalidate: 60 // Каждый час проверяет
Проблема: если контент обновился за 30 минут до revalidate, то пользователь еще 30 минут видит старую версию.
On-Demand ISR:
await res.revalidate('/path')
Решение: мгновенно регенерировать по запросу из CMS webhook.
Лучшая практика: комбинировать обе
return {
props: { post },
revalidate: 3600, // fallback на регенерацию каждый час
};
// + webhook для мгновенной регенерации при изменении
Хостинг на Vercel
Vercel оптимизирована для ISR:
- Автоматические регенерации работают в background
- Не нужен долгоживущий server
- Кэш хранится на Edge locations (CDN)
- Есть dashboard для мониторинга
// На Vercel это просто работает
export async function getStaticProps() {
return {
props: {},
revalidate: 60,
};
}
ISR на других хостингах
Другие платформы требуют self-hosted сервер для фоновых регенераций:
- Railway, Render, Dokku
- Используйте On-Demand ISR вместе с webhooks
// Без фоновых регенераций используйте on-demand
await res.revalidate('/path');
Заключение
ISR — это лучший выбор для большинства современных веб-приложений:
- Нужна скорость SSG
- Но контент динамический
- И не нужен real-time update
ISR позволяет получить лучшее из обоих миров: производительность статических сайтов с гибкостью динамического контента.