How do you systematically find and fix frontend performance problems?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
Measure first (RUM field data for what users feel, Lighthouse/WebPageTest lab runs for diagnosis), profile the bottleneck (Performance panel, bundle analyzer, backend traces), fix the biggest offender, then lock gains with performance budgets in CI. Never optimize without a number before and after.
Detailed explanation
Random optimization wastes effort on non-bottlenecks, so follow the loop. First, establish truth: field data (Real User Monitoring — CrUX, web-vitals library) shows the 75th-percentile LCP/INP/CLS across real devices and networks, segmented by route, device class, and geography — your laptop on office Wi-Fi is not your user base. Second, reproduce in the lab: Lighthouse CI and WebPageTest on throttled Moto-G4/4G profiles give repeatable numbers plus opportunity lists sorted by savings. Third, profile the specific bottleneck: DevTools Performance panel flame chart (long tasks blocking INP? forced reflows? main-thread parse of a giant bundle?), Coverage drawer (unused CSS/JS shipped), bundle analyzer (which dependency owns the kilobytes), backend traces for slow TTFB. Fourth, fix top-down: server/edge caching and CDN for TTFB, code splitting and deferral for JS weight, media optimization for LCP, transform-only animations and task yielding for INP, reserved space for CLS. Fifth, prevent regression: performance budgets (e.g., JS < 200KB, LCP < 2.5s on lab profile) enforced in CI via Lighthouse assertions or bundlesize checks, plus RUM alerting on releases. Report impact in business terms — conversion and bounce move with the vitals — because budgets survive only with stakeholder buy-in.
Example
// Ship RUM in one snippet, alert on regressions
// import { onLCP, onINP, onCLS } from 'web-vitals';
// onLCP((m) => report('/analytics', { metric: 'LCP', value: m.value, route }));
// Lighthouse CI budget (lighthouserc.json)
// {
// "assert": {
// "assertions": {
// "largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
// "cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
// "resource-summary:script:size": ["error", { "maxNumericValue": 200000 }]
// }
// }
// }Interview tip
Recite the loop — field data, lab reproduce, profile, fix biggest, budget in CI — and stress that field data judges while lab diagnoses. Framing impact in conversion terms shows senior ownership.
Common mistakes
- Optimizing from lab scores alone while field data disagrees.
- Fixing small wins while a single giant bundle dominates.
- Shipping gains with no CI budgets, watching them regress in a month.