From 383817916dda1d4d7c71cbe5b1fc365fd759f76b Mon Sep 17 00:00:00 2001 From: neodk2004 Date: Thu, 20 Aug 2026 19:00:35 +0200 Subject: [PATCH] perf(landing): scope Clerk provider + fix contrast/landmark on marketing page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moves ClerkThemeProvider from the root layout into (app)/layout.tsx and (auth)/layout.tsx — it was previously mounted globally, shipping the ~240 KiB Clerk client SDK to every route including the public marketing page. Only Sidebar's UserButton and the (auth) sign-in/sign-up forms actually need client-side Clerk context; server-side auth() calls are unaffected since they read from proxy.ts's clerkMiddleware, not React context. Also fixes two WCAG AA contrast failures on the hero/header CTAs (orange-500/600 -> orange-700, ~2.8:1/3.6:1 -> ~5.5:1) and adds a missing
landmark around the landing page content. Source: PageSpeed Insights audit, mobile Performance 70 -> targets >90. --- src/app/(app)/layout.tsx | 31 +++++++++++++++--------- src/app/(auth)/layout.tsx | 13 +++++++--- src/app/layout.tsx | 19 ++++++--------- src/app/page.tsx | 4 ++- src/components/landing/LandingHeader.tsx | 2 +- 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx index 880859a..6d87300 100644 --- a/src/app/(app)/layout.tsx +++ b/src/app/(app)/layout.tsx @@ -8,6 +8,7 @@ import { ActivePetInitializer } from "@/components/layout/ActivePetInitializer"; import { ThemeInitializer } from "@/components/layout/ThemeInitializer"; import { LegalUpdateBanner } from "@/components/legal/LegalUpdateBanner"; import { BroadcastBanner } from "@/components/broadcast/BroadcastBanner"; +import { ClerkThemeProvider } from "@/components/providers/ClerkThemeProvider"; import { recordVisit } from "@/lib/visit-tracking"; /** @@ -22,6 +23,10 @@ import { recordVisit } from "@/lib/visit-tracking"; * Security (T-2-03): pets.list scoped by ctx.userId — no cross-owner pet leakage. * * ActivePetProvider is already mounted in root layout.tsx so we do NOT re-wrap here. + * + * ClerkThemeProvider (client-side Clerk SDK) is scoped to this layout instead of + * root layout.tsx — only Sidebar's needs it, so the public marketing + * page and legal routes no longer ship the ~240 KiB Clerk bundle (SpeedUp-Plan P0). */ export default async function AppLayout({ children, @@ -69,19 +74,21 @@ export default async function AppLayout({ } return ( -
- - - - - {/* Desktop sidebar — hidden on mobile */} - + +
+ + + + + {/* Desktop sidebar — hidden on mobile */} + - {/* Main content area */} -
{children}
+ {/* Main content area */} +
{children}
- {/* Mobile bottom nav — hidden on desktop */} - -
+ {/* Mobile bottom nav — hidden on desktop */} + +
+ ); } diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx index 8db9f34..6cbb3f1 100644 --- a/src/app/(auth)/layout.tsx +++ b/src/app/(auth)/layout.tsx @@ -1,8 +1,13 @@ +import { ClerkThemeProvider } from "@/components/providers/ClerkThemeProvider"; + /** * Auth layout — centers all auth pages in a 448px card. * * No sidebar or navigation — auth pages are standalone experiences. * Applied to all routes under /(auth)/. + * + * ClerkThemeProvider is scoped here (not root layout.tsx) — the / + * components need it, but the public marketing page doesn't (SpeedUp-Plan P0). */ export default function AuthLayout({ children, @@ -10,8 +15,10 @@ export default function AuthLayout({ children: React.ReactNode; }) { return ( -
-
{children}
-
+ +
+
{children}
+
+
); } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 0003b8e..bcdf88c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,7 +5,6 @@ import { NextIntlClientProvider } from "next-intl"; import { getLocale, getMessages } from "next-intl/server"; import { TRPCReactProvider } from "@/trpc/client"; import { ActivePetProvider } from "@/context/ActivePetContext"; -import { ClerkThemeProvider } from "@/components/providers/ClerkThemeProvider"; import { Toaster } from "@/components/ui/sonner"; import "./globals.css"; @@ -54,16 +53,14 @@ export default async function RootLayout({ > - - - - - {children} - - - - - + + + + {children} + + + + diff --git a/src/app/page.tsx b/src/app/page.tsx index 34c5a03..b67a3d4 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -43,6 +43,7 @@ export default async function RootPage() {
+
{/* Hero */}
@@ -64,7 +65,7 @@ export default async function RootPage() {
{t("getStarted")} @@ -180,6 +181,7 @@ export default async function RootPage() {
+
{/* Footer — repeats the navbar */} diff --git a/src/components/landing/LandingHeader.tsx b/src/components/landing/LandingHeader.tsx index 77b7730..92db18f 100644 --- a/src/components/landing/LandingHeader.tsx +++ b/src/components/landing/LandingHeader.tsx @@ -45,7 +45,7 @@ export async function LandingHeader() { {t("navSignUp")}