skills/web-performance/SKILL.md
Web performance analysis and optimization across the full stack. Use when the user asks about Core Web Vitals, Lighthouse audits, page speed, load times, bundle size reduction, image optimization, caching strategies, code splitting, lazy loading, font loading, compression, CDN configuration, render-blocking resources, performance budgets, real user monitoring, synthetic monitoring, server-side rendering performance, Time to First Byte, First Contentful Paint, Largest Contentful Paint, Cumulative Layout Shift, or any aspect of making websites and web applications faster.
npx skillsauth add 1mangesh1/dev-skills-collection web-performanceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Reference for diagnosing and improving web application performance, covering measurement, asset delivery, rendering, caching, and monitoring.
Measures time until the largest visible content element (image, video poster, or text block) finishes rendering.
Replaced FID in March 2024. Measures latency of all click, tap, and keyboard interactions, reports near the worst case.
Measures unexpected layout shifts across the page lifespan.
npx lighthouse URL), or the Node API.pagespeed.web.dev) combines lab (Lighthouse) and field (CrUX) data.Modern formats: WebP is 25-35% smaller than JPEG. AVIF is 20-50% smaller than WebP for photos. Use <picture> for format negotiation:
<picture>
<source type="image/avif" srcset="photo.avif">
<source type="image/webp" srcset="photo.webp">
<img src="photo.jpg" alt="Description" width="800" height="600">
</picture>
Responsive images: Serve different sizes via srcset and sizes to avoid oversized downloads:
<img srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
src="photo-800.jpg" alt="Description" width="800" height="600">
Lazy loading: Use loading="lazy" on offscreen images. Do not lazy-load the LCP image; use fetchpriority="high" on it instead.
Image CDNs (Cloudinary, imgix, Cloudflare Images) resize, compress, and convert images on the fly via URL parameters.
// Route-based splitting in React
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
// Manual dynamic import
const { Editor } = await import('./Editor');
import/export) so bundlers can eliminate dead code.import * as lib when you only need specific functions."module" field in package.json)."sideEffects": false in package.json.requestIdleCallback, scheduler.postTask, or setTimeout(fn, 0).<script defer> or <script type="module">.Critical CSS: Inline above-the-fold CSS in <head>, load the full stylesheet asynchronously:
<head>
<style>/* Critical CSS inlined here */</style>
<link rel="preload" href="styles.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
</head>
Tools like the critical npm package can extract critical CSS automatically.
Reducing render-blocking CSS: Split CSS per route, use media attributes on non-applicable stylesheets, avoid @import (it creates sequential requests).
CSS Containment:
.card {
contain: layout style paint;
content-visibility: auto;
contain-intrinsic-size: 0 200px;
}
content-visibility: auto skips rendering for offscreen elements. Provide contain-intrinsic-size to preserve scroll position.
@font-face {
font-family: 'CustomFont';
src: url('custom.woff2') format('woff2');
font-display: swap; /* or optional, fallback */
}
swap: shows fallback text immediately, swaps on load. Risk of layout shift.optional: uses fallback for the whole visit if the font does not load quickly. Best for non-critical fonts.<link rel="preload" href="custom.woff2" as="font" type="font/woff2" crossorigin>.pyftsubset, glyphhanger, or Google Fonts &text= parameter.Cache-Control: public, max-age=31536000, immutable # hashed assets
Cache-Control: no-cache # HTML (always revalidate)
Cache-Control: private, max-age=0, must-revalidate # API responses
immutable: skip revalidation on reload; safe only for content-hashed URLs.no-cache: always revalidate (not the same as no-store).stale-while-revalidate: serve stale content while fetching fresh copy in the background.ETags enable conditional requests via If-None-Match. The server responds 304 Not Modified if unchanged, saving bandwidth.
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
return cached || fetch(event.request).then((response) => {
const clone = response.clone();
caches.open('v1').then((cache) => cache.put(event.request, clone));
return response;
});
})
);
});
Strategies: cache-first (static assets), network-first (API calls), stale-while-revalidate (balance of speed and freshness).
| Algorithm | Savings vs. Uncompressed | Browser Support | Notes | |-----------|--------------------------|-----------------|-------| | gzip | 60-80% | Universal | Baseline everywhere | | Brotli | 15-25% smaller than gzip | All modern browsers | Best for pre-compressed static assets | | zstd | Comparable to Brotli | Chrome 123+, Firefox 126+ | Faster compression, emerging support |
Vary: Accept-Encoding so caches store separate versions per encoding.<link rel="preload" href="critical.js" as="script">
<link rel="preload" href="hero.avif" as="image" type="image/avif">
<link rel="prefetch" href="/next-page.js">
<link rel="preconnect" href="https://api.example.com">
<link rel="dns-prefetch" href="https://analytics.example.com">
fetchpriority="high" on the LCP image, fetchpriority="low" on non-critical resources.Server-Side Rendering (SSR): Server generates full HTML per request. Faster FCP, better SEO, but higher server load. Frameworks: Next.js, Nuxt, SvelteKit, Remix.
Static Site Generation (SSG): Pages pre-rendered at build time, served from CDN. Fastest TTFB. Not suitable for highly dynamic content. ISR (Next.js) bridges the gap.
Client-Side Rendering (CSR): Minimal HTML shell; JS fetches data and renders. Slower initial paint. Good for authenticated apps behind login. Mitigate with code splitting and skeleton screens.
Streaming and Partial Hydration: Streaming SSR sends HTML in chunks as data resolves. Partial hydration only hydrates interactive components. React Server Components mix server and client rendering in one tree.
webpack-bundle-analyzer:
npx webpack --profile --json > stats.json
npx webpack-bundle-analyzer stats.json
Look for duplicate libraries, oversized dependencies, and unstripped locale data.
source-map-explorer:
npx source-map-explorer dist/main.js dist/main.js.map
Works with any bundler that produces source maps.
Import Cost editor plugins show the size of each import inline during development.
Slow queries directly increase TTFB for SSR pages and API response times for CSR apps.
web-vitals JS library reports LCP, INP, CLS, FCP, and TTFB to your analytics endpoint.| Metric | Example Budget | |--------|---------------| | Total JS (compressed) | < 200 KB | | Total CSS (compressed) | < 50 KB | | Total images per page | < 500 KB | | Total font files | < 100 KB | | LCP | < 2.5s | | INP | < 200ms | | CLS | < 0.1 | | Total page weight | < 1 MB |
Enforcement: bundlesize or size-limit in CI, Lighthouse CI assertions, webpack performance.maxAssetSize.
depcheck or knip.fetchpriority="high".font-display: swap or optional, subset unused glyphs.tools
Parallel execution with xargs, GNU parallel, and batch processing patterns. Use when user mentions "xargs", "parallel", "batch processing", "run in parallel", "parallel execution", "process list of files", "bulk operations", "concurrent commands", "map over files", or running commands on multiple inputs.
development
WebSocket implementation for real-time bidirectional communication. Use when user mentions "websocket", "ws://", "wss://", "real-time", "live updates", "chat application", "socket.io", "Server-Sent Events", "SSE", "push notifications", "live data", "streaming data", "bidirectional communication", "websocket server", "reconnection", or building real-time features.
tools
Frontend bundler configuration for Webpack and Vite. Use when user mentions "webpack", "vite", "bundler", "vite config", "webpack config", "code splitting", "tree shaking", "hot module replacement", "HMR", "build optimization", "bundle size", "chunk splitting", "loader", "plugin", "esbuild", "rollup", "dev server", or configuring JavaScript build tools.
tools
VS Code configuration, extensions, keybindings, and workspace optimization. Use when user mentions "vscode", "vs code", "vscode settings", "vscode extensions", "keybindings", "code editor", "workspace settings", "settings.json", "launch.json", "tasks.json", "vscode snippets", "devcontainer", "remote development", or customizing their VS Code setup.