SPB Git

spb/ultra-sharp-agent-skills Public

Ultra-Sharp Agent Skills — a research-first skill-authoring system + 72 production-ready skills for AI agents.

Python 100%

# Patterns — Optimizing Web Performance

# Contents

  • LCP: hero image and critical path
  • Images: responsive, modern, shift-free
  • Fonts
  • JavaScript: splitting and on-interaction loading
  • Third-party scripts: facades and idle loading
  • INP: breaking long tasks
  • Measuring
  • Gotchas

# LCP: hero image and critical path

html
<head>
  <link rel="preconnect" href="https://cdn.example.com">
  <link rel="preload" as="image" href="hero-1200.avif"
        imagesrcset="hero-800.avif 800w, hero-1200.avif 1200w" imagesizes="100vw">
  <style>/* inlined critical CSS: layout + above-the-fold only */</style>
  <script src="/app.js" defer></script>
</head>
<body>
  <img src="hero-1200.avif"
       srcset="hero-800.avif 800w, hero-1200.avif 1200w" sizes="100vw"
       width="1200" height="600" fetchpriority="high" alt="…">

# Images: responsive, modern, shift-free

html
<picture>
  <source type="image/avif" srcset="chart-400.avif 400w, chart-800.avif 800w">
  <source type="image/webp" srcset="chart-400.webp 400w, chart-800.webp 800w">
  <img src="chart-800.jpg" srcset="chart-400.jpg 400w, chart-800.jpg 800w"
       sizes="(max-width: 600px) 100vw, 50vw"
       width="800" height="500" loading="lazy" decoding="async" alt="…">
</picture>
  • width/height (or CSS aspect-ratio) on every img/video/iframe — CLS zero-cost insurance.
  • loading="lazy" only below the fold; the browser handles the rest.

# Fonts

html
<link rel="preload" as="font" type="font/woff2" href="/fonts/inter-var.woff2" crossorigin>
css
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;      /* one variable file replaces 5 static weights */
  font-display: swap;        /* text visible immediately with fallback */
}
/* Reduce swap-induced shift: size-adjusted fallback */
@font-face {
  font-family: 'Inter-fallback';
  src: local('Arial');
  size-adjust: 107%;         /* match Inter's metrics; tune per family */
}

Subset with pyftsubset (fonttools) to the scripts actually used — typically 30–100 KB → under 15 KB.

# JavaScript: splitting and on-interaction loading

tsx
// Route-level splitting (React Router / Next.js does this per page by default)
const Settings = lazy(() => import('./Settings'));

// Widget on interaction — nothing loads until the user needs it
button.addEventListener('click', async () => {
  const { openChart } = await import('./chart.js');
  openChart(data);
}, { once: true });
bash
# Find what's actually in the bundle before removing anything
npx source-map-explorer dist/assets/*.js

# Third-party scripts: facades and idle loading

html
<!-- Facade: static thumbnail replaces a 500 KB embed until clicked -->
<button class="yt-facade" data-id="VIDEO_ID"
        style="background: url('https://i.ytimg.com/vi/VIDEO_ID/hqdefault.jpg')">▶</button>
<script>
  document.querySelector('.yt-facade').addEventListener('click', (e) => {
    const iframe = document.createElement('iframe');
    iframe.src = `https://www.youtube.com/embed/${e.currentTarget.dataset.id}?autoplay=1`;
    iframe.width = 560; iframe.height = 315; iframe.allow = 'autoplay';
    e.currentTarget.replaceWith(iframe);
  }, { once: true });
</script>

<!-- Analytics after everything else -->
<script>
  addEventListener('load', () => {
    requestIdleCallback(() => import('/analytics.js'));
  });
</script>

# INP: breaking long tasks

js
// Yield to the main thread between chunks of work (>50 ms tasks block input)
async function processRows(rows) {
  for (const chunk of chunks(rows, 200)) {   // 200 rows ≈ stays under 50 ms
    renderChunk(chunk);
    await (scheduler.yield?.() ?? new Promise(r => setTimeout(r)));
  }
}

Pure computation (parsing, diffing, search indexing) → Web Worker; the main thread only renders.

# Measuring

bash
npx lighthouse https://example.com --preset=perf --form-factor=mobile --view
js
// Field data from real users
import { onLCP, onINP, onCLS } from 'web-vitals';
[onLCP, onINP, onCLS].forEach(fn => fn(m => navigator.sendBeacon('/vitals', JSON.stringify(m))));

# Gotchas

  • Lazy-loading the LCP image is the single most common self-inflicted LCP regression — audit every loading="lazy" above the fold.
  • preload overuse starves the network of bandwidth for actual critical resources — preload at most the LCP image and one font.
  • display: none fonts still download if declared in CSS — subset instead.
  • CLS from late-loading banners/toolbars: reserve the slot with min-height even when content is conditional.
  • Debounce vs INP: debouncing helps continuous input, but a slow handler needs chunking (see INP section) — debounce doesn't shorten the task.
  • Bundle analyzer lies about tree-shaking until you build in production mode — always analyze the production build.
  • CDN cache misses dominate TTFB for global users — check cf-cache-status / x-cache headers before optimizing the payload.