feat(frontend): optimize client-side bundle size for Onboarding Progr…#1268
Merged
Conversation
|
@emmanuelStack654 is attempting to deploy a commit to the Emmanuel's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@emmanuelStack654 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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.
…ess Tracker
closes #1159
Reduces the client-side JavaScript footprint of the Onboarding Progress Tracker by lazy-loading framer-motion, replacing JS-driven animations with CSS-only Tailwind keyframes, fixing type drift between the reducer and hook layers, and streaming a zero-dependency shimmer skeleton while the tracker bundle loads. The result is a significantly lighter initial parse cost and a smoother perceived load experience.
Changes
New files
OnboardingTrackerSkeleton.tsx
— server-safe shimmer skeleton, no framer-motion, no hooks. Used as the dynamic() loading fallback and as a standalone Suspense placeholder.
Modified files
tailwind.config.js — 5 new keyframes + animation utilities for CSS-only onboarding animations.
OnboardingProgressTracker.tsx
— lazy framer-motion, CSS-only sub-components, native reduced-motion detection.
useOnboardingI18n.ts
— memoised return object to prevent reference churn.
onboarding-reducer.ts
— fixed type drift: SYNC_STEPS added to action union, createInitialOnboardingState arity corrected, selectProgressPercent reads from state directly.
useOnboardingProgress.ts
— aligned to corrected reducer API.
src/app/(public)/register/page.tsx — tracker lazy-loaded via dynamic() with skeleton fallback.
Optimisation details
Before, motion, AnimatePresence, and useReducedMotion were statically imported, meaning framer-motion (~30 KB gzip) was always parsed before the page became interactive.
After, all five framer-motion exports used by the tracker (motion.div, motion.ol, motion.li, motion.svg, AnimatePresence) are loaded via dynamic(…, { ssr: false }). They are fetched only after mount and only when needed, not on initial page load.
StepIcon previously used motion.span for the checkmark pop-in and spinner rotation. It now uses:
animate-onboarding-check-pop — CSS @Keyframes spring-style scale animation
animate-onboarding-spin — CSS @Keyframes linear rotation
StatusBadge previously used motion.span for a scale fade-in on every step row. It now uses a plain with transition-colors. This removes all framer-motion from the step-list render hot-path — the most frequently rendered section.
The progress bar fill previously used a motion.div with variants and scaleX transforms. It now uses a plain
useReducedMotion from framer-motion was replaced with a matchMedia("(prefers-reduced-motion: reduce)") effect. This removes one more framer-motion import and reads the OS preference directly from the browser API.
The hook previously returned a new object literal on every render, causing all memo()'d children to re-render via reference inequality. The return value is now wrapped in useMemo keyed on [t, ...callbacks] — the object is stable between renders and only recomputes on locale change.
Three issues were silently breaking the TypeScript contract between the reducer and the hook:
SYNC_STEPS was dispatched in useOnboardingProgress but absent from the OnboardingAction union — now added.
createInitialOnboardingState had its signature changed to (currentStep, loadingState) in a previous task but the hook called it with (currentStep, total, completed) — signature restored to the 3-arg form and totalSteps/completedSteps added to OnboardingState.
selectProgressPercent was changed to take (completedSteps, totalSteps) args but the hook called selectProgressPercent(state) — selector now reads from state directly, single-argument.
7. Lazy tracker in register page
OnboardingProgressTracker was statically imported in
page.tsx
, pulling the full tracker + framer-motion into the page's initial bundle. It is now loaded via dynamic(…, { ssr: false, loading: () => }) — the skeleton renders at paint time while the tracker bundle streams in the background.