@tank/web-performance
1.0.0Skill
Description
Web performance optimization for modern JS apps. Core Web Vitals (LCP, INP, CLS), loading strategies, bundle optimization (tree-shaking, code splitting), resource hints, runtime performance (DOM batching, Web Workers, virtual lists), network optimization (caching, CDN, service workers), image optimization (AVIF, WebP, responsive), and third-party script management. Framework-agnostic. Synthesizes Grigorik, Wagner, web.dev, Chromium guides..
Download
Verified
tank install @tank/web-performanceWeb Performance
Measure first. Fix the bottleneck. Ship smaller, faster, leaner.
Core Philosophy
- Measure before optimizing. Lighthouse, CrUX, and DevTools profiling dictate priorities, not hunches.
- Ship less JavaScript. Every kilobyte costs parse time, compile time, and execution time on every device.
- Critical path is king. Identify what blocks first paint and first interaction. Eliminate everything else from that path.
- Perceived performance beats raw speed. Skeleton screens, optimistic updates, and progressive rendering make 3s feel like 1s.
- Performance is a budget, not a task. Set thresholds, automate enforcement, fail the build when budgets break.
Quick-Start: Symptom to Fix
"LCP is slow (>2.5s)"
- Identify the LCP element (DevTools > Performance > Timings).
- If image: add
fetchpriority="high", ensure no lazy-loading, use responsivesrcset. - If text: eliminate render-blocking CSS/fonts. Inline critical CSS. Use
font-display: swap. - If server-slow: check TTFB. Preconnect to origins. Consider CDN or edge rendering.
- -> See
references/core-web-vitals.md
"INP is high (>200ms)"
- Profile with DevTools > Performance. Find long tasks (>50ms).
- Break long tasks:
yield()viascheduler.yield()orsetTimeout(0). - Move heavy computation to Web Workers.
- Debounce rapid-fire input handlers. Use
requestAnimationFramefor visual updates. - -> See
references/runtime-performance.md
"CLS is bad (>0.1)"
- Set explicit
width/heighton images and videos. - Reserve space for dynamic content (ads, embeds, lazy-loaded sections).
- Avoid injecting content above the fold after initial render.
- Use
contain: layouton containers with dynamic children. - -> See
references/core-web-vitals.md
"Bundle is too large"
- Run bundle analyzer (
webpack-bundle-analyzer,vite-bundle-visualizer,source-map-explorer). - Identify largest chunks. Apply dynamic
import()for below-fold and interaction-gated features. - Audit dependencies: replace heavy libraries (moment -> date-fns, lodash -> lodash-es or native).
- Verify tree-shaking: use ESM imports, check
sideEffectsin package.json. - -> See
references/bundle-optimization.md
"Third-party scripts block rendering"
- Audit all third-party scripts. Move non-critical to
asyncordefer. - Implement facades for heavy embeds (YouTube, chat widgets, maps).
- Delay non-essential scripts until after user interaction or idle.
- -> See
references/network-and-caching.md
Loading Strategy Decision Tree
| Signal | Strategy |
|---|---|
| Above-fold, critical path | Static import, inline critical CSS |
| Below-fold component | import() on visibility (IntersectionObserver) |
| Triggered by user action (modal, dropdown) | import() on interaction (click/hover) |
| Entire route/page | Route-based code splitting |
| Large library used in one feature | Dynamic import, separate chunk |
| Third-party embed (YouTube, maps) | Facade pattern with lazy load |
Resource Hint Decision Tree
| Scenario | Hint | Example |
|---|---|---|
| LCP image or critical font | <link rel="preload"> | <link rel="preload" as="image" href="hero.webp"> |
| Next-page navigation likely | <link rel="prefetch"> | <link rel="prefetch" href="/dashboard.js"> |
| Third-party origin needed soon | <link rel="preconnect"> | <link rel="preconnect" href="https://cdn.example.com"> |
| ES module in critical path | <link rel="modulepreload"> | <link rel="modulepreload" href="/app.js"> |
| Many possible next origins | <link rel="dns-prefetch"> | <link rel="dns-prefetch" href="https://api.example.com"> |
See references/loading-strategies.md for import patterns and splitting techniques.
Image Format Decision Tree
| Content Type | Format | Fallback |
|---|---|---|
| Photographic content | AVIF > WebP > JPEG | <picture> with source sets |
| Graphics, logos, icons | SVG (vector) or WebP | PNG-8 for simple graphics |
| Animated content | Animated WebP or short video | GIF (last resort) |
| Thumbnails / placeholders | LQIP (blurred tiny image) or CSS gradient | Solid color placeholder |
See references/image-optimization.md for responsive images, lazy loading, and LQIP patterns.
Performance Budget Template
| Metric | Target | Action |
|---|---|---|
| LCP | < 2.5s (p75) | Block deploy if exceeded |
| INP | < 200ms (p75) | Alert, investigate |
| CLS | < 0.1 (p75) | Block deploy if exceeded |
| Total JS (compressed) | < 200 KB | Fail CI build |
| Total CSS (compressed) | < 50 KB | Warn in CI |
| Largest single chunk | < 100 KB | Warn, suggest splitting |
| Hero image | < 200 KB | Warn, suggest compression |
Anti-Patterns
| Anti-Pattern | Impact | Fix |
|---|---|---|
| Importing entire lodash | +70 KB bundle | Cherry-pick or use lodash-es |
Synchronous <script> in <head> | Blocks parsing | Move to body end, add defer |
| Unoptimized hero image (5 MB PNG) | LCP > 5s | Compress, serve WebP/AVIF, use srcset |
| Layout reads interleaved with writes | Forced synchronous layout | Batch reads then writes, use rAF |
No width/height on images | CLS spikes | Always set intrinsic dimensions |
| Polling instead of event-driven | Wasted CPU, battery drain | Use MutationObserver, IntersectionObserver, SSE |
| Bundling unused polyfills | +30-50 KB | Use browserslist and differential serving |
| Inlining everything | Defeats caching | Inline only critical CSS; externalize the rest |
Reference Index
| File | Contents |
|---|---|
references/core-web-vitals.md | LCP, INP, CLS measurement, diagnosis workflows, optimization patterns, field vs lab data |
references/loading-strategies.md | Static/dynamic imports, route splitting, import-on-interaction, import-on-visibility, resource hints |
references/bundle-optimization.md | Tree-shaking, code splitting, chunk strategies, bundle analysis tools, dependency auditing |
references/runtime-performance.md | DOM batching, requestAnimationFrame, Web Workers, virtual lists, event delegation, long tasks |
references/network-and-caching.md | Compression, HTTP/2+, caching headers, CDN strategy, service workers, third-party script management |
references/image-optimization.md | Modern formats (AVIF, WebP), responsive images, lazy loading, LQIP, video replacement, CDN transforms |