From e5cae9b49dc2bcef484809cba4bd57f6fb5510e0 Mon Sep 17 00:00:00 2001 From: Nick Szaunig Date: Sat, 19 Sep 2026 04:47:43 +0200 Subject: [PATCH] perf: Firmendaten und Social-Links je Request nur noch einmal laden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getCompanyInfo() wurde bei JEDEM Seitenaufruf mehrfach ausgefuehrt: das Root-Layout braucht es zweimal (einmal in generateMetadata, einmal fuer das LocalBusiness-Schema im Rumpf), dazu kommt fast jede Seite mit einem eigenen Aufruf. Jeder davon war eine eigene Datenbankabfrage ueber dieselben zehn Schluessel — dreimal dasselbe Ergebnis pro gerenderter Seite, auf jeder Seite des Shops. Beide Funktionen sind jetzt in React-cache() gehuellt. Die Deduplizierung gilt je Request und ist KEIN serverweiter Zwischenspeicher: eine Aenderung im Admin-Bereich wirkt unveraendert sofort, es gibt nichts zu invalidieren. Beide Funktionen nehmen keine Argumente, damit greift die Deduplizierung zuverlaessig — cache() unterscheidet Aufrufe anhand ihrer Argumente. Geprueft: "next build" laeuft durch, tsc 0 Fehler, vitest 328/328 gruen, eslint 0 Warnungen. Nicht geaendert, aber geprueft: die Admin-Listen ohne "take" (Chargen, Ernten, Gutscheine, Inhalte, Produkte, Versandstaffeln) betreffen ausnahmslos kleine, langsam wachsende Tabellen — eine Begrenzung waere dort Vorratsarbeit. Die Listen auf den wachsenden Tabellen (Bestellungen, Bewertungen, Audit-Log, Retouren, Anfragen, Benutzer) sind bereits begrenzt. Co-Authored-By: Claude Opus 5 (1M context) --- src/lib/company-info.ts | 18 ++++++++++++++++-- src/lib/social-links.ts | 9 +++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/lib/company-info.ts b/src/lib/company-info.ts index 0e0a30e..f859c64 100644 --- a/src/lib/company-info.ts +++ b/src/lib/company-info.ts @@ -1,3 +1,4 @@ +import { cache } from "react"; import { siteConfig } from "@/lib/site-config"; import { getContentValues } from "@/lib/content"; @@ -20,8 +21,21 @@ const COMPANY_KEYS = [ * Konsumenten nur `siteConfig` gegen `await getCompanyInfo()` tauschen * muessen. domain/country bleiben aus siteConfig (keine Content-Felder, * echte Infra-Werte). + * + * In React-cache() gehuellt, weil diese Funktion je Seitenaufruf MEHRFACH + * aufgerufen wird: allein das Root-Layout braucht sie zweimal (einmal fuer + * generateMetadata, einmal fuer das LocalBusiness-Schema im Rumpf), dazu + * kommt fast jede Seite mit einem eigenen Aufruf. Ohne die Huelle war das je + * Aufruf eine eigene Datenbankabfrage ueber dieselben zehn Schluessel — + * dreimal dasselbe Ergebnis pro gerenderter Seite. + * + * cache() ist auf EINEN Request begrenzt und kein serverweiter Zwischen- + * speicher: eine Aenderung im Admin-Bereich wirkt unveraendert sofort, es + * gibt nichts zu invalidieren. Die Funktion nimmt keine Argumente, damit + * greift die Deduplizierung zuverlaessig (cache() unterscheidet Aufrufe + * anhand der Argumente). */ -export async function getCompanyInfo() { +export const getCompanyInfo = cache(async () => { // Firmendaten sind nicht lokalisiert (siehe content-registry.ts) — die // uebergebene Locale wirkt sich fuer diese Schluessel nicht aus. const v = await getContentValues([...COMPANY_KEYS], "de"); @@ -41,4 +55,4 @@ export async function getCompanyInfo() { city: v["company.city"], }, }; -} +}); diff --git a/src/lib/social-links.ts b/src/lib/social-links.ts index 1625456..69b9aad 100644 --- a/src/lib/social-links.ts +++ b/src/lib/social-links.ts @@ -1,3 +1,4 @@ +import { cache } from "react"; import { getContentValues } from "@/lib/content"; const SOCIAL_KEYS = ["social.tiktok", "social.youtube", "social.instagram"] as const; @@ -13,12 +14,16 @@ export interface SocialLinks { * Media") — nicht lokalisiert, wie Firmendaten (company-info.ts). Ein leerer * String bedeutet "kein Profil hinterlegt"; der Footer rendert dann kein * Icon fuer diese Plattform (siehe components/site-footer.tsx Footer()). + * + * In React-cache() gehuellt, aus demselben Grund wie getCompanyInfo: die + * Deduplizierung gilt je Request, nicht serverweit — Aenderungen im + * Admin-Bereich wirken unveraendert sofort. */ -export async function getSocialLinks(): Promise { +export const getSocialLinks = cache(async (): Promise => { const v = await getContentValues([...SOCIAL_KEYS], "de"); return { tiktok: v["social.tiktok"], youtube: v["social.youtube"], instagram: v["social.instagram"], }; -} +});