объясняет, как сайт документации обеспечивает быструю загрузку статических страниц, сохраняя функциональность режима редактирования CMS
В этом руководстве объясняется, как сайт документации обеспечивает быструю загрузку статических страниц, сохраняя при этом функциональность режима редактирования CMS.
Мы используем два маршрута для одного и того же контента:
app/
├── [...slug]/page.tsx # Продакшн: force-static (быстро)
└── preview/[...slug]/page.tsx # Режим редактирования: force-dynamic (читает searchParams)
Промежуточное ПО прокси прозрачно переписывает запросы в режиме редактирования:
Пользователь запрашивает: /en/headless/quickstart?edit_mode=true
↓
Прокси обнаруживает ?edit_mode=true
↓
Внутренний редирект на: /preview/en/headless/quickstart?edit_mode=true
↓
Динамический маршрут рендерится с оболочками редактирования
Пользователь никогда не увидит /preview в своём URL — это внутреннее переписывание.
// app/[...slug]/page.tsx
export const dynamic = 'force-static';
export const revalidate = 60;
export default async function Page({ params }) {
// Нет searchParams — страница полностью статическая
// app/preview/[...slug]/page.tsx
export const dynamic = 'force-dynamic';
export default async function PreviewPage({ params, searchParams }) {
// searchParams доступны — можно определить edit_mode
return <ParametricRoutePage params={params
?edit_mode=true из URL// src/proxy.ts
export const proxy = async (request: NextRequest) => {
const { pathname, searchParams } = request.nextUrl;
const editMode = searchParams.get('edit_mode');
| Сценарий | Время ответа | Рендеринг |
|---|---|---|
| Страница продакшна (из кэша) | ~50-100ms | Статическая из CDN |
| Страница продакшна (устаревшая) | ~50-100ms + фоновое обновление | Статическая, затем ISR |
| Режим редактирования | ~500-1500ms | Динамический SSR |
Параметр revalidate = 60 включает ISR. Это НЕ означает, что страницы пересчитываются каждые 60 секунд.
ISR использует шаблон stale-while-revalidate:
Поступает запрос:
→ Кэшированная страница моложе 60 с? → Отдаём из кэша (мгновенно)
→ Кэшированная страница старше 60 с? → Отдаём устаревший кэш (мгновенно)
+ выполняем повторную валидацию в фоне для следующего запроса
Нет запросов = Нет перерасчёта. Никогда.
Пример:
Интервал в 60 секунд — это страховочная сетка. В идеале мы бы использовали повторную валидацию по требованию через вебхуки при изменении контента в CMS.
| Сценарий использования | URL | Используемый маршрут |
|---|---|---|
| Обычный просмотр | /en/headless/quickstart | Статический |
| Конструктор шаблонов CMS | /en/headless/quickstart?edit_mode=true | Предпросмотр (через переписывание) |
| Предпросмотр AI-блока | /en/headless/quickstart?ai_preview=1 | Предпросмотр (через переписывание) |
Простой подход (без force-static, без маршрута preview) работает, но медленный:
// Простой подход — работает, но ~1-2 с на запрос
export default async function Page({ params, searchParams }) {
return <ParametricRoutePage params={params} searchParams={searchParams} />;
}
Он рендерит динамически на каждый запрос. Для сайта документации с большим количеством страниц это означает:
Архитектура с двумя маршрутами даёт нам лучшее из обоих миров: статическую скорость для читателей и динамическую функциональность для редакторов.