perf(cms-client+ssr): O(1)-Slug-Lookup, Sparse-Pages, höhere TTLs, Cache-Control, Parallel-Resolver
- getPageBySlug: neuer Filter-Lookup-Pfad (?slug=X&_fields=_slug) als primärer Fallback — O(1) statt komplette Page-Liste laden. Vollständige Liste nur noch als Last-Resort-Safety-Net. Skaliert egal wieviele Pages. - getPages: Sparse-Projektion via _fields (8 Felder statt Voll-Resolve- Tree) → ~90 % kleinere Payload pro Call. - CACHE_TTL hoch (Webhooks purgen eh): page/page_config/navigation/footer/ fullwidth_banner/translation/openapi → 1h; tag/text_fragment → 30min; post → 10min. Spart Cold-Loads + CMS-Roundtrips. - [...slug]/+page.server.ts: Cache-Control public, s-maxage=60, stale-while-revalidate=600 für öffentliche Pages (Caddy/Browser cachen). Preview-Branch bleibt private/no-store. - Resolver parallelisiert: Calendar/Deadline/StellingnahmeGenerator starten sofort parallel zu PostOverview, nicht erst danach. - Icon-Subset um clock-remove-outline ergänzt (Frist-abgelaufen-Banner). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,14 @@ export const load: PageServerLoad = async ({ params, locals, fetch, url, setHead
|
||||
'cache-control': 'private, no-store, max-age=0',
|
||||
'x-robots-tag': 'noindex, nofollow',
|
||||
});
|
||||
} else {
|
||||
// Public Pages: Caddy/CDN + Browser cachen 60s, stale-while-revalidate
|
||||
// erlaubt 10min Sofort-Lieferung während im Hintergrund neu geholt wird.
|
||||
// CMS-Mutationen lösen Webhook → Frontend-Content-Cache-Purge aus, der
|
||||
// Edge-Cache läuft per TTL aus (kurze Inkonsistenz akzeptabel).
|
||||
setHeaders({
|
||||
'cache-control': 'public, s-maxage=60, stale-while-revalidate=600',
|
||||
});
|
||||
}
|
||||
|
||||
const page = await getPageBySlug(slug, {
|
||||
@@ -58,15 +66,20 @@ export const load: PageServerLoad = async ({ params, locals, fetch, url, setHead
|
||||
// Tree — vor den Block-Resolvern erledigen, die danach gegen mutierte
|
||||
// Blocks arbeiten.
|
||||
await resolveContentImages(page);
|
||||
// PostOverview liefert tagsMap, den SearchableText braucht. Calendar +
|
||||
// DeadlineBanner sind unabhängig → parallel mit SearchableText laufen.
|
||||
const tagsMap = await resolvePostOverviewBlocks(page);
|
||||
await Promise.all([
|
||||
resolveSearchableTextBlocks(page, tagsMap),
|
||||
// PostOverview→SearchableText hat Daten-Abhängigkeit (tagsMap). Calendar,
|
||||
// DeadlineBanner und StellingnahmeGenerator sind unabhängig — sofort
|
||||
// parallel starten, nicht erst nach PostOverview warten.
|
||||
const postOverviewPromise = resolvePostOverviewBlocks(page);
|
||||
const independentResolvers = Promise.all([
|
||||
resolveCalendarBlocks(page),
|
||||
resolveDeadlineBannerBlocks(page),
|
||||
resolveStellingnahmeGeneratorBlocks(page),
|
||||
]);
|
||||
const tagsMap = await postOverviewPromise;
|
||||
await Promise.all([
|
||||
resolveSearchableTextBlocks(page, tagsMap),
|
||||
independentResolvers,
|
||||
]);
|
||||
sanitizeBlocks(page);
|
||||
|
||||
// Top-Bild: bevorzugt neues inline-Feld `topImage`, sonst Legacy via
|
||||
|
||||
Reference in New Issue
Block a user