All Systems Operational
Powered By
profound-logo
profound-logoProfound CMS
⌘K
Admin

Renderowanie statyczne z obsługą trybu edycji

wyjaśnia, jak strona dokumentacji osiąga szybkie statyczne ładowanie stron, zachowując funkcjonalność trybu edycji CMS

Continue Reading
Previous‹Konfiguracja Proxy Panelu AdministracyjnegoNextSkryptowanie W Kreatorze Szablonów›

Hybryda

Projekt rendereraParametryczne RoutowanieTypy komponentówSseKonfiguracja Proxy Panelu AdministracyjnegoRenderowanie statyczne z obsługą trybu edycjiSkryptowanie W Kreatorze SzablonówCreate Profound Next

Bezgłowy

Szybki startJson I Kod ClaudeKomponent Zod Pobieranie

Mcp

Mcp

Funkcje Cms

Funkcja Szablon DokumentacjiFunkcja Kreator SzablonówFeat TłumaczFunkcja Organizacja

Motywacja

Nasze podejście

Terminologia

Hybrydowe Vs Headless

Ten przewodnik wyjaśnia, w jaki sposób strona dokumentacji osiąga szybkie statyczne ładowanie stron, jednocześnie zachowując funkcjonalność trybu edycji CMS.

Architektura podwójnych tras

Używamy dwóch tras dla tej samej zawartości:

app/
├── [...slug]/page.tsx          # Produkcja: force-static (szybko)
└── preview/[...slug]/page.tsx  # Tryb edycji: force-dynamic (odczytuje searchParams)

Pośrednik proxy w warstwie middleware przezroczysto przepisuje żądania trybu edycji:

Żądanie użytkownika: /en/headless/quickstart?edit_mode=true
       ↓
Proxy wykrywa ?edit_mode=true
       ↓
Wewnętrzne przepisanie na: /preview/en/headless/quickstart?edit_mode=true
       ↓
Dynamiczna trasa renderuje z opakowaniami edycji

Użytkownik nigdy nie widzi /preview w swoim adresie URL – to wewnętrzne przepisanie.

Jak to działa

Ścieżka produkcyjna (domyślna)

// app/[...slug]/page.tsx
export const dynamic = 'force-static';
export const revalidate = 60;

export default async function Page({ params }) {
  // Brak searchParams – strona jest w pełni statyczna
  
  • Strony są wstępnie renderowane w czasie budowania
  • Dostarczane natychmiast z pamięci podręcznej CDN (edge)
  • Odświeżane co 60 sekund (ISR) jako zabezpieczenie

Ścieżka trybu edycji

// app/preview/[...slug]/page.tsx
export const dynamic = 'force-dynamic';

export default async function PreviewPage({ params, searchParams }) {
  // searchParams dostępne – można wykryć edit_mode
  return <ParametricRoutePage params={params
  • Renderowana przy każdym żądaniu
  • Może odczytać ?edit_mode=true z adresu URL
  • Renderuje się z edytowalnymi obramowaniami i konturami bloków CMS

Przepisanie przez proxy

// src/proxy.ts
export const proxy = async (request: NextRequest) => {
  const { pathname, searchParams } = request.nextUrl;

  const editMode = searchParams.get('edit_mode');

Porównanie wydajności

ScenariuszCzas odpowiedziRenderowanie
Strona produkcyjna (z pamięci podręcznej)~50-100 msStatyczna z CDN
Strona produkcyjna (przeterminowana)~50-100 ms + odświeżenie w tleStatyczna, potem ISR
Tryb edycji~500-1500 msDynamiczne SSR

Zrozumienie ISR (Incremental Static Regeneration)

Ustawienie revalidate = 60 włącza ISR. To NIE oznacza, że strony są przeliczane co 60 sekund.

ISR wykorzystuje schemat stale-while-revalidate:

Żądanie przychodzi:
  → Czy zbuforowana strona ma mniej niż 60 s? → Dostarcz z pamięci podręcznej (natychmiast)
  → Czy zbuforowana strona ma więcej niż 60 s? → Dostarcz nieświeżą pamięć podręczną (natychmiast)
                                + odśwież w tle na potrzeby następnego żądania

Brak żądań = brak ponownego przeliczania. Nigdy.

Przykład:

  • Strona zbuforowana o 10:00
  • Brak odwiedzających do 15:00
  • Pierwszy odwiedzający o 15:00 natychmiast otrzymuje nieświeżą pamięć podręczną
  • Następuje odświeżenie w tle, kolejny odwiedzający dostaje świeżą treść

Okno 60 sekund to zabezpieczenie. Idealnie używalibyśmy odświeżania na żądanie poprzez webhooki, gdy zmienia się zawartość w CMS.

Kiedy używać każdej z tras

Przypadek użyciaURLUżyta trasa
Zwykłe przeglądanie/en/headless/quickstartStatyczna
Kreator szablonów CMS/en/headless/quickstart?edit_mode=truePodgląd (przez przepisanie)
Podgląd bloku AI/en/headless/quickstart?ai_preview=1Podgląd (przez przepisanie)

Dlaczego po prostu nie używać renderowania dynamicznego?

Proste podejście (bez force-static, bez trasy podglądu) działa, ale jest wolne:

// Proste podejście – działa, ale ~1-2 s na żądanie
export default async function Page({ params, searchParams }) {
  return <ParametricRoutePage params={params} searchParams={searchParams} />;
}

To renderuje dynamicznie przy każdym żądaniu. W przypadku strony z dokumentacją z wieloma stronami oznacza to:

  • Zimne starty na każdej stronie
  • Brak korzyści z buforowania na brzegu CDN
  • Czas ładowania 1-2 sekundy zamiast milisekund

Architektura dwóch tras daje nam to, co najlepsze z obu światów: statyczną szybkość dla czytelników i dynamiczną funkcjonalność dla redaktorów.

return
<
ParametricRoutePage
params
={
params
} />;
}
}
searchParams
={
searchParams
} />;
}
const
aiPreview
=
searchParams.
get
(
'ai_preview'
);
// Przepisz na trasę preview, jeśli obecne jest edit_mode lub ai_preview
if ((editMode === 'true' || editMode === '1' || aiPreview) && !pathname.startsWith('/preview')) {
const url = request.nextUrl.clone();
url.pathname = `/preview${pathname}`;
return NextResponse.rewrite(url);
}
return NextResponse.next();
};