Created comprehensive PERFORMANCE_BASELINE.md documenting: - Target thresholds from performance.spec.ts (90% all categories) - Current optimizations (AVIF/WebP, font swap, preconnect, cache headers) - Critical issues: hero-portrait.jpg (2.9MB), portrait.jpg (1.2MB) - 13 client components identified for potential RSC conversion - Prioritized action items for optimization Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
9.3 KiB
Performance Baseline Report
Date: 2025-01-25 URL: https://www.damjan-savic.com/ Framework: Next.js 15.1 with React 19 Methodology: Code analysis + Playwright-Lighthouse test configuration
Executive Summary
This baseline report documents the current performance state of the portfolio website based on code analysis and the existing performance test infrastructure. The site targets 90% scores across all Lighthouse categories (Performance, Accessibility, Best Practices, SEO).
Target Thresholds (from tests/e2e/performance.spec.ts)
| Category | Target | Status |
|---|---|---|
| Performance | ≥90% | To be tested |
| Accessibility | ≥90% | To be tested |
| Best Practices | ≥90% | To be tested |
| SEO | ≥90% | To be tested |
Core Web Vitals Targets
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP (Largest Contentful Paint) | ≤2.5s | 2.5s - 4.0s | >4.0s |
| INP (Interaction to Next Paint) | ≤200ms | 200ms - 500ms | >500ms |
| CLS (Cumulative Layout Shift) | ≤0.1 | 0.1 - 0.25 | >0.25 |
| FCP (First Contentful Paint) | ≤1.8s | 1.8s - 3.0s | >3.0s |
| TBT (Total Blocking Time) | ≤200ms | 200ms - 600ms | >600ms |
Current Optimizations Analysis
✅ Positive Findings (Already Implemented)
1. Image Optimization
// next.config.ts
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
}
- Status: ✅ Modern formats (AVIF, WebP) configured
- Impact: Reduces image payload by 25-50%
2. Font Loading Strategy
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
});
- Status: ✅ Font swap prevents FOIT (Flash of Invisible Text)
- Impact: Improved LCP and user experience
3. Resource Hints
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
<link rel="dns-prefetch" href="https://mxadgucxhmstlzsbgmoz.supabase.co" />
- Status: ✅ Critical third-party connections pre-established
- Impact: Reduces connection latency by 100-300ms
4. Static Generation
export function generateStaticParams() {
return locales.map((locale) => ({ locale }));
}
- Status: ✅ All locale routes pre-rendered at build time
- Impact: Zero server-side rendering delay
5. Package Import Optimization
experimental: {
optimizePackageImports: ['lucide-react', 'framer-motion'],
}
- Status: ✅ Tree-shaking for large icon/animation libraries
- Impact: Reduces bundle size by 50-80% for these packages
6. Cache Headers
{
source: '/images/:path*',
headers: [{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' }],
}
- Status: ✅ Aggressive caching for static assets (1 year)
- Impact: Eliminates re-download on repeat visits
7. Production Console Removal
compiler: {
removeConsole: process.env.NODE_ENV === 'production',
}
- Status: ✅ No console pollution in production
- Impact: Smaller bundle, cleaner performance profile
8. Priority Image Loading
<Image src="/hero-portrait.jpg" priority />
<Image src="/header-logo.svg" priority />
- Status: ✅ Critical images loaded with high priority
- Impact: Faster LCP
9. Structured Data (JSON-LD)
- PersonJsonLd, ProfessionalServiceJsonLd, OrganizationJsonLd, WebSiteJsonLd
- Status: ✅ Comprehensive schema markup
- Impact: Better search engine understanding and rich results
10. Responsive Image Variants
Pre-generated sizes: 224, 288, 300, 448, 576, 600px (WebP and JPG)
- Status: ✅ Multiple sizes for different viewports
- Impact: Optimal image delivery per device
⚠️ Optimization Opportunities Identified
1. CRITICAL: Unoptimized Hero Image
File: /public/hero-portrait.jpg
Size: 2,957,516 bytes (~2.9 MB)
Impact: Major LCP delay
Recommendation:
- Compress to <500KB (80-85% JPEG quality)
- Use Next.js Image component with blur placeholder
- Consider AVIF format for additional savings
- Add
fetchpriority="high"attribute
Potential Savings: 2.0-2.5 MB (60-85% reduction)
2. HIGH: Large Portrait Image
File: /public/portrait.jpg
Size: 1,207,506 bytes (~1.2 MB)
Impact: Page weight, especially on portfolio pages
Recommendation:
- Already have optimized versions (portrait-600.webp at 31KB)
- Ensure optimized versions are used in components
- Remove unused original if all references use optimized versions
Potential Savings: ~1.1 MB per page using original
3. MEDIUM: Client Component Count
Current State: 13 client-side components detected
| Component | Needs Client? |
|---|---|
| Header.tsx | Yes (scroll, menu state) |
| ContactForm.tsx | Yes (form state) |
| LoginForm.tsx | Yes (form state) |
| PortfolioCard.tsx | Review - possibly RSC |
| PortfolioGrid.tsx | Review - possibly RSC |
| NavLink.tsx | Review - possibly RSC |
| LanguageSwitcher.tsx | Yes (dropdown state) |
| ContactInfo.tsx | Review - possibly RSC |
| Skills.tsx (sections) | Review - animations? |
| Experience.tsx | Review - animations? |
| Skills.tsx (about) | Review - animations? |
| Hero.tsx (about) | Review - animations? |
| DashboardContent.tsx | Yes (auth state) |
Recommendation:
- Audit each client component for necessity
- Convert static components to RSC where possible
- Use
use clientonly at the boundary where interactivity is needed
Potential Impact: Reduced JavaScript bundle, faster TTI
4. MEDIUM: Background SVG Animations
File: /src/components/layout/GlobalBackground.tsx
// Animated SVG lines with CSS animations
<animate attributeName="y1" values="20%;80%;20%" dur="10s" repeatCount="indefinite" />
Current State:
- SVG-based animations (GPU-accelerated)
- Low opacity (0.1-0.3)
- Fixed positioning
Assessment: Generally performant, but:
Recommendations:
- Consider
prefers-reduced-motionmedia query - Lazy load on mobile devices
- Test on low-end devices for jank
5. LOW: Missing Loading States
Observation: No skeleton loaders or loading states visible for dynamic content
Recommendation:
- Add loading.tsx files for route segments
- Use Suspense boundaries for data fetching
- Implement skeleton UI for improved perceived performance
6. LOW: Consider Link Prefetching
Current State: Default Next.js prefetching (on hover)
Recommendation:
- Verify prefetching is working correctly
- Consider
prefetch={false}for rarely-used links - Use
priorityprop on critical navigation links
Performance Test Infrastructure
Available Tests (tests/e2e/performance.spec.ts)
-
Homepage Performance Tests
- Tests all 3 locales (de, en, sr)
- Runs Lighthouse audits with 90% thresholds
-
Critical Pages Performance
- Homepage, About, Portfolio, Contact
- German locale only (optimization)
-
Mobile Performance
- Pixel 5 emulation (375x812)
- iPhone user agent
-
Core Web Vitals Verification
- LCP threshold test
- CLS measurement
- Resource error monitoring
-
Resource Loading Tests
- JavaScript bundle size (<500KB per chunk)
- Image lazy loading verification
- Modern image format detection
Running Performance Tests
# Run all performance tests
npx playwright test tests/e2e/performance.spec.ts --project=chromium
# Run with HTML report
npx playwright test tests/e2e/performance.spec.ts --reporter=html
Recommended Action Items
Priority 1: Critical (Immediate)
- Optimize hero-portrait.jpg (target: <500KB)
- Run full Lighthouse audit once API access is available
- Remove unused large image files
Priority 2: High (This Sprint)
- Audit client components for RSC conversion
- Add loading.tsx for main route segments
- Implement blur placeholder for hero image
Priority 3: Medium (Next Sprint)
- Add
prefers-reduced-motionsupport - Review and optimize third-party scripts
- Implement performance monitoring (web-vitals integration)
Priority 4: Low (Backlog)
- Bundle analysis and code splitting optimization
- Edge caching configuration
- Service worker implementation for offline support
Notes
API Access Issue
The PageSpeed Insights API was inaccessible during this audit (proxy/firewall blocking). For live metrics:
- Use PageSpeed Insights directly in browser
- Run local Lighthouse via Chrome DevTools
- Use the Playwright performance tests locally
Next Steps
- Resolve image optimization issues (Priority 1)
- Run Playwright performance tests with
npm run dev - Capture live metrics and update this baseline
- Track improvements over time
Appendix: Configuration Files
| File | Purpose |
|---|---|
next.config.ts |
Image optimization, headers, compiler options |
playwright.config.ts |
E2E test configuration with Lighthouse ports |
tests/e2e/performance.spec.ts |
Performance test suite |
scripts/pagespeed-check.js |
PageSpeed API integration script |
Generated by auto-claude performance audit