Skip to content

React Performance Auditing

FieldValue
TypeSkill Resource
Source~/.copilot/skills/frontend/references/react-perf.md
DescriptionNot specified

Source Content

React Performance Auditing

Audit a React app for performance regressions with Lighthouse, react-scan render heatmaps, bundle inspection, and CrUX/RUM field data — then lock the wins in with a CI perf budget. Absorbed from the former react-perf-auditor skill.

Use for

  • Users report sluggishness or a specific slow interaction.
  • Web Vitals (LCP, INP, CLS) regressed in production.
  • Pre-launch sweep before a feature, marketing push, or major release.
  • Quarterly preventive audit.

How it works

  1. Baseline. npx lighthouse <url> --preset=desktop --output=json --output=html against production. Capture LCP, INP, CLS, TBT, total bytes.
  2. Render hotspots. Run react-scan in dev, exercise key flows, screenshot heatmap. Flag any component re-rendering >5×/interaction.
  3. Bundle analysis. vite build --mode=analyze (rollup-plugin-visualizer) or npx source-map-explorer. Top 10 modules by size; flag any >50KB gzipped chunk not lazy-loaded.
  4. Image audit. Every <img> not AVIF/WebP, missing loading="lazy", missing width/height, or oversized → fix list.
  5. Network audit. DevTools Performance tab; serial waterfalls → batch with TanStack Query or hoist to a Router loader.
  6. State audit. useState that should be URL state; Context providers wrapping >50% of the tree (should be Zustand); prop drilling >3 levels.
  7. Prioritize. Score each finding estimated_ms_saved / hours_to_fix. Top 5 first.
  8. Fix and re-measure. Implement, re-run Lighthouse, verify Web Vitals improvement.
  9. Lock it in. Add bundlewatch or size-limit to CI with budgets matching the new baseline. Optional Playwright perf test asserting LCP < target.

Examples

  • “Users say the dashboard feels slow” → baseline with Lighthouse on prod, run react-scan against the dashboard flow, and return a ranked top-5 with measured ms-saved per fix.
  • “Our LCP regressed from 1.8s to 3.4s — find it” → diff the bundle against the last release, audit hero images for missing width/height/AVIF, and check for a new render-blocking script.
  • “Before we launch, do a perf sweep” → run the full audit (Lighthouse + react-scan + bundle + image + network + state), implement the top 5 fixes, re-measure, and wire size-limit into CI at the new baseline.
  • “Should I memo all these components?” → no — React.memo after a profiler trace, not before. Show the trace first.

Quick wins to check first

  • React.lazy for routes off the critical path.
  • loading="lazy", width/height, AVIF/WebP for below-fold images.
  • Virtualization (TanStack Virtual) for any list >100 items.
  • useDeferredValue for input-driven heavy renders.
  • Drop dead imports — many “wins” are ghost dependencies.

Self-rubric

  • Numbers, not vibes. Every finding has a measured ms / KB / count.
  • Ranked by leverage. Top 5 are the highest ms_saved / hours_to_fix, not the easiest.
  • Re-measured after fixes. Lighthouse re-run, delta reported.
  • CI guard added. A budget exists so the regression can’t sneak back.
  • No premature memo. Memoization is justified by a profiler trace.
  • Web Vitals named. Wins map to LCP / INP / CLS, not just “feels faster”.
  • Validated: scripts/check_perf_report.sh REPORT.md [REPO_ROOT] exits 0.

scripts/check_perf_report.sh REPORT.md [REPO_ROOT] fails if the report has no real before/after numeric comparison (a number with a unit — ms/KB/MB/fps/s — near before/after language), or if it references a CI perf budget file (e.g. budget.json, .bundlesizerc, lighthouserc*) that doesn’t actually exist on disk.

References