GH GambleHub

Оптимізація UI-продуктивності

1) Що вважати «швидко»

TTFB (час до першого байта) - швидкий відгук сервера/CDN.
LCP (Largest Contentful Paint) - «головний» контент з'явився швидко.
INP (Interaction to Next Paint) - чуйність при взаємодії.
CLS (Cumulative Layout Shift) - відсутність «тремтіння» інтерфейсу.
TTI (Time to Interactive) - коли все вже відповідає.
Рекомендовані орієнтири: LCP ≤ 2. 5 с, INP ≤ 200 мс, CLS ≤ 0. 1 (для 75-го перцентиля реальних користувачів).

2) Процес: виміряти → знайти вузькі місця → зафіксувати бюджети

1. Виміряти: RUM (реальні користувачі, що перцентили по країнах/мережах/девайсах) + синтетика (Lighthouse/оглядачі).
2. Знайти: профілювальник Performance (тривалі завдання> 50 мс, layout thrashing, зайві рендери).
3. Зафіксувати: бюджети (вага JS/CSS/шрифтів, LCP/INP) і «червоні лінії» в CI.

3) Мережа і завантаження ресурсів

3. 1 HTTP і пріоритети

Увімкнути HTTP/2/3, стиснення Brotli.
'preconnect'до критичних доменів;'dns-prefetch'для другорядних.
«preload» для критичних ресурсів (герой-зображення, основний шрифт).
' fetchpriority =» high/low»'і'priority'підказки де підтримується.

3. 2 Кешування

Статика з хешем файлу: `Cache-Control: public, max-age=31536000, immutable`.
HTML - короткий TTL + stale-while-revalidate через CDN.
ETag/Last-Modified і Service Worker для офлайн/повторних візитів.

4) Код: менше, пізніше, «рівніше»

4. 1 Збірка

Tree-shaking, minify (в т.ч. dead-code-elim).
Code-splitting за маршрутами/віджетами, динамічний імпорт.
Уникати «глобальних» важких пакетів в базовому бандлі (moment → Intl/Day. js).

4. 2 Рендеринг і доставлення HTML

SSR/ISR/стрімінг: віддати каркас і головний контент першими.
Partial/Islands hydration: гідрувати тільки інтерактивні ділянки.
Defer все некритичне: `<script type="module" defer>`.

4. 3 Реакт-специфіка (якщо використовуєте React)

`React. lazy'+'Suspense'для ледачих віджетів.
'startTransition'і'useDeferredValue'для важких фільтрів/пошуку.
RSC (Server Components) - обчислення на сервері, менше JS на клієнті.
Селектори в стейті (zustand/redux): підписувати компонент на фрагменти, а не весь стор.

5) Рендер і стан: де «гальмує»

5. 1 Ізоляція ререндерів

Дробіть великі компоненти, мемоізуйте («memo», «useMemo», «useCallback»).
Ключі списків - стабільні; не створюйте нові функції/об'єкти в пропсах без потреби.
Уникайте «глобального» контексту для часто мінливих даних - використовуйте селектори або подієві шини.

5. 2 Віртуалізація і великі списки

Аркуші/таблиці → віртуалізація (render window).
Пагінація/інфініт-скролл з backpressure (не вантажте по 100k рядків відразу).
Відкладена ініціалізація важких віджетів поза в'юпортом.

5. 3 Layout & paint

content-visibility: auto; для прихованих секцій (браузер не рендерить невидиме).
contain і'contain-intrinsic-size'для передбачуваних розмірів.
Уникайте частих читань-записів layout упереміш (layout thrashing); групуйте вимірювання.
will-change використовуйте дозовано (інакше зайва пам'ять/шари).

6) Зображення та графіка

Формати: AVIF / WebP (fallback на PNG/JPEG).
Responsive-підхід: 'srcset'+'sizes', density-based для ретини.
' loading =» lazy»'для не-геройських зображень; priority/preload - тільки для LCP-кандидата.
Плейсхолдери з фіксованими розмірами → немає стрибків CLS.
Канвас/чарти: offscreen-канвас і Web Worker для розрахунків; батчинг перерисовок.

7) Шрифти і текст

Один-два variable font замість безлічі накреслень.
`font-display: swap '/' optional', preload для основного накреслення.
'size-adjust'для зменшення «стрибка» при підміні шрифту.
Локальні fallback-шрифти зі схожими метриками.

8) CSS та анімації

Критичний CSS інлайн (<14-20 кБ), інше - відкласти.
Видалити невикористовувані стилі (Purge/CSSTree).
Анімації по можливості на transform/opacity; поважати'prefers-reduced-motion'.
Уникати глибоких каскадів і підривних селекторів.

9) Web Workers, потік і важкі завдання

Все CPU-важке - в Worker (парсинг, сортування, агрегації, ML).
Стрімінгові API ('ReadableStream','fetch'з потоками) для довгих відповідей.
Дроблення завдань на чанки через'requestIdleCallback '/мікротаски для збереження чуйності.

10) Стабільність макета (CLS)

Резервуйте місце під LCP-елемент (зображення/віджет).
Не вставляйте банери/стрічки без фіксованих розмірів.
Асиметричні тултипи/тости - не рухати контент; використовувати шари/портали.

11) Приклади сніпетів

Критичний шрифт та зображення LCP

html
<link rel="preload" href="/fonts/Inter. var. woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" as="image" href="/hero. avif" imagesrcset="/hero. avif 1x, /hero@2x. avif 2x" fetchpriority="high">

Лінива і безпечна ініціалізація віджету

js const Widget = React. lazy(() => import('./Widget'));
function Section() {
const inView = useInViewport('#sec');
return <div id="sec">{inView? <React. Suspense fallback={null}><Widget/></React. Suspense>: null}</div>;
}

Стабілізація макета

css
.hero {
content-visibility: auto;
contain: layout paint;
contain-intrinsic-size: 720px 320px ;/LCP reserve/
}

12) Контроль регресій і бюджети

Bundle-budget: загальний JS ≤ N кБ, CSS ≤ M кБ, initial-chunk ≤ K кБ.
Web-Vitals в CI (емульовані) + RUM-алерти (на перцентилях).
Аналіз бандла: source-map-explorer/аналізатор в PR.
Перформанс-бенчмарки компонентів (рендер 10k елементів, час реакції).

13) Анти-патерни

Вантажити «все і відразу»: графіки, редактори, карти в першому екрані.
Величезний глобальний стейт → каскадні ререндери.
Зображення в 2-4 × від потрібного розміру, без'srcset/sizes'.
Довгі синхронні цикли на головному потоці.
`outline: none'і кастомні фокуси без оптимізації - заважають індикаторам рендера.
Анімації по'top/left'( ламають компонування і викликають reflow).

14) Чек-лист екрану

  • LCP ≤ 2. 5 c на трафіку 3G/мобайл, CLS ≤ 0. 1, INP ≤ 200 мс
  • Критичні ресурси: preload/пріоритети; решта - defer/lazy
  • Бандли: code-split, немає зайвих залежностей
  • Віртуалізація списків/таблиць, відкладена ініціалізація важких віджетів
  • Зображення: AVIF/WebP, `srcset/sizes`, `loading="lazy"`
  • Шрифти: variable +'font-display', preload тільки потрібного
  • CSS: критичний інлайн, Purge,'content-visibility'і'contain'там, де доречно
  • Workers/idle для важких обчислень
  • Бюджети та Web-Vitals підключені до дашбордів/алертів

15) План впровадження (3 ітерації)

Ітерація 1 - Швидкі перемоги (1-2 тижні)

Увімкнути Brotli/HTTP-2/3, CDN. Критичний CSS і preload LCP ресурсів.
Винести важкі віджети в динамічні імпорти.
Зображення → AVIF/WebP +'srcset'. Шрифти: `font-display: swap`.

Ітерація 2 - Структурні поліпшення (3-4 тижні)

Code-split за маршрутами, аналіз бандла, видалення «важких» ліб.
Віртуалізація списків, контент-visibility, contain-intrinsic-size.
Впровадити SSR/стрімінг/острови (де релевантно).
RUM з Web-Vitals, бюджети в CI.

Ітерація 3 - Масштаб і стійкість (безперервно)

Workers/offscreen-канвас, батчинг розрахунків, startTransition/deferredValue.
Регулярний перф-аудит, автодайджест регресій, навчання команди.

16) Міні-FAQ

Що прискорить найбільше на мобайлі?
Зменшення початкового JS, SSR/стрімінг та оптимізація LCP-зображення.

Чи потрібно завжди SSR?
Ні, ні. Якщо сторінка динамічно інтерактивна і кешується погано - islands/partial hydration може бути краще.

Чому INP поганий при «легкому» бандлі?
Ймовірно, довгі завдання (сортування, графіки) на головному потоці - винесіть в Worker і дробіть завдання.

Підсумок

Швидкий UI - це сукупність дисциплін: мережеві пріоритети і кеш, менші і пізні бандли, передбачуваний рендер без стрибків, економні зображення і шрифти, а також постійний контроль метрик в реальному світі. Введіть бюджети, автоматизуйте перевірки і вчіть команду думати про швидкість на кожному кроці - так інтерфейс залишиться швидким сьогодні і через рік.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Telegram
@Gamble_GC
Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.