45+ Web Performance i Core Web Vitals Pytania Rekrutacyjne 2026: LCP, INP i CLS - Flipcards

45+ Web Performance i Core Web Vitals Pytania Rekrutacyjne 2026: LCP, INP i CLS

Sławomir Plamowski 17 min czytania
cls core-web-vitals frontend inp lcp lighthouse pytania-rekrutacyjne web-performance

Wydajność stron to obszar, który wyróżnia seniorów od juniorów. Na rozmowach rekrutacyjnych pytania o Core Web Vitals, optymalizację i narzędzia pojawiają się coraz częściej - szczególnie w firmach dbających o UX i SEO. Ten przewodnik zawiera 45 pytań z odpowiedziami - od podstaw po zaawansowane techniki optymalizacji.

Spis Treści

  1. Dlaczego Wydajność Jest Ważna Pytania
  2. Core Web Vitals Pytania
  3. Optymalizacja Ładowania Pytania
  4. Optymalizacja Obrazów Pytania
  5. JavaScript Performance Pytania
  6. Narzędzia i Monitoring Pytania
  7. Powiązane Artykuły

Dlaczego Wydajność Jest Ważna Pytania

Jaki jest wpływ wydajności na biznes i UX?

Odpowiedź w 30 sekund: Każda sekunda opóźnienia = spadek konwersji o 7%. Google używa Core Web Vitals jako czynnika rankingowego. Wolne strony = wyższy bounce rate, mniej zakupów, gorsze SEO. Amazon: 100ms opóźnienia = 1% spadek sprzedaży.

Odpowiedź w 2 minuty:

Wydajność ma bezpośredni wpływ na biznesowe wskaźniki konwersji i zaangażowania użytkowników. Poniższa tabela pokazuje korelację między czasem ładowania a bounce rate oraz konwersją:

Wpływ wydajności na metryki biznesowe:

┌────────────────────────────────────────────────────────────┐
│  Czas ładowania    │  Bounce Rate  │  Konwersja           │
├────────────────────┼───────────────┼──────────────────────┤
│  1-2 sekundy       │  ~9%          │  Baseline            │
│  3 sekundy         │  ~32%         │  -7%                 │
│  5 sekund          │  ~90%         │  -20%                │
│  10+ sekund        │  ~123%        │  Katastrofa          │
└────────────────────────────────────────────────────────────┘

Case studies:

  • Pinterest: -40% czasu ładowania → +15% rejestracji
  • BBC: +1s ładowania → -10% użytkowników
  • Walmart: -1s ładowania → +2% konwersji
  • Google: +0.5s → -20% wyszukiwań

Core Web Vitals i SEO (od 2021):

Google Page Experience Signals:
├── Core Web Vitals (LCP, INP, CLS)
├── Mobile-friendly
├── HTTPS
├── No intrusive interstitials
└── Safe browsing

Czym jest Critical Rendering Path?

Odpowiedź w 30 sekund: Critical Rendering Path to sekwencja kroków przeglądarki do pierwszego renderowania: HTML → DOM → CSS → CSSOM → Render Tree → Layout → Paint. Optymalizacja polega na minimalizacji render-blocking resources i Critical CSS inline.

Odpowiedź w 2 minuty:

Critical Rendering Path składa się z kilku sekwencyjnych kroków, które przeglądarka wykonuje aby wyrenderować stronę. Poniższy diagram przedstawia pełny proces od parsowania HTML do wyświetlenia pikseli:

Critical Rendering Path:

HTML ──────► DOM Tree
               │
               ▼
CSS ───────► CSSOM Tree ──┐
                          │
               ┌──────────┘
               ▼
         Render Tree
               │
               ▼
           Layout (Reflow)
               │
               ▼
           Paint
               │
               ▼
          Composite
               │
               ▼
         🖥️ Pixels na ekranie

Render-blocking resources:

<!-- ❌ Blokuje rendering -->
<link rel="stylesheet" href="styles.css">
<script src="app.js"></script>

<!-- ✅ Nie blokuje -->
<link rel="stylesheet" href="print.css" media="print">
<script src="app.js" defer></script>
<script src="analytics.js" async></script>

Optymalizacja Critical Path:

<!-- 1. Inline Critical CSS -->
<style>
  /* Only above-the-fold styles */
  .header { ... }
  .hero { ... }
</style>

<!-- 2. Defer non-critical CSS -->
<link rel="preload" href="styles.css" as="style"
      onload="this.onload=null;this.rel='stylesheet'">

<!-- 3. Preconnect do external origins -->
<link rel="preconnect" href="https://fonts.googleapis.com">

<!-- 4. Defer/async scripts -->
<script src="app.js" defer></script>

Core Web Vitals Pytania

Czym są Core Web Vitals i jakie są ich wartości docelowe?

Odpowiedź w 30 sekund: Core Web Vitals to 3 metryki Google mierzące UX: LCP (szybkość ładowania) < 2.5s, INP (responsywność) < 200ms, CLS (stabilność) < 0.1. Od marca 2024 INP zastąpił FID. Wpływają na ranking w Google.

Odpowiedź w 2 minuty:

Core Web Vitals składają się z trzech kluczowych metryk, które Google uznaje za fundamentalne dla użyteczności stron. Poniższy diagram przedstawia wszystkie trzy metryki wraz z progami dla dobrych, średnich i złych wyników:

CORE WEB VITALS (2024+)

┌─────────────────────────────────────────────────────────────────┐
│                                                                  │
│   LCP (Largest Contentful Paint)                                │
│   "Jak szybko widzę główną treść?"                              │
│   ┌────────┬────────────┬────────────┐                          │
│   │ Good   │ Needs Work │ Poor       │                          │
│   │ <2.5s  │ 2.5s-4s    │ >4s        │                          │
│   └────────┴────────────┴────────────┘                          │
│                                                                  │
│   INP (Interaction to Next Paint) ← Zastąpił FID               │
│   "Jak szybko strona reaguje na moje akcje?"                    │
│   ┌────────┬────────────┬────────────┐                          │
│   │ Good   │ Needs Work │ Poor       │                          │
│   │ <200ms │ 200-500ms  │ >500ms     │                          │
│   └────────┴────────────┴────────────┘                          │
│                                                                  │
│   CLS (Cumulative Layout Shift)                                 │
│   "Czy coś się przesunęło niespodziewanie?"                     │
│   ┌────────┬────────────┬────────────┐                          │
│   │ Good   │ Needs Work │ Poor       │                          │
│   │ <0.1   │ 0.1-0.25   │ >0.25      │                          │
│   └────────┴────────────┴────────────┘                          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Jak mierzyć w kodzie:

import { onLCP, onINP, onCLS } from 'web-vitals'

onLCP(metric => {
  console.log('LCP:', metric.value)
  // Wyślij do analytics
})

onINP(metric => {
  console.log('INP:', metric.value)
})

onCLS(metric => {
  console.log('CLS:', metric.value)
})

Jak poprawić Largest Contentful Paint (LCP)?

Odpowiedź w 30 sekund: LCP mierzy czas do wyrenderowania największego elementu (obraz, tekst, video). Optymalizuj: preload głównego obrazu, szybki TTFB, usuń render-blocking CSS/JS, użyj CDN, lazy load tylko poniżej fold.

Odpowiedź w 2 minuty:

Co wpływa na LCP:

LCP = TTFB + Resource Load Time + Render Time

1. TTFB (Time to First Byte)
   └── Serwer, DNS, SSL, redirect

2. Resource Load Time
   └── Obrazy, fonty, CSS

3. Render Time
   └── JavaScript, CSS parsing

Optymalizacje:

<!-- 1. Preload LCP image -->
<link rel="preload" as="image" href="hero.webp"
      imagesrcset="hero-400.webp 400w, hero-800.webp 800w"
      imagesizes="100vw">

<!-- 2. Preconnect do CDN -->
<link rel="preconnect" href="https://cdn.example.com">

<!-- 3. Fetchpriority dla LCP image -->
<img src="hero.webp" fetchpriority="high" alt="Hero">

<!-- 4. Inline Critical CSS -->
<style>
  .hero-image { width: 100%; height: auto; }
</style>
// 5. Unikaj client-side rendering dla LCP
// ❌ CSR - LCP element renderowany przez JS
function Hero() {
  const [data, setData] = useState(null)
  useEffect(() => { fetchData() }, [])
  if (!data) return null  // LCP element nie istnieje!
  return <img src={data.heroUrl} />
}

// ✅ SSR/SSG - LCP element w HTML
// Next.js / Remix - HTML zawiera już obraz

Checklist LCP:

  • TTFB < 800ms
  • Preload LCP image/font
  • fetchpriority="high" na LCP element
  • Nie lazy-load LCP image
  • Inline Critical CSS
  • Usuń render-blocking JS

Czym jest INP i czym różni się od FID?

Odpowiedź w 30 sekund: INP (Interaction to Next Paint) mierzy responsywność WSZYSTKICH interakcji użytkownika przez całą sesję. FID mierzył tylko PIERWSZĄ interakcję. INP zastąpił FID w marcu 2024. Dobra wartość INP < 200ms.

Odpowiedź w 2 minuty:

Główna różnica między FID a INP polega na zakresie pomiaru - FID mierzył tylko pierwszą interakcję, podczas gdy INP analizuje wszystkie interakcje podczas całej sesji użytkownika. Porównanie obu metryk:

FID vs INP:

FID (First Input Delay) - przestarzałe
├── Mierzy tylko PIERWSZĄ interakcję
├── Często dobry wynik (strona jeszcze nie zablokowana)
└── Nie odzwierciedla prawdziwego UX

INP (Interaction to Next Paint) - aktualne
├── Mierzy WSZYSTKIE interakcje
├── Bierze p75 najwolniejszych
└── Lepiej odzwierciedla rzeczywistość

Co powoduje słaby INP:

// ❌ Long Task blokujący main thread
button.addEventListener('click', () => {
  // Synchroniczna operacja > 50ms
  for (let i = 0; i < 1000000; i++) {
    heavyComputation()
  }
  updateUI()
})

// ✅ Yield to main thread
button.addEventListener('click', async () => {
  // Podziel na mniejsze kawałki
  for (let i = 0; i < 1000; i++) {
    await processChunk(i)

    // Yield co 50ms
    if (i % 100 === 0) {
      await scheduler.yield()  // lub setTimeout(0)
    }
  }
  updateUI()
})

Optymalizacje INP:

// 1. Web Workers dla heavy computation
const worker = new Worker('heavy-task.js')
worker.postMessage(data)
worker.onmessage = (e) => updateUI(e.data)

// 2. requestIdleCallback dla non-critical
requestIdleCallback(() => {
  // Analytics, prefetching, etc.
})

// 3. Debounce/throttle dla częstych zdarzeń
const handleScroll = throttle(() => {
  // Scroll handler
}, 100)

// 4. CSS contain dla izolacji layout
.component {
  contain: layout style paint;
}

Jak unikać Cumulative Layout Shift (CLS)?

Odpowiedź w 30 sekund: CLS mierzy nieoczekiwane przesunięcia elementów. Unikaj przez: wymiary dla obrazów (width/height), rezerwację miejsca na reklamy/embedy, preload fontów, unikanie wstawiania treści powyżej istniejącej.

Odpowiedź w 2 minuty:

CLS obliczany jest jako suma przesunięć wszystkich elementów, które niespodziewanie zmieniły swoją pozycję. Poniższy przykład ilustruje typowy scenariusz, w którym wstawienie reklamy powoduje przesunięcie treści:

CLS = Σ (Impact Fraction × Distance Fraction)

Przykład złego CLS:
┌─────────────────────┐      ┌─────────────────────┐
│      Header         │      │      Header         │
├─────────────────────┤      ├─────────────────────┤
│                     │      │   [REKLAMA]         │  ← Wstawiona
│      Content        │ ──►  ├─────────────────────┤     nagle!
│                     │      │                     │
│                     │      │      Content        │  ← Przesunięty
└─────────────────────┘      └─────────────────────┘

Główne przyczyny i rozwiązania:

<!-- 1. OBRAZY - brak wymiarów -->
<!-- ❌ Powoduje CLS -->
<img src="photo.jpg" alt="Photo">

<!-- ✅ Ustaw wymiary -->
<img src="photo.jpg" alt="Photo" width="800" height="600">

<!-- ✅ Lub aspect-ratio w CSS -->
<style>
  .responsive-img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
  }
</style>


<!-- 2. FONTY - FOUT/FOIT -->
<!-- ❌ Powoduje CLS gdy font się załaduje -->
@font-face {
  font-family: 'Custom';
  src: url('font.woff2');
}

<!-- ✅ font-display: optional (brak CLS) -->
@font-face {
  font-family: 'Custom';
  src: url('font.woff2');
  font-display: optional;
}


<!-- 3. REKLAMY / EMBEDY -->
<!-- ❌ Brak zarezerwowanego miejsca -->
<div id="ad-container"></div>

<!-- ✅ Zarezerwuj minimum miejsca -->
<div id="ad-container" style="min-height: 250px;"></div>


<!-- 4. DYNAMICZNA TREŚĆ -->
<!-- ❌ Wstawianie powyżej istniejącej treści -->
container.prepend(newElement)

<!-- ✅ Wstawiaj poniżej lub z animacją -->
container.append(newElement)
<!-- lub użyj transform do animacji -->

Animacje bez CLS:

/* ❌ Powoduje reflow/repaint */
.animate {
  animation: bad 0.3s;
}
@keyframes bad {
  from { height: 0; margin-top: 100px; }
  to { height: 100px; margin-top: 0; }
}

/* ✅ Tylko transform i opacity */
.animate {
  animation: good 0.3s;
}
@keyframes good {
  from { transform: translateY(100px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

Optymalizacja Ładowania Pytania

Czym jest lazy loading i jak go zaimplementować?

Odpowiedź w 30 sekund: Lazy loading opóźnia ładowanie zasobów do momentu gdy są potrzebne (np. obrazy poniżej fold). Native: loading="lazy" dla img/iframe. JavaScript: Intersection Observer. Nie lazy-load zasobów LCP!

Odpowiedź w 2 minuty:

Najprościej zaimplementować lazy loading używając natywnego atrybutu loading="lazy" dostępnego we wszystkich nowoczesnych przeglądarkach. Przykłady użycia:

<!-- NATIVE LAZY LOADING (rekomendowane) -->
<img src="photo.jpg" loading="lazy" alt="Photo">
<iframe src="embed.html" loading="lazy"></iframe>

<!-- Nie używaj dla LCP! -->
<img src="hero.jpg" loading="eager" fetchpriority="high" alt="Hero">

Intersection Observer (więcej kontroli):

// Lazy loading z Intersection Observer
const lazyImages = document.querySelectorAll('img[data-src]')

const imageObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target
      img.src = img.dataset.src
      img.removeAttribute('data-src')
      observer.unobserve(img)
    }
  })
}, {
  rootMargin: '100px'  // Załaduj 100px przed viewport
})

lazyImages.forEach(img => imageObserver.observe(img))

React - lazy loading komponentów:

import { lazy, Suspense } from 'react'

// Code splitting na poziomie route
const Dashboard = lazy(() => import('./Dashboard'))
const Settings = lazy(() => import('./Settings'))

function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/settings" element={<Settings />} />
      </Routes>
    </Suspense>
  )
}

Czym są preload, prefetch i preconnect?

Odpowiedź w 30 sekund: preload - załaduj zasób natychmiast (critical resources). prefetch - załaduj w tle dla przyszłej nawigacji (low priority). preconnect - nawiąż połączenie z serwerem (DNS, TCP, TLS). Używaj oszczędnie - zbyt wiele może zaszkodzić.

Odpowiedź w 2 minuty:

Każda z tych technik służy różnym celom i ma swój poziom priorytetu. Poniższe przykłady pokazują prawidłowe użycie preconnect, preload i prefetch dla różnych scenariuszy:

<!-- PRECONNECT - nawiąż połączenie wcześnie -->
<!-- Użyj dla zewnętrznych domen (CDN, API, fonty) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>

<!-- DNS-PREFETCH - tylko DNS lookup (fallback) -->
<link rel="dns-prefetch" href="https://analytics.com">


<!-- PRELOAD - załaduj natychmiast (HIGH priority) -->
<!-- Użyj dla critical resources: LCP image, fonty, critical JS -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero.webp" as="image">
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

<!-- Preload z media query -->
<link rel="preload" href="mobile.jpg" as="image"
      media="(max-width: 600px)">


<!-- PREFETCH - załaduj dla przyszłej nawigacji (LOW priority) -->
<!-- Użyj dla next page resources -->
<link rel="prefetch" href="/next-page.html">
<link rel="prefetch" href="/next-page-data.json">

<!-- Modulepreload dla ES modules -->
<link rel="modulepreload" href="/app.js">

Kiedy używać czego:

Technika Priorytet Kiedy używać
preconnect Wysoki External domains (max 2-3)
preload Wysoki LCP image, critical fonts, critical CSS
prefetch Niski Next page resources
dns-prefetch Niski Wiele external domains

Uwagi:

<!-- ❌ Za dużo preload = wolniejsze ładowanie -->
<link rel="preload" href="a.js" as="script">
<link rel="preload" href="b.js" as="script">
<link rel="preload" href="c.js" as="script">
<!-- ... 20 więcej -->

<!-- ✅ Tylko naprawdę critical (2-5 max) -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero.webp" as="image">

Optymalizacja Obrazów Pytania

Jakie formaty obrazów są najlepsze dla web?

Odpowiedź w 30 sekund: WebP - 25-35% mniejsze niż JPEG, szeroko wspierane. AVIF - 50% mniejsze, rosnące wsparcie. JPEG - fallback dla starszych przeglądarek. PNG - przezroczystość (ale WebP lepszy). SVG - ikony i ilustracje wektorowe.

Odpowiedź w 2 minuty:

Nowoczesne formaty obrazów oferują znacznie lepszą kompresję niż tradycyjne JPEG i PNG. Element <picture> pozwala zdefiniować wiele formatów, z których przeglądarka wybierze najlepszy wspierany:

<!-- PICTURE element dla różnych formatów -->
<picture>
  <!-- AVIF - najlepszy jeśli wspierany -->
  <source srcset="photo.avif" type="image/avif">

  <!-- WebP - szeroko wspierany -->
  <source srcset="photo.webp" type="image/webp">

  <!-- JPEG - fallback -->
  <img src="photo.jpg" alt="Photo" width="800" height="600">
</picture>
Format Kompresja Przezroczystość Animacje Wsparcie
AVIF Najlepsza Tak Tak ~93%
WebP Bardzo dobra Tak Tak ~97%
JPEG Dobra Nie Nie 100%
PNG Bezstratna Tak Nie 100%
SVG Wektorowa Tak Tak 100%

Responsive images:

<!-- srcset + sizes dla różnych rozmiarów ekranu -->
<img
  srcset="photo-400.webp 400w,
          photo-800.webp 800w,
          photo-1200.webp 1200w"
  sizes="(max-width: 600px) 100vw,
         (max-width: 1200px) 50vw,
         800px"
  src="photo-800.webp"
  alt="Photo"
  loading="lazy"
  decoding="async"
>

Narzędzia do optymalizacji:

# squoosh (online/CLI)
npx @squoosh/cli --webp '{"quality": 80}' photo.jpg

# sharp (Node.js)
sharp('input.jpg').webp({ quality: 80 }).toFile('output.webp')

# imagemin (build pipeline)
# Next.js Image component (automatyczna optymalizacja)

JavaScript Performance Pytania

Jak JavaScript blokuje rendering?

Odpowiedź w 30 sekund: JavaScript domyślnie blokuje parsing HTML i rendering (parser-blocking). Rozwiązania: defer (wykonaj po parsingu), async (pobierz równolegle, wykonaj natychmiast), dynamiczny import dla code splitting.

Odpowiedź w 2 minuty:

JavaScript domyślnie blokuje parsowanie HTML, co znacząco wydłuża czas do pierwszego renderowania. Atrybuty defer i async pozwalają kontrolować sposób ładowania i wykonywania skryptów:

<!-- ❌ PARSER-BLOCKING (domyślne) -->
<script src="app.js"></script>
<!--
  1. HTML parsing ZATRZYMANE
  2. Pobierz app.js
  3. Wykonaj app.js
  4. Kontynuuj parsing HTML
-->


<!-- ✅ DEFER - pobierz równolegle, wykonaj po parsingu -->
<script src="app.js" defer></script>
<!--
  1. HTML parsing KONTYNUOWANE
  2. Pobierz app.js równolegle
  3. Po zakończeniu parsingu HTML - wykonaj app.js
  4. DOMContentLoaded
-->


<!-- ✅ ASYNC - pobierz równolegle, wykonaj natychmiast -->
<script src="analytics.js" async></script>
<!--
  1. HTML parsing KONTYNUOWANE
  2. Pobierz analytics.js równolegle
  3. Gdy gotowe - PRZERWIJ parsing, wykonaj
  4. Kontynuuj parsing
-->
Wizualizacja:

         HTML Parsing ───────────────────────►

DEFAULT  ████████░░░░░░░░░░░████████████████████
         └─parse─┘└─download─┘└──execute──┘└─parse─┘

DEFER    ████████████████████████████████████░░░░
         └────────parse──────────────────┘└execute┘
                    └─download─┘

ASYNC    ████████████░░░░████████████████████████
         └──parse───┘└exec┘└─────parse──────────┘
              └download┘

Kiedy używać czego:

Atrybut Kiedy używać
(brak) Nigdy (chyba że w <body> na końcu)
defer Główna aplikacja, zależna od DOM
async Analytics, tracking, niezależne skrypty

Czym są Long Tasks i jak wpływają na INP?

Odpowiedź w 30 sekund: Long Task to zadanie JavaScript trwające > 50ms. Blokuje main thread, powodując słaby INP i "zamrożony" UI. Rozwiązania: dziel na mniejsze kawałki, yield to main thread, Web Workers, requestIdleCallback.

Odpowiedź w 2 minuty:

Long Tasks blokują główny wątek przeglądarki, uniemożliwiając przeglądарce reagowanie na interakcje użytkownika. Kluczowym rozwiązaniem jest dzielenie długich zadań na mniejsze fragmenty z wykorzystaniem yield to main thread:

// ❌ LONG TASK - blokuje main thread
function processLargeArray(items) {
  items.forEach(item => {
    heavyComputation(item)  // 1000 items × 1ms = 1000ms!
  })
}


// ✅ YIELD TO MAIN THREAD
async function processLargeArray(items) {
  const CHUNK_SIZE = 100

  for (let i = 0; i < items.length; i += CHUNK_SIZE) {
    const chunk = items.slice(i, i + CHUNK_SIZE)

    chunk.forEach(item => heavyComputation(item))

    // Pozwól przeglądarce obsłużyć eventy
    await yieldToMain()
  }
}

function yieldToMain() {
  return new Promise(resolve => {
    // scheduler.yield() (nowsze API)
    if ('scheduler' in window && 'yield' in scheduler) {
      scheduler.yield().then(resolve)
    } else {
      // Fallback
      setTimeout(resolve, 0)
    }
  })
}


// ✅ WEB WORKER dla heavy computation
// main.js
const worker = new Worker('worker.js')
worker.postMessage({ items: largeArray })
worker.onmessage = (e) => {
  updateUI(e.data.result)
}

// worker.js
self.onmessage = (e) => {
  const result = e.data.items.map(item => heavyComputation(item))
  self.postMessage({ result })
}


// ✅ REQUEST IDLE CALLBACK dla non-critical
requestIdleCallback((deadline) => {
  while (deadline.timeRemaining() > 0 && tasks.length > 0) {
    performTask(tasks.shift())
  }
})

Monitoring Long Tasks:

// PerformanceObserver dla Long Tasks
const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach(entry => {
    console.log('Long Task:', entry.duration, 'ms')
    // Wyślij do analytics
  })
})

observer.observe({ entryTypes: ['longtask'] })

Narzędzia i Monitoring Pytania

Jak używać Lighthouse i jakie są kluczowe metryki?

Odpowiedź w 30 sekund: Lighthouse to narzędzie Google do audytu wydajności. Mierzy: Performance (FCP, LCP, TBT, CLS, Speed Index), Accessibility, Best Practices, SEO. Uruchom w DevTools, CLI lub CI. Score 90+ to dobry wynik.

Odpowiedź w 2 minuty:

Lighthouse można uruchomić na kilka sposobów - przez DevTools, CLI lub jako część procesu CI/CD. Poniżej przedstawiono przykłady użycia Lighthouse w wierszu poleceń oraz integracji z GitHub Actions:

# Lighthouse CLI
npm install -g lighthouse
lighthouse https://example.com --output html --output-path ./report.html

# W CI (GitHub Actions)
- name: Lighthouse CI
  uses: treosh/lighthouse-ci-action@v10
  with:
    urls: |
      https://example.com
      https://example.com/about
    budgetPath: ./budget.json

Metryki Lighthouse:

Metryka Co mierzy Cel
FCP First Contentful Paint < 1.8s
LCP Largest Contentful Paint < 2.5s
TBT Total Blocking Time (proxy dla INP) < 200ms
CLS Cumulative Layout Shift < 0.1
Speed Index Jak szybko treść jest widoczna < 3.4s

Performance budget:

// budget.json
[
  {
    "path": "/*",
    "resourceSizes": [
      { "resourceType": "script", "budget": 300 },
      { "resourceType": "image", "budget": 500 },
      { "resourceType": "total", "budget": 1000 }
    ],
    "timings": [
      { "metric": "first-contentful-paint", "budget": 1800 },
      { "metric": "largest-contentful-paint", "budget": 2500 }
    ]
  }
]

Lab data vs Field data:

Lab Data (Lighthouse, DevTools)
├── Kontrolowane środowisko
├── Reproducible
├── Dobre do debugowania
└── Nie odzwierciedla rzeczywistych użytkowników

Field Data (CrUX, RUM)
├── Prawdziwi użytkownicy
├── Różne urządzenia i sieci
├── Odzwierciedla rzeczywistość
└── Trudniejsze do debugowania

Jak monitorować wydajność w produkcji (RUM)?

Odpowiedź w 30 sekund: RUM (Real User Monitoring) zbiera metryki od prawdziwych użytkowników. Narzędzia: web-vitals library, Chrome UX Report, Sentry, Datadog. Monitoruj percentyle (p75, p90), nie średnie.

Odpowiedź w 2 minuty:

Real User Monitoring zbiera dane o wydajności od rzeczywistych użytkowników w produkcji. Biblioteka web-vitals od Google umożliwia łatwe zbieranie Core Web Vitals i wysyłanie ich do systemu analitycznego:

// web-vitals library
import { onLCP, onINP, onCLS, onFCP, onTTFB } from 'web-vitals'

function sendToAnalytics(metric) {
  const body = JSON.stringify({
    name: metric.name,
    value: metric.value,
    rating: metric.rating,  // 'good' | 'needs-improvement' | 'poor'
    id: metric.id,
    navigationType: metric.navigationType
  })

  // Użyj sendBeacon dla niezawodności
  if (navigator.sendBeacon) {
    navigator.sendBeacon('/analytics', body)
  } else {
    fetch('/analytics', { body, method: 'POST', keepalive: true })
  }
}

onLCP(sendToAnalytics)
onINP(sendToAnalytics)
onCLS(sendToAnalytics)
onFCP(sendToAnalytics)
onTTFB(sendToAnalytics)

Dashboard metryki:

Monitoruj percentyle, nie średnie!

Percentyle:
├── p50 (mediana) - połowa użytkowników
├── p75 - Core Web Vitals threshold
├── p90 - worst 10%
└── p99 - outliers

Przykład:
LCP p75 = 2.1s ✅ Good
LCP p90 = 3.8s ⚠️ Needs improvement dla 15% użytkowników

Alerting:

// Przykład alertu gdy metryki się pogarszają
if (metric.name === 'LCP' && metric.value > 2500) {
  sendAlert({
    type: 'performance_degradation',
    metric: 'LCP',
    value: metric.value,
    threshold: 2500,
    page: window.location.pathname
  })
}

Powiązane Artykuły

Jeśli przygotowujesz się do rozmowy jako Frontend Developer, sprawdź również:


Powodzenia na rozmowie! Web Performance to obszar, który wyróżnia doświadczonych developerów. Pokaż, że rozumiesz Core Web Vitals, potrafisz używać Lighthouse i DevTools, i wiesz jak optymalizować LCP, INP i CLS.

Chcesz więcej pytań rekrutacyjnych?

To tylko jeden temat z naszego kompletnego przewodnika po rozmowach rekrutacyjnych. Uzyskaj dostęp do 800+ pytań z 13 technologii.

Kup pełny dostęp Zobacz bezpłatny podgląd
Powrót do blogu

Zostaw komentarz

Pamiętaj, że komentarze muszą zostać zatwierdzone przed ich opublikowaniem.