improvement(landing): optimize core web vitals and accessibility#4193
improvement(landing): optimize core web vitals and accessibility#4193emir-karabeg merged 3 commits intostagingfrom
Conversation
Code-split AuthModal and DemoRequestModal via next/dynamic across 7 landing components to move auth-client bundle (~150-250KB) out of the initial JS payload. Replace useSession import in navbar with direct SessionContext read to avoid pulling the entire better-auth client into the landing page bundle. Add immutable cache header for content-hashed _next/static assets. Defer PostHog session recording until user identification to avoid loading the recorder (~80KB) on anonymous visits. Fix accessibility issues flagged by Lighthouse: add missing aria-label on preview submit button, add inert to aria-hidden ReactFlow wrapper, set decorative alt on logos inside labeled links, disambiguate duplicate footer API links. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Updates the landing navbar to read auth state directly from Tightens analytics/a11y behavior: disables PostHog session recording at init and starts recording only after user identification, adds missing Reviewed by Cursor Bugbot for commit 9bc82bf. Configure here. |
|
@cursor review |
Greptile SummaryThis PR reduces initial JS payload on the landing page by code-splitting
Confidence Score: 5/5Safe to merge — all code changes are correct; one stated optimization (static asset cache headers) is missing from the diff but doesn't affect correctness. All four optimizations are structurally sound: dynamic imports use the correct named-export pattern with SSR enabled, the SessionContext swap uses safe fallback values, PostHog deferral is guarded against duplicate recording calls, and accessibility fixes are correct. The only finding is a P2 gap between the PR description and the actual changeset (missing No files require special attention; the missing change is in Important Files Changed
Sequence DiagramsequenceDiagram
participant Browser
participant Next.js SSR
participant SessionProvider
participant PostHogProvider
participant PostHog
Browser->>Next.js SSR: Request landing page
Next.js SSR-->>Browser: HTML (navbar buttons, hero CTAs rendered)
Note over Browser: AuthModal/DemoRequestModal JS NOT in initial bundle
Browser->>PostHogProvider: useEffect → posthog.init(disable_session_recording: true)
Browser->>SessionProvider: useEffect → loadSession()
SessionProvider-->>Browser: session data returned
alt User is authenticated
SessionProvider->>PostHog: posthog.identify(user.id, ...)
SessionProvider->>PostHog: sessionRecordingStarted()? → false
SessionProvider->>PostHog: startSessionRecording()
else Anonymous visitor
SessionProvider->>PostHog: posthog.reset()
Note over PostHog: Recording stays disabled (~80KB saved)
end
Browser->>Browser: User clicks CTA button
Browser->>Next.js: dynamic import → AuthModal chunk loaded
Browser-->>Browser: Modal opens
Reviews (2): Last reviewed commit: "fix(config): remove redundant _next/stat..." | Re-trigger Greptile |
…efetch The effect fires on every session reload (e.g., subscription upgrade). Calling startSessionRecording() while already recording fragments the session in the analytics dashboard. Add sessionRecordingStarted() guard so recording only starts once per page lifecycle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Next.js already sets Cache-Control: public, max-age=31536000, immutable on _next/static assets natively and this cannot be overridden. The custom rule was redundant on Vercel and conflicted with the extension-based rule on self-hosted deployments due to last-match-wins ordering. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@cursor review |
|
@greptile |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 9bc82bf. Configure here.
Summary
AuthModalandDemoRequestModalvianext/dynamicacross 7 landing components to move the auth-client bundle out of the initial JS payloaduseSessionimport in navbar with directSessionContextread to avoid pulling the entire better-auth client into the landing page bundleCache-Controlheader for content-hashed_next/staticassetsaria-label,inertonaria-hiddenwrapper, decorativealton logos, duplicate link labelsContext
PageSpeed Insights (Apr 15, 2026) shows sim.ai failing Core Web Vitals — LCP 3.4s (mobile) / 2.6s (desktop), Performance score 75 (mobile) / 82 (desktop). Root causes: ~675KB unused JS on landing page, 3.0s JS execution time, poor cache lifetimes for hashed static assets, and PostHog recorder loading on anonymous visits. Accessibility score was 88 (desktop) / 92 (mobile) due to missing labels and focusable elements inside
aria-hiddencontainers.Changes
Code-split auth modals (
hero.tsx,navbar.tsx,features.tsx,collaboration.tsx,pricing.tsx,footer-cta.tsx,landing-preview-panel.tsx)import { AuthModal }/import { DemoRequestModal }withdynamic()(SSR preserved, client-side code-split)Navbar session optimization (
navbar.tsx)import { useSession } from '@/lib/auth/auth-client'withuseContext(SessionContext)from session-provideruseSessionin auth-client.ts is a thin wrapper around the same context, but importing it forces bundling the entirecreateAuthClient()call with all pluginsCache headers (
next.config.ts)Cache-Control: public, max-age=31536000, immutablefor/_next/static/:path*PostHog session recording deferral (
posthog-provider.tsx,session-provider.tsx)disable_session_recording: trueto PostHog init config — prevents recorder JS (~80KB) from loading on anonymous visitsposthog.startSessionRecording()afterposthog.identify()for authenticated usersAccessibility fixes (
footer.tsx,navbar.tsx,landing-preview-home.tsx,templates.tsx)alt=''on logo images inside links that already havearia-labeland sr-only text (image is decorative)aria-label='Submit message'to icon-only button in landing previewinertattribute alongsidearia-hidden='true'on ReactFlow preview wrapper to prevent focusable descendants from tab orderType of Change
Testing
ssr: false— buttons visible in initial HTML)SessionContextprovided by root layoutSessionProviderdisable_session_recordingandstartSessionRecording()verified against posthog-js 1.364.4 type definitions_next/staticcache rule only applies to content-hashed assets — safe for immutable cachingChecklist