# 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
<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
```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
<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 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
<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-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*
