This guide outlines performance optimizations implemented and recommended for the GitHub PR Dashboard.
// Components are lazy loaded
const LazyDashboard = lazy(() => import('../pages/Dashboard'));
const LazyIssuesPage = lazy(() => import('../pages/IssuesPage'));- Reduced initial bundle size
- Faster time to first meaningful paint
- Better user experience on slow connections
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 minutes
retry: (failureCount, error) => {
if (error?.status === 401 || error?.status === 403) return false;
return failureCount < 3;
},
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
},
},
});- Intelligent caching reduces API calls
- Background refetching keeps data fresh
- Optimistic updates improve perceived performance
- Configurable requests per minute limit
- Queue-based request management
- Exponential backoff for retries
- Priority handling for urgent requests
- Default: 200 requests per minute
- Adjustable via environment variable
- Automatic cleanup of old timestamps
- Tree Shaking: Ensure unused code is eliminated
- Code Splitting: Route-based splitting implemented
- Compression: Enable gzip/brotli compression
- CDN: Use CDN for static assets
npm run analyze # Analyze bundle size- AbortController for cancelled requests
- Cleanup intervals in rate limiter
- Proper useEffect cleanup
- Intersection Observer for conditional loading
useEffect(() => {
const controller = new AbortController();
fetchData({ signal: controller.signal });
return () => controller.abort();
}, []);When displaying many PRs/issues, consider implementing:
import { FixedSizeList as List } from 'react-window';
const VirtualizedList = ({ items }) => (
<List
height={600}
itemCount={items.length}
itemSize={100}
>
{({ index, style }) => (
<div style={style}>
<PullRequestCard pr={items[index]} />
</div>
)}
</List>
);- Use appropriate image sizes
- Implement lazy loading for avatars
- Consider WebP format support
- Add loading states
- Batch related requests
- Use proper caching headers
- Implement request deduplication
- Optimize payload sizes
<link rel="preconnect" href="https://api.github.com" />
<link rel="preconnect" href="https://avatars.githubusercontent.com" />- Time to First Byte (TTFB)
- First Contentful Paint (FCP)
- Largest Contentful Paint (LCP)
- Cumulative Layout Shift (CLS)
- First Input Delay (FID)
- React DevTools Profiler
- Chrome Lighthouse
- Web Vitals extension
- Bundle analyzer
- Bundle size: < 1MB compressed
- First load: < 3 seconds
- Subsequent loads: < 1 second
- API response time: < 500ms
npm run build # Build and check sizes
npm run analyze # Analyze bundle- Implement React.memo for expensive components
- Use useMemo for expensive calculations
- Implement useCallback for stable references
- Lazy load non-critical components
- Optimize re-renders with proper dependencies
- Enable HTTP/2
- Use compression (gzip/brotli)
- Implement proper caching strategies
- Optimize API payload sizes
- Use CDN for static assets
- Code splitting implemented
- Tree shaking enabled
- Dead code elimination
- Proper source maps for debugging
- Bundle size monitoring
- Test with large datasets (1000+ PRs)
- Simulate slow network conditions
- Test on low-end devices
- Monitor memory usage over time
// Performance measurement
const startTime = performance.now();
await fetchData();
const endTime = performance.now();
console.log(`Operation took ${endTime - startTime} milliseconds`);