React Vite-проєкти отримають Core Web Vitals лише коли рендер організують інженерно, а не зводять до списку Lighthouse-фіксів. Справжній ефект дає не швидкість білду, а логіка: що користувач бачить першим, і чи працює це до завантаження даних.

Vite прискорює білд, але не момент появи контенту

Менший бандл у Vite не гарантує кращий LCP, якщо головний контент з’явиться лиш після гідрації JS. Швидкість збірки і швидкість першого рендеру — різні речі: Vite доставляє пакет, але враження формує архітектура першого екрану.

Браузер вимірює враження, а не твій процес білду.

Команда маркетингу оновлює сайт на Vite, але герой-зона з CTA та картинкою з’являється тільки після клієнтської гідрації React. CI показує ідеальні показники, а користувач бачить порожню рамку. Причина — ключовий контент запускається тільки клієнтськи, руйнуючи всі обіцянки Lighthouse.

Core Web Vitals ламаються на hydration-gap

CLS та INP часто гіршають після першого paint, бо перехід від HTML до інтерактивного UI залишається нестабільним. Користувач бачить готову сторінку, але вона зсувається чи гальмує у першу ж дію.

  • Компоненти-гідрати можуть зміщувати кнопки, бейджі після підключення.
  • Шрифти завантажуються асинхронно, відсуваючи текст та картинки.
  • Інтерактивні області блочать інпут, доки React не ініціалізується повністю.
// Production observation

В e-commerce grid перехід від skeleton до реального контенту часто зміщує кнопки та ціну, особливо на слабких пристроях.

LCP у React рідко блокується лише картинкою

Найбільше зображення рідко затримує LCP — часто блокує JavaScript.

Порада "відкладати головну картинку" мало допомагає у світі React. Часто браузер чекає додаткових бандлів, бібліотек чи аналітики перед тим, як рендерить зображення. Доки dependency-ланцюг React блокує chunk, оптимізація формату не вирішує проблему.

У типовому SaaS‑dashboard герой-графік та скріншот з’являються лише після завантаження date-picker чи аналітики. Картинка перша за задумом, але остання у візуальному потоці. Поки контент не пріоритезовано над усіма ресурсами, зміна формату не дає виграшу.

INP у React губиться не під час кліків, а через конкуренцію потоків

INP (Interaction to Next Paint) падає, коли важкі операції рендеру змагаються з користувацьким вводом за головний потік. Вся відповідальність — на архітектурі, а не на дрібних оптимізаціях.

  1. Фільтрація та сортування йдуть синхронно із вводом.
  2. Віртуальні списки повністю оновлюються на кожну зміну.
  3. Без useTransition чи мемоізації компонент блокує інпут напряму.

Розбалансовані пріоритети React Scheduler одразу роблять UI "важким", навіть при швидких API. useTransition, мемо або віртуалізація захищають не компонент, а ритм чуйнoго інтерфейсу.

Code splitting допомагає лише якщо стартова сторінка чиста

Code splitting дає виграш у Core Web Vitals, лише якщо реальні фічі винесено за межі першого роута. Динамічний import не дає ефекту, якщо загальні залежності все одно підʼєднуються eagerly.

  • Загальні UI-компоненти все ще потрапляють у головний чанк.
  • Передзавантаження неважливих фіч збільшує навантаження при запуску.
  • Рішення про те, що бачить користувач, — питання бізнесу, а не системи.

У клієнтському порталі головна сторінка тягне аналітику і адміністрування ще до першого кліку. Code splitting як інструмент без звʼязку з продуктом — це архітектурний глухий кут.

Debugging починається не у Lighthouse, а у реальному сценарії користувача

Покращити продуктивність можна лише через аналіз реальних user flows, а не лабораторних оцінок. Розрив між Lighthouse та поведінкою у полі — головна архітектурна сліпота в React Vite проектах.

// Operational note

RUM та Chrome Performance Panel показують блокування потоків та reflow саме в реальному трафіку, не у тестлабі.

Продає не ідеальний score, а чесна діагностика.