Назад към всички

afrexai-web-performance-engine

// Complete web performance optimization system. Audit, diagnose, fix, and monitor — no external tools required (but integrates with Lighthouse, WebPageTest, Chrome DevTools when available).

$ git log --oneline --stat
stars:1,933
forks:367
updated:March 4, 2026
SKILL.mdreadonly

Web Performance Engine

Complete web performance optimization system. Audit, diagnose, fix, and monitor — no external tools required (but integrates with Lighthouse, WebPageTest, Chrome DevTools when available).

Phase 1: Performance Audit

Quick Health Check

Run these checks in order. Stop when you find the bottleneck tier.

Tier 1 — Critical (blocks rendering):

  • Time to First Byte (TTFB) > 800ms → server problem
  • First Contentful Paint (FCP) > 1.8s → render-blocking resources
  • Largest Contentful Paint (LCP) > 2.5s → hero element problem
  • Total Blocking Time (TBT) > 200ms → JavaScript problem
  • Cumulative Layout Shift (CLS) > 0.1 → layout instability
  • Interaction to Next Paint (INP) > 200ms → event handler problem

Tier 2 — Important (affects experience):

  • Page weight > 2MB
  • Requests > 80
  • JavaScript > 500KB (compressed)
  • Images > 1MB total
  • No compression (gzip/brotli)
  • No caching headers

Tier 3 — Polish (competitive edge):

  • Speed Index > 3.4s
  • Time to Interactive > 3.8s
  • Font loading causes flash
  • Third-party scripts > 30% of JS

Audit Brief Template

audit:
  url: ""
  device: "mobile"  # mobile | desktop | both
  connection: "4G"  # 3G | 4G | fiber
  region: ""        # closest to target users
  
scores:
  performance: null  # 0-100
  fcp_ms: null
  lcp_ms: null
  tbt_ms: null
  cls: null
  inp_ms: null
  ttfb_ms: null
  
page_weight:
  total_kb: null
  html_kb: null
  css_kb: null
  js_kb: null
  images_kb: null
  fonts_kb: null
  other_kb: null
  
requests:
  total: null
  by_type: {}
  third_party_count: null
  third_party_kb: null

Getting Metrics Without Tools

If no Lighthouse/DevTools available, use web-based tools:

  1. web_fetch "https://pagespeed.web.dev/analysis?url={encoded_url}" — Google's free tool
  2. web_search "webpagetest {url}" — find cached results
  3. web_search "site:{domain} core web vitals" — find CrUX data
  4. Check <head> for obvious issues: render-blocking CSS/JS, missing preloads, no meta viewport

Phase 2: Diagnosis — The Performance Waterfall

Critical Rendering Path Analysis

DNS → TCP → TLS → TTFB → HTML Parse → CSSOM → Render Tree → FCP → LCP
                                ↓
                         JS Download → Parse → Execute → INP

Bottleneck Decision Tree:

High TTFB (>800ms)?
├─ YES → Phase 3A: Server optimization
└─ NO → High FCP (>1.8s)?
    ├─ YES → Phase 3B: Render-blocking resources
    └─ NO → High LCP (>2.5s)?
        ├─ YES → Phase 3C: Hero element optimization
        └─ NO → High TBT (>200ms)?
            ├─ YES → Phase 3D: JavaScript optimization
            └─ NO → High CLS (>0.1)?
                ├─ YES → Phase 3E: Layout stability
                └─ NO → High INP (>200ms)?
                    ├─ YES → Phase 3F: Interaction optimization
                    └─ NO → ✅ Performance is good!

Resource Impact Scoring

Rate each resource by impact:

FactorWeightScore 1Score 3Score 5
Size (KB)3x<1010-100>100
Render-blocking5xNoPartialFull
Above-fold impact4xNoneIndirectDirect
Cacheable2xLong cacheShort cacheNo cache
Compressible2xAlready donePossibleNot compressed

Priority = Sum(Factor × Weight). Fix highest scores first.

Phase 3: Fix Playbooks

3A: Server Optimization (TTFB)

Quick wins:

# CDN: If no CDN, this is #1 priority
# Check: curl -sI {url} | grep -i 'x-cache\|cf-cache\|x-cdn'

# Compression: Must have brotli or gzip
# Check: curl -sI -H "Accept-Encoding: br,gzip" {url} | grep -i content-encoding

# HTTP/2 or HTTP/3
# Check: curl -sI --http2 {url} | head -1

Server-side checklist:

  • CDN in front (Cloudflare, Fastly, CloudFront)
  • Brotli compression enabled (20-30% smaller than gzip)
  • HTTP/2 minimum, HTTP/3 if possible
  • Server-side caching (Redis, Varnish)
  • Database query optimization (<50ms per query)
  • Connection pooling enabled
  • Edge computing for dynamic content (Workers, Lambda@Edge)

Cache headers template:

# Static assets (CSS, JS, images, fonts)
Cache-Control: public, max-age=31536000, immutable

# HTML pages
Cache-Control: public, max-age=0, must-revalidate

# API responses
Cache-Control: private, max-age=60, stale-while-revalidate=300

3B: Render-Blocking Resources (FCP)

CSS optimization:

<!-- BEFORE: Render-blocking -->
<link rel="stylesheet" href="styles.css">

<!-- AFTER: Critical CSS inline + async load -->
<style>/* Critical above-fold CSS here (< 14KB) */</style>
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>

Rules:

  • Inline critical CSS (above-fold styles, < 14KB)
  • Defer non-critical CSS
  • Remove unused CSS (typical savings: 60-90%)
  • Combine media queries
  • Avoid @import (creates sequential loading)

JavaScript optimization:

<!-- BEFORE: Render-blocking -->
<script src="app.js"></script>

<!-- AFTER: Non-blocking -->
<script src="app.js" defer></script>

<!-- OR: Independent scripts -->
<script src="analytics.js" async></script>

Rules:

  • defer for app scripts (maintains order, runs after parse)
  • async for independent scripts (analytics, ads)
  • Never put <script> in <head> without defer/async
  • Inline small scripts (< 1KB)

3C: Hero Element Optimization (LCP)

LCP element types and fixes:

LCP ElementFix
<img>Preload + responsive + modern format
<video> posterPreload poster image
CSS background-imagePreload + inline critical CSS
Text blockPreload font + font-display: optional

Image optimization checklist:

<!-- Optimal hero image -->
<link rel="preload" as="image" href="hero.webp" 
      imagesrcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
      imagesizes="100vw">

<img src="hero.webp" 
     srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
     sizes="100vw"
     width="1200" height="600"
     alt="Hero description"
     fetchpriority="high"
     decoding="async">

Image format decision:

Photo/complex image? → WebP (25-35% smaller than JPEG)
                     → AVIF (50% smaller, but slower encode)
Simple graphic/logo? → SVG (scalable, tiny)
                    → PNG only if transparency needed
Animation?          → WebM/MP4 video (not GIF — 90% smaller)

Image size targets:

ViewportMax widthTarget KB
Mobile400px< 50KB
Tablet800px< 100KB
Desktop1200px< 150KB
Hero/banner1600px< 200KB

3D: JavaScript Optimization (TBT)

Bundle analysis approach:

  1. Check total JS size: web_fetch the page, count <script> tags
  2. Identify large libraries (React, Lodash, Moment.js)
  3. Check for duplicate code across bundles
  4. Identify unused exports

Common JS bloat and replacements:

LibrarySizeAlternativeSize
moment.js67KBdate-fns2-10KB
lodash (full)71KBlodash-es (tree-shake)2-5KB
jQuery87KBvanilla JS0KB
animate.css80KBCSS animations1-2KB
chart.js60KBlightweight-charts40KB

Code splitting rules:

  • Route-based splitting (each page loads its own JS)
  • Component-level splitting for heavy components (modals, editors, charts)
  • Dynamic import for below-fold features: const Chart = lazy(() => import('./Chart'))
  • Vendor chunk for stable dependencies (changes rarely = long cache)

Long task breaking:

// BEFORE: Blocks main thread 200ms+
function processLargeList(items) {
  items.forEach(item => heavyComputation(item));
}

// AFTER: Yields to main thread
async function processLargeList(items) {
  for (const item of items) {
    heavyComputation(item);
    // Yield every 50ms
    if (performance.now() - start > 50) {
      await scheduler.yield(); // or setTimeout(0)
      start = performance.now();
    }
  }
}

3E: Layout Stability (CLS)

Top CLS causes and fixes:

CauseFix
Images without dimensionsAlways set width + height
Ads/embeds without spaceReserve space with aspect-ratio or min-height
Dynamic content injectionUse CSS contain or reserved space
Web fonts causing reflowfont-display: optional or swap with size-adjust
Late-loading CSSInline critical CSS

Anti-CLS patterns:

/* Reserve space for dynamic content */
.ad-slot { min-height: 250px; }
.embed-container { aspect-ratio: 16/9; }

/* Prevent font swap reflow */
@font-face {
  font-family: 'Brand';
  src: url('brand.woff2') format('woff2');
  font-display: optional; /* No swap = no shift */
  size-adjust: 105%; /* Match fallback metrics */
}

/* Contain layout shifts */
.dynamic-widget {
  contain: layout;
  min-height: 200px;
}

3F: Interaction Optimization (INP)

Event handler rules:

  • Keep handlers < 50ms
  • Debounce scroll/resize (100-150ms)
  • Use requestAnimationFrame for visual updates
  • Offload heavy computation to Web Workers
  • Use content-visibility: auto for off-screen content

Input responsiveness:

// BEFORE: Blocks during type
input.addEventListener('input', (e) => {
  expensiveFilter(e.target.value); // 100ms+ 
});

// AFTER: Debounced + visual feedback
input.addEventListener('input', (e) => {
  showSpinner(); // Instant visual feedback
  debounce(() => expensiveFilter(e.target.value), 150);
});

Phase 4: Resource Loading Strategy

Preload / Prefetch / Preconnect Decision

<!-- Preconnect: Third-party origins you'll need soon -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>

<!-- DNS-prefetch: Third-party origins you might need -->
<link rel="dns-prefetch" href="https://analytics.example.com">

<!-- Preload: Critical resources for THIS page -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero.webp" as="image">
<link rel="preload" href="brand.woff2" as="font" type="font/woff2" crossorigin>

<!-- Prefetch: Resources for NEXT page (low priority) -->
<link rel="prefetch" href="/next-page.js">

<!-- Modulepreload: ES modules -->
<link rel="modulepreload" href="app.mjs">

Rules:

  • Max 3-5 preloads per page (more = competing priorities)
  • Always preload: LCP image, critical font, above-fold CSS
  • Preconnect to known third-party origins (max 4-6)
  • Prefetch only on fast connections

Lazy Loading Strategy

Above fold (viewport):     fetchpriority="high", no lazy
Below fold (1-2 screens):  loading="lazy", decoding="async"
Way below fold:            Intersection Observer, load on demand
Off-screen widgets:        content-visibility: auto

Font Loading Optimization

/* Optimal font loading */
@font-face {
  font-family: 'Brand';
  src: url('brand.woff2') format('woff2');
  font-display: swap;
  unicode-range: U+0000-00FF; /* Latin only if applicable */
}

Font checklist:

  • WOFF2 format only (best compression)
  • Subset fonts (Latin, extended only if needed)
  • Max 2-3 font families
  • Max 4 font files total (regular, bold, italic, bold-italic)
  • Preload critical font files
  • Consider system font stack for body text

System font stacks:

/* Modern system fonts — zero network cost */
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

/* Monospace */
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace;

Phase 5: Third-Party Script Management

Impact Assessment

third_party_audit:
  - script: "Google Analytics 4"
    size_kb: 45
    blocks_render: false
    loads_more_scripts: true
    total_impact_kb: 90
    essential: true
    mitigation: "gtag async, delay until interaction"
    
  - script: "Intercom chat widget"
    size_kb: 200
    blocks_render: false
    loads_more_scripts: true
    total_impact_kb: 450
    essential: false
    mitigation: "Load on scroll/click, not page load"

Third-party loading strategies:

// Strategy 1: Load on interaction
document.addEventListener('scroll', () => {
  loadThirdParty('chat-widget.js');
}, { once: true });

// Strategy 2: Load after page is idle
requestIdleCallback(() => {
  loadThirdParty('analytics.js');
});

// Strategy 3: Facade pattern (show placeholder until needed)
chatButton.addEventListener('click', () => {
  loadThirdParty('intercom.js').then(() => Intercom('show'));
});

Rules:

  • Audit ALL third-party scripts quarterly
  • Every script needs a business justification
  • If a script loads >100KB, it needs a loading strategy
  • Self-host what you can (fonts, analytics alternatives)
  • Use rel="noopener" on all external links

Phase 6: Mobile Performance

Mobile-Specific Optimization

Targets (mobile on 4G):

MetricGoodNeeds WorkPoor
FCP< 1.8s1.8-3.0s> 3.0s
LCP< 2.5s2.5-4.0s> 4.0s
TBT< 200ms200-600ms> 600ms
CLS< 0.10.1-0.25> 0.25
INP< 200ms200-500ms> 500ms

Mobile-specific checklist:

  • Viewport meta tag present
  • Touch targets ≥ 48×48px
  • No horizontal scroll
  • Images responsive (srcset + sizes)
  • JS budget < 300KB (compressed) on mobile
  • Critical CSS < 14KB (fits in first TCP round trip)
  • Avoid complex CSS (heavy animations, large box-shadows)

Phase 7: Performance Budget

Setting Budgets

performance_budget:
  metrics:
    lcp_ms: 2500
    fcp_ms: 1800
    tbt_ms: 200
    cls: 0.1
    inp_ms: 200
    
  resources:
    total_kb: 1500
    js_kb: 350
    css_kb: 80
    images_kb: 800
    fonts_kb: 100
    
  requests:
    total: 60
    third_party: 15
    
  lighthouse:
    performance: 90
    accessibility: 90
    best_practices: 90
    seo: 90

Budget enforcement rules:

  • Any PR that increases JS by >10KB needs justification
  • LCP regression > 200ms blocks deploy
  • Monthly Lighthouse audit — track trend
  • Per-route budgets for SPAs (homepage stricter than admin)

Budget Monitoring Template

# Weekly performance check
date: "YYYY-MM-DD"
url: ""
device: "mobile"

scores:
  lighthouse: null
  lcp: null
  fcp: null
  tbt: null
  cls: null

trend: "improving | stable | degrading"
regressions: []
actions: []

Phase 8: Performance Scoring Rubric

Rate the site 0-100:

DimensionWeight0-23-45
Core Web Vitals25%All redMixedAll green
Page weight15%>5MB2-5MB<2MB
Caching strategy15%NonePartialFull with immutable
Render path15%Multiple blockersSome optimizedClean critical path
Image optimization10%UnoptimizedPartiallyWebP/AVIF + responsive
JavaScript health10%>1MB, no splittingSome splitting<350KB, code-split
Third-party control5%UnmanagedSome deferredAll managed + budgeted
Mobile experience5%Desktop-onlyResponsiveMobile-first optimized

Score interpretation:

  • 90-100: Elite. Maintain and iterate.
  • 70-89: Good. Fix the weakest dimension.
  • 50-69: Needs work. Follow Phase 3 playbooks.
  • <50: Critical. Start with server + render-blocking fixes.

Phase 9: Common Architectures — Quick Wins

Next.js / React

  • Use next/image (auto WebP, lazy, blur placeholder)
  • Enable ISR or SSG for static pages
  • Use dynamic() for heavy components
  • Check bundle with @next/bundle-analyzer
  • Middleware for edge caching

WordPress

  • Page cache plugin (WP Super Cache, W3 Total Cache)
  • Image optimization (ShortPixel, Imagify)
  • Disable unused plugins (each adds JS+CSS)
  • Use a CDN plugin
  • Consider static generation (Simply Static)

SPA (React/Vue/Svelte)

  • Route-based code splitting (mandatory)
  • SSR or SSG for SEO pages
  • Service worker for repeat visits
  • Skeleton screens (not spinners)
  • Virtual scrolling for long lists

Static Sites

  • Already fast — focus on image optimization
  • Deploy to CDN edge (Cloudflare Pages, Netlify, Vercel)
  • Inline all critical CSS
  • Minimal JS (< 50KB)

Phase 10: Advanced Techniques

Service Worker Caching

// Cache-first for static assets
self.addEventListener('fetch', (event) => {
  if (event.request.url.match(/\.(css|js|woff2|webp|avif)$/)) {
    event.respondWith(
      caches.match(event.request).then(cached => cached || fetch(event.request))
    );
  }
});

Resource Hints for Navigation

// Predictive prefetch on hover
document.querySelectorAll('a').forEach(link => {
  link.addEventListener('mouseenter', () => {
    const prefetch = document.createElement('link');
    prefetch.rel = 'prefetch';
    prefetch.href = link.href;
    document.head.appendChild(prefetch);
  }, { once: true });
});

Performance Monitoring in Production

// Report Core Web Vitals
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Send to analytics
    sendToAnalytics({
      metric: entry.name,
      value: entry.value,
      rating: entry.rating, // "good" | "needs-improvement" | "poor"
    });
  }
}).observe({ type: 'largest-contentful-paint', buffered: true });

Edge Cases

Infinite scroll / pagination:

  • Virtual scrolling for >100 items
  • Intersection Observer to load batches
  • content-visibility: auto for off-screen items
  • Memory management: remove far-off-screen DOM nodes

SPAs with client-side routing:

  • Measure soft navigations (not just initial load)
  • Report per-route metrics
  • Prefetch likely next routes
  • Keep route JS < 100KB each

E-commerce product pages:

  • Preload first product image
  • Lazy load review section, related products
  • Defer recommendation engine JS
  • Cache product data with stale-while-revalidate

Media-heavy sites:

  • Lazy load everything below fold
  • Use <video> not GIF (90% smaller)
  • Adaptive quality based on connection (Network Information API)
  • Progressive JPEG for large photos

Natural Language Commands

  • "Audit {url}" → Run full Phase 1 audit
  • "Fix LCP on {url}" → Phase 3C playbook
  • "What's slowing down {url}?" → Phase 2 diagnosis tree
  • "Set performance budget for {project}" → Phase 7 template
  • "Score {url}" → Phase 8 rubric
  • "Optimize images on {url}" → Phase 3C image checklist
  • "Reduce JavaScript on {url}" → Phase 3D JS optimization
  • "Fix layout shifts on {url}" → Phase 3E CLS playbook
  • "Mobile performance audit for {url}" → Phase 6
  • "Third-party script audit for {url}" → Phase 5
  • "Weekly performance check for {url}" → Phase 7 monitoring template
  • "Compare {url1} vs {url2}" → Side-by-side audit