Skip to content

perf: Remove Framer Motion from critical path on expertise pages#106

Merged
vibemarketerpromax merged 3 commits intomainfrom
perf/lighthouse-optimization
Feb 19, 2026
Merged

perf: Remove Framer Motion from critical path on expertise pages#106
vibemarketerpromax merged 3 commits intomainfrom
perf/lighthouse-optimization

Conversation

@vibemarketerpromax
Copy link
Collaborator

Summary

  • Remove Framer Motion import from PageHero.tsx, replacing 3 motion.div animations with CSS keyframes
  • Dynamic import 17 below-fold section components in ExpertisePageClient.tsx (defers JS hydration)
  • Switch ExpertisePageClient inline motion usage from full motion to lightweight LazyMotion + m pattern

Problem

Lighthouse reports 3.8s LCP on /technologies/react (target: <2.5s). The LCP element is the h1 heading — it renders at FCP (~1.3s) with fallback font, then re-renders at 3.8s when the Outfit web font loads via font-display: swap. The font load is delayed because Framer Motion's chunk (1714ms CPU, 653ms scripting) blocks the main thread.

TBT is 380ms (target: <200ms) from 17 long tasks, primarily FM hydration of eagerly-imported section components.

Root Cause

ExpertisePageClient.tsx eagerly imports 17 section components + motion from framer-motion. Even though below-fold sections use whileInView, the import and hydration happen on initial load, blocking the main thread for ~2s.

What Changed

File Change
components/ui/PageHero.tsx Removed FM import, converted glow/stats/children motion.div to CSS animations
app/globals.css Added CSS keyframes: glowFadeIn, heroSlideUp, stagger delays
app/services/[slug]/ExpertisePageClient.tsx 17 section components now next/dynamic imports; motion.divm.div with LazyMotion

Expected Impact

  • LCP: 3.8s → <2.5s (FM removed from critical path, main thread free for font render)
  • TBT: 380ms → <200ms (deferred JS execution)
  • TTI: 8.0s → ~3-4s (less initial JS to hydrate)
  • Performance score: 79 → 90+

Test plan

  • Verify /technologies/react loads with h1 visible at first paint
  • Verify below-fold scroll animations still trigger (CapabilitiesGrid, FAQ, etc.)
  • Run Lighthouse on /technologies/react — confirm LCP < 2.5s
  • Check other technology pages (/technologies/nodejs, /technologies/python)
  • Check service pages (/services/ai-engineering, /services/frontend-development)
  • Verify no CLS regression (currently 0)

🤖 Generated with Claude Code

… pages

- Remove FM import from PageHero.tsx, replace motion.div with CSS animations
- Dynamic import 17 below-fold section components in ExpertisePageClient
- Switch ExpertisePageClient inline motion usage to LazyMotion + m pattern

LCP element (h1) was delayed to 3.8s because FM's 1714ms CPU chunk blocked
the main thread, preventing timely font-swap render. These changes remove FM
from the initial JS bundle entirely — it now loads lazily when below-fold
sections hydrate on scroll.

Expected: LCP < 2.5s, TBT < 200ms (from 380ms), Performance 90+.
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 19, 2026

Deploying website with  Cloudflare Pages  Cloudflare Pages

Latest commit: 25bb26c
Status: ✅  Deploy successful!
Preview URL: https://00280ef9.website-yiq.pages.dev
Branch Preview URL: https://perf-lighthouse-optimization.website-yiq.pages.dev

View logs

font-display:swap caused the h1 (LCP element) to re-render when the
web font loaded late, pushing LCP to 4.4s. With display:optional the
browser gives ~100ms for the font to load; if it misses, it sticks
with the fallback for that page load. Combined with adjustFontFallback
and preload, repeat visitors get the web font from cache. First-visit
users on slow connections see system font headings — acceptable
trade-off for sub-2.5s LCP.
…aint

The h1 (LCP element) was inside ExpertisePageClient ("use client"),
causing React hydration to repaint it at ~3.9s instead of staying
at FCP (~1.5s). This restructures the rendering so the hero is a
server component passed as heroSlot from the page-level server
component.

Changes:
- Remove "use client" from PageHero.tsx and ExpertiseHero.tsx (no
  longer use FM or any client hooks)
- Create ExpertisePageHero.tsx server component with all slug-specific
  hero CTA/children logic extracted from ExpertisePageClient
- Add heroSlot prop to ExpertisePageClient, render it instead of
  inline ExpertiseHero
- Update all 10 page files (1 dynamic service + 8 technology) to
  pass server-rendered heroSlot

With this pattern, React treats the hero as an opaque subtree during
hydration — the h1 paints at FCP and is never repainted. LCP should
drop from ~3.9s to ~1.5s.
@vibemarketerpromax vibemarketerpromax merged commit 6a0c7ff into main Feb 19, 2026
4 of 5 checks passed
@vibemarketerpromax vibemarketerpromax deleted the perf/lighthouse-optimization branch February 19, 2026 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments