# 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 ```typescript // 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 ```typescript 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 ```html ``` - **Status:** ✅ Critical third-party connections pre-established - **Impact:** Reduces connection latency by 100-300ms #### 4. Static Generation ```typescript 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 ```typescript 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 ```typescript { 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 ```typescript compiler: { removeConsole: process.env.NODE_ENV === 'production', } ``` - **Status:** ✅ No console pollution in production - **Impact:** Smaller bundle, cleaner performance profile #### 8. Priority Image Loading ```typescript ``` - **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 client` only 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` ```typescript // Animated SVG lines with CSS animations ``` **Current State:** - SVG-based animations (GPU-accelerated) - Low opacity (0.1-0.3) - Fixed positioning **Assessment:** Generally performant, but: **Recommendations:** - Consider `prefers-reduced-motion` media 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 `priority` prop on critical navigation links --- ## Performance Test Infrastructure ### Available Tests (`tests/e2e/performance.spec.ts`) 1. **Homepage Performance Tests** - Tests all 3 locales (de, en, sr) - Runs Lighthouse audits with 90% thresholds 2. **Critical Pages Performance** - Homepage, About, Portfolio, Contact - German locale only (optimization) 3. **Mobile Performance** - Pixel 5 emulation (375x812) - iPhone user agent 4. **Core Web Vitals Verification** - LCP threshold test - CLS measurement - Resource error monitoring 5. **Resource Loading Tests** - JavaScript bundle size (<500KB per chunk) - Image lazy loading verification - Modern image format detection ### Running Performance Tests ```bash # 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-motion` support - [ ] 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: 1. Use [PageSpeed Insights](https://pagespeed.web.dev/) directly in browser 2. Run local Lighthouse via Chrome DevTools 3. Use the Playwright performance tests locally ### Next Steps 1. Resolve image optimization issues (Priority 1) 2. Run Playwright performance tests with `npm run dev` 3. Capture live metrics and update this baseline 4. 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*