perf: Remove Framer Motion from critical path on expertise pages#106
Merged
vibemarketerpromax merged 3 commits intomainfrom Feb 19, 2026
Merged
perf: Remove Framer Motion from critical path on expertise pages#106vibemarketerpromax merged 3 commits intomainfrom
vibemarketerpromax merged 3 commits intomainfrom
Conversation
… 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+.
Deploying website with
|
| 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 |
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PageHero.tsx, replacing 3motion.divanimations with CSS keyframesExpertisePageClient.tsx(defers JS hydration)ExpertisePageClientinline motion usage from fullmotionto lightweightLazyMotion + mpatternProblem
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 viafont-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.tsxeagerly imports 17 section components +motionfrom framer-motion. Even though below-fold sections usewhileInView, the import and hydration happen on initial load, blocking the main thread for ~2s.What Changed
components/ui/PageHero.tsxmotion.divto CSS animationsapp/globals.cssglowFadeIn,heroSlideUp, stagger delaysapp/services/[slug]/ExpertisePageClient.tsxnext/dynamicimports;motion.div→m.divwithLazyMotionExpected Impact
Test plan
/technologies/reactloads with h1 visible at first paint/technologies/react— confirm LCP < 2.5s/technologies/nodejs,/technologies/python)/services/ai-engineering,/services/frontend-development)🤖 Generated with Claude Code