From c2c4f56d052677d64e60da4616be17a9f2e24870 Mon Sep 17 00:00:00 2001 From: Joan Leon Date: Wed, 8 Apr 2026 00:25:19 +0200 Subject: [PATCH] Improve performance-optimization skill with clearer guidance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Distinguish synthetic (Lighthouse) vs RUM (web-vitals) measurement approaches, clarifying when each is appropriate: synthetic for CI regression detection, RUM to validate real user impact. - Expand TTFB diagnosis from a single vague hint into a decision tree that breaks down each component (DNS, TCP/TLS, server processing) with specific next steps. Mirrors the tree in the skill and adds a dedicated checklist section. - Fix image optimization example: the previous "GOOD" example applied loading="lazy" without distinguishing the LCP hero image from below-the-fold images. Hero images must never be lazy-loaded. New example separates both cases explicitly. - Add art direction + resolution switching to the hero image example using with media queries for mobile/desktop crops and srcset for density variants. Mobile-first: fallback points to the mobile version. Covers AVIF → WebP → JPG format cascade and fetchpriority="high" for LCP. - Correct the date-fns tree-shaking example: modern bundlers (Vite, webpack 5+) handle named imports automatically. The "BAD" pattern was not actually bad, and following it could lead to unnecessary micro-optimizations. Real gains come from dynamic imports and route-level code splitting, which the example now illustrates instead. --- references/performance-checklist.md | 8 +++ skills/performance-optimization/SKILL.md | 78 +++++++++++++++++++----- 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/references/performance-checklist.md b/references/performance-checklist.md index 711cf37f..238b04ff 100644 --- a/references/performance-checklist.md +++ b/references/performance-checklist.md @@ -18,6 +18,14 @@ Quick reference checklist for web application performance. Use alongside the `pe | INP (Interaction to Next Paint) | ≤ 200ms | ≤ 500ms | > 500ms | | CLS (Cumulative Layout Shift) | ≤ 0.1 | ≤ 0.25 | > 0.25 | +## TTFB Diagnosis + +When TTFB is slow (> 600ms), check each component in DevTools Network waterfall: + +- [ ] **DNS resolution** slow → add `` or `` for known origins +- [ ] **TCP/TLS handshake** slow → enable HTTP/2, consider edge deployment, verify keep-alive +- [ ] **Server processing** slow → profile backend, check slow queries, add caching + ## Frontend Checklist ### Images diff --git a/skills/performance-optimization/SKILL.md b/skills/performance-optimization/SKILL.md index 676d2502..2839bf15 100644 --- a/skills/performance-optimization/SKILL.md +++ b/skills/performance-optimization/SKILL.md @@ -39,13 +39,18 @@ Measure before optimizing. Performance work without measurement is guessing — ### Step 1: Measure +Two complementary approaches — use both: + +- **Synthetic (Lighthouse, DevTools Performance tab):** Controlled conditions, reproducible. Best for CI regression detection and isolating specific issues. +- **RUM (web-vitals library, CrUX):** Real user data in real conditions. Required to validate that a fix actually improved user experience. + **Frontend:** ```bash -# Lighthouse in Chrome DevTools (or CI) +# Synthetic: Lighthouse in Chrome DevTools (or CI) # Chrome DevTools → Performance tab → Record # Chrome DevTools MCP → Performance trace -# Web Vitals library in code +# RUM: Web Vitals library in code import { onLCP, onINP, onCLS } from 'web-vitals'; onLCP(console.log); @@ -73,7 +78,10 @@ Use the symptom to decide what to measure first: What is slow? ├── First page load │ ├── Large bundle? --> Measure bundle size, check code splitting -│ ├── Slow server response? --> Measure TTFB, check API/database +│ ├── Slow server response? --> Measure TTFB in DevTools Network waterfall +│ │ ├── DNS long? --> Add dns-prefetch / preconnect for known origins +│ │ ├── TCP/TLS long? --> Enable HTTP/2, check edge deployment, keep-alive +│ │ └── Waiting (server) long? --> Profile backend, check queries and caching │ └── Render-blocking resources? --> Check network waterfall for CSS/JS blocking ├── Interaction feels sluggish │ ├── UI freezes on click? --> Profile main thread, look for long tasks (>50ms) @@ -144,18 +152,56 @@ const tasks = await db.tasks.findMany({ #### Missing Image Optimization (Frontend) ```html - + - + + + + + + + + + + Hero image description + + + Hero image description ``` @@ -188,14 +234,14 @@ function TaskStats({ tasks }: Props) { #### Large Bundle Size ```typescript -// BAD: Importing entire library -import { format } from 'date-fns'; - -// GOOD: Tree-shakable import (if the library supports it) -import { format } from 'date-fns/format'; +// Modern bundlers (Vite, webpack 5+) handle named imports with tree-shaking automatically. +// Profile before changing import styles — the real gains come from splitting and lazy loading. // GOOD: Dynamic import for heavy, rarely-used features const ChartLibrary = lazy(() => import('./ChartLibrary')); + +// GOOD: Route-level code splitting +const SettingsPage = lazy(() => import('./pages/Settings')); ``` #### Missing Caching (Backend)