Performance
Performance optimization techniques and monitoring for WI-CARPOOL
Performance Metrics
WI-CARPOOL is optimized for excellent performance with fast loading times and smooth user interactions.
⚡ Fast Loading
First Contentful Paint under 1.5s, optimized bundle sizes.
🔄 Code Splitting
Dynamic imports and route-based code splitting for faster initial loads.
🎯 Lazy Loading
Images and components load only when needed.
📊 Monitoring
Real-time performance monitoring and analytics.
Bundle Optimization
Vite Build Configuration
// vite.config.ts - Performance optimizations
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
router: ['react-router-dom'],
ui: ['@radix-ui/react-dialog', '@radix-ui/react-popover'],
utils: ['date-fns', 'clsx', 'class-variance-authority'],
},
},
},
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
sourcemap: false,
chunkSizeWarningLimit: 1000,
},
})
Lazy Component Loading
// Route-based code splitting
import { lazy, Suspense } from 'react'
import { Skeleton } from '@/components/ui/skeleton'
const Dashboard = lazy(() => import('@/pages/Dashboard'))
const Profile = lazy(() => import('@/pages/Profile'))
const RideSearch = lazy(() => import('@/pages/RideSearch'))
function AppRouter() {
return (
<Suspense fallback={<PageSkeleton />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
<Route path="/search" element={<RideSearch />} />
</Routes>
</Suspense>
)
}
function PageSkeleton() {
return (
<div className="space-y-4 p-4">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-32 w-full" />
<Skeleton className="h-24 w-full" />
</div>
)
}
React Optimizations
Memoization Strategies
// Optimized component with React.memo
import { memo, useMemo, useCallback } from 'react'
interface RideCardProps {
ride: Ride
onBook: (rideId: string) => void
}
export const RideCard = memo(({ ride, onBook }: RideCardProps) => {
const formattedPrice = useMemo(() =>
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(ride.price)
, [ride.price])
const handleBook = useCallback(() => {
onBook(ride.id)
}, [onBook, ride.id])
return (
<Card>
<CardContent>
<h3>{ride.destination}</h3>
<p>{formattedPrice}</p>
<Button onClick={handleBook}>Book Ride</Button>
</CardContent>
</Card>
)
})
Virtual Scrolling for Large Lists
// Virtual scrolling implementation
import { FixedSizeList as List } from 'react-window'
interface VirtualRideListProps {
rides: Ride[]
onRideSelect: (ride: Ride) => void
}
export function VirtualRideList({ rides, onRideSelect }: VirtualRideListProps) {
const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => (
<div style={style}>
<RideCard
ride={rides[index]}
onBook={() => onRideSelect(rides[index])}
/>
</div>
)
return (
<List
height={600}
itemCount={rides.length}
itemSize={120}
width="100%"
>
{Row}
</List>
)
}
Image Optimization
Responsive Image Component
// Optimized image component with lazy loading
import { useState, useRef, useEffect } from 'react'
interface OptimizedImageProps {
src: string
alt: string
className?: string
sizes?: string
}
export function OptimizedImage({ src, alt, className, sizes }: OptimizedImageProps) {
const [isLoaded, setIsLoaded] = useState(false)
const [isInView, setIsInView] = useState(false)
const imgRef = useRef<HTMLImageElement>(null)
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsInView(true)
observer.disconnect()
}
},
{ threshold: 0.1 }
)
if (imgRef.current) {
observer.observe(imgRef.current)
}
return () => observer.disconnect()
}, [])
return (
<div className={cn("relative overflow-hidden", className)}>
{!isLoaded && (
<div className="absolute inset-0 bg-gray-200 animate-pulse" />
)}
{isInView && (
<img
ref={imgRef}
src={src}
alt={alt}
sizes={sizes}
onLoad={() => setIsLoaded(true)}
className={cn(
"transition-opacity duration-300",
isLoaded ? "opacity-100" : "opacity-0"
)}
/>
)}
</div>
)
}
API Performance
Request Debouncing
// Debounced search hook
import { useState, useEffect, useMemo } from 'react'
import { useQuery } from '@tanstack/react-query'
import { debounce } from 'lodash'
export function useSearchRides(searchTerm: string) {
const [debouncedTerm, setDebouncedTerm] = useState(searchTerm)
const debouncedUpdate = useMemo(
() => debounce((term: string) => setDebouncedTerm(term), 300),
[]
)
useEffect(() => {
debouncedUpdate(searchTerm)
return () => debouncedUpdate.cancel()
}, [searchTerm, debouncedUpdate])
return useQuery({
queryKey: ['rides', 'search', debouncedTerm],
queryFn: () => searchRides(debouncedTerm),
enabled: debouncedTerm.length > 2,
staleTime: 5 * 60 * 1000, // 5 minutes
cacheTime: 10 * 60 * 1000, // 10 minutes
})
}
Request Caching and Prefetching
// Query client configuration
import { QueryClient } from '@tanstack/react-query'
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 minutes
cacheTime: 10 * 60 * 1000, // 10 minutes
retry: (failureCount, error: any) => {
if (error?.status === 404) return false
return failureCount < 3
},
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
},
},
})
// Prefetch popular routes
export function prefetchPopularRides() {
queryClient.prefetchQuery({
queryKey: ['rides', 'popular'],
queryFn: fetchPopularRides,
staleTime: 10 * 60 * 1000, // 10 minutes
})
}
Performance Monitoring
Core Web Vitals Tracking
// Performance monitoring utility
export function initPerformanceTracking() {
// First Contentful Paint
new PerformanceObserver((list) => {
const entries = list.getEntries()
entries.forEach((entry) => {
if (entry.name === 'first-contentful-paint') {
trackMetric('FCP', entry.startTime)
}
})
}).observe({ entryTypes: ['paint'] })
// Largest Contentful Paint
new PerformanceObserver((list) => {
const entries = list.getEntries()
const lastEntry = entries[entries.length - 1]
trackMetric('LCP', lastEntry.startTime)
}).observe({ entryTypes: ['largest-contentful-paint'] })
// Cumulative Layout Shift
new PerformanceObserver((list) => {
let clsValue = 0
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += (entry as any).value
}
}
trackMetric('CLS', clsValue)
}).observe({ entryTypes: ['layout-shift'] })
}
function trackMetric(name: string, value: number) {
// Send to analytics service
if (window.gtag) {
window.gtag('event', name, {
custom_parameter_1: value,
})
}
}
Best Practices
Code Quality
- Use TypeScript for better code optimization
- Implement proper error boundaries
- Minimize bundle size with tree shaking
- Use modern JavaScript features for better performance
Runtime Performance
- Avoid unnecessary re-renders with React.memo
- Use useCallback and useMemo appropriately
- Implement virtual scrolling for large datasets
- Optimize images with proper sizing and formats
Network Performance
- Implement service worker caching strategies
- Use HTTP/2 and compression
- Minimize API requests with batching
- Implement proper error handling and retries