Про швидкість власного сайту ми писали двічі. Спершу — чому сторінка думала три секунди: важкий запит меню, який виконувався на кожному показі. Потім — стиснення, яке начебто працювало; у другій половині тієї статті показано, що вага сучасної сторінки сидить у серіалізованих даних для компонентів, а не в розмітці. Цю тезу тут не повторюємо.
Питання цієї статті інше: що саме їде в браузер разом із кожною сторінкою, хоча відвідувач цим ніколи не скористається. 5 вересня 2026 року ми розібрали відповідь власного сайту й знайшли п'ять таких пасажирів. 13 вересня знайшовся шостий. 16 і 17 вересня перевірили, що з цього лишилось, — і побачили, що один пасажир уже потроху повертається.
Що знайшли 5 вересня
У комітах того дня записано: на сторінку припадало 300–380 КБ даних React, і найбільші шматки не мали стосунку до самої сторінки.
Словник цілої мови. Усі переклади інтерфейсу їхали в браузер на кожній сторінці, хоча компоненти, які працюють у браузері, читають 19 розділів словника з 40. Решту — тексти «Про нас», юридичних сторінок, службові підписи — перекладає сервер, і браузеру вони не потрібні.
Друга шапка. Фреймворк кладе в кожну відповідь заготовку сторінки 404, на випадок якщо адреса не знайдеться під час переходу. Наша сторінка 404 малювала повну шапку з меню послуг, тож на кожну сторінку лягало ще 18 КБ, яких ніхто ніколи не бачив.
Текст статті тричі. Зміст статті збирали два компоненти в браузері, і кожен отримував увесь HTML статті, щоб знайти в ньому заголовки. Текст приїжджав один раз для читання і ще двічі заради списку з кількох пунктів.
Мобільне меню на комп'ютері. Вміст мобільного меню — кнопки напрямів, категорії, пошук, 29 іконок — займав 17 КБ розмітки і близько 150 вузлів DOM. Сервер малював його на кожній сторінці й ховав прозорістю, зокрема тим, хто відкрив сайт із комп'ютера, де це меню не показується взагалі.
Обкладинка, про яку браузер дізнавався пізно. Один прогін трасування статті на мобільному в'юпорті (Slow 4G, процесор уповільнений у чотири рази) дав найбільший елемент першого екрана за 1 094 мс. З них 184 мс браузер просто не знав про обкладинку: вона була фоном у стилях і виявлялась лише після того, як стилі завантажились. Ще 574 мс ішло на оригінальний JPEG 1200×630 вагою 44–85 КБ, без жодного перетворення під екран.
Шостий пасажир, 13 вересня. Скрипт нашого чату — 57 КБ плюс налаштування й відкрите з'єднання — вставлявся сам при першій взаємодії зі сторінкою або коли вона просто стояла. На практиці його отримував кожен відвідувач, а не той, хто натиснув на чат.
Чому цього ніхто не помітив
Жодного з цих пасажирів не видно. Словник не показується, заготовка 404 не малюється, поки не знадобиться, мобільне меню прозоре, чат виглядає як кнопка. Сторінка при цьому має правильний вигляд і працює правильно, а зайва робота, яка працює правильно, сама про себе не повідомляє. Той самий візерунок, що й з важким запитом меню в першій статті, лише з іншого боку: там невидиме сиділо на сервері, тут — у відповіді.
Друга причина — спосіб, у який це накопичується. Ніхто не вирішував везти словник цілої мови: його підключили один раз на весь сайт, коли словник був маленький, і далі він ріс разом із сайтом. Заготовку 404 ставить фреймворк, а шапку в неї поклали, бо так виглядає звичайна сторінка сайту. Кожне рішення окремо розумне, а разом виходить багаж.
Що змінили
- У браузер їдуть лише ті 19 розділів словника, які читають його компоненти. Перелік звіряє окремий скрипт: він іде графом імпортів від файлів із
'use client'і падає, якщо розділу бракує. Без такої перевірки пропущений розділ видно тільки на живому сайті — ключем перекладу замість тексту. - Сторінка 404 бере легку шапку без меню.
- Пункти змісту статті збирає сервер, у пропси йде короткий масив заголовків.
- Вміст мобільного меню монтується після першого відкриття. У серверній розмітці статті лишилось 2 вузли замість 156, а посилання для пошукових роботів стоять у панелі меню для ПК, яка в HTML залишилась.
- Обкладинка стала звичайним зображенням із попереднім завантаженням і форматами під ширину екрана.
- Чат вантажиться після кліку по кнопці.
Що бачимо на живому сайті
16 вересня ми зняли три сторінки проду заголовком Accept-Encoding, як у Chrome, і розібрали їх одним скриптом.
| Сторінка | HTML без стиснення | Передано мережею | Частка скриптів із даними React |
|---|---|---|---|
| головна | 935 639 Б | 83 209 Б | 49% |
| стаття блогу | 453 910 Б | 59 273 Б | 65% |
| сторінка послуги | 633 694 Б | 66 207 Б | 61% |
Шапка всередині заготовки 404 займає тепер 137 байтів із порожнім переліком послуг — проти 23 707 байтів справжнього меню на тій самій сторінці. Контейнер мобільного меню в розмітці статті порожній. Скрипт чату в коді сторінки не згадується взагалі: замість нього кнопка на 707 байтів. Сам скрипт 17 вересня важив 56 953 байти, мережею стиснутим 20 214, — але отримує його лише той, хто натиснув.
А от словник повернувся до старого розміру, і тут є окремий урок.
Урок про одиниці виміру
5 вересня в коміті записано «64 КБ». Коли 16-го ми перерахували той самий файл словника, вийшло 63 261 символ — і 96 372 байти. Кирилиця в UTF-8 займає два байти на літеру, тож записана тоді цифра описувала символи, а не те, що справді їде мережею.
У байтах картина така. Повний словник української на 5 вересня — 96 372 Б у 40 розділах. Дев'ятнадцять потрібних розділів після виправлення — 57 976 Б. Ті самі дев'ятнадцять розділів у поточній гілці — 67 924 Б. За одинадцять днів словник виріс, бо на головній з'явились нові блоки: розділ Home побільшав з 12 852 до 20 539 байтів, 39 нових ключів, найбільший із них — блок питань і відповідей на 4 339 байтів.
Цей розділ приїжджає на кожну сторінку, бо його читають компоненти головної. У відповіді сторінки статті ми перевірили всі 53 рядки з нього, довші за 40 символів: жоден не зустрічається більше ніде в тій відповіді. Тобто читач статті отримує 20,5 КБ текстів головної, яких на його екрані немає. Після brotli це 5 553 байти проти 16 510 на всі дев'ятнадцять розділів; числа рахували для кожного шматка окремо, у складі сторінки вони будуть трохи інші.
Як перевірити це в себе
1. Скільки даних везе сторінка. Для сайтів на Next.js з App Router відкрийте сторінку, консоль DevTools і виконайте:
const d = self.__next_f.map(x => x[1] || '').join('');
new TextEncoder().encode(d).length
Це байти. d.length дасть символи, і на кириличному сайті ви недорахуєте приблизно третину — рівно так, як ми 5 вересня. На Next.js із Pages Router (без App Router) шукайте блок <script id="__NEXT_DATA__"> замість self.__next_f. В інших фреймворках шукайте в коді сторінки великі блоки <script type="application/json">, які фреймворк вставляє для гідратації.
2. Чи не їде чужий текст. Скопіюйте речення, яке є лише на головній, і пошукайте його в коді сторінки статті чи товару (Ctrl+U, далі Ctrl+F). Якщо воно там є, а на екрані немає, це пасажир. Так само шукайте тексти попапів, повні списки міст, довідники, переклади інших мов.
3. Чи не малюється приховане. В інспекторі знайдіть мобільне меню, модальні вікна, кошик — на комп'ютерній версії сайту. Сотні вузлів ще до першого відкриття означають, що ці вузли будуються на сервері й передаються кожному.
4. Що вантажиться до кліку. Вкладка Network, перезавантажте сторінку, трохи погортайте і нічого не натискайте. Скрипти чатів, відеоплеєрів і карт, які з'явились у списку, отримує кожен відвідувач.
5. Чим є найбільший елемент першого екрана. У вкладці Performance знайдіть LCP. Якщо це картинка, задана через background-image у стилях, браузер дізнається про неї пізно — саме на цьому ми втратили 184 мс.
Що це не виправило
Словник росте разом із сайтом, і одноразове обрізання не тримається само. Щоб тексти головної не їхали на статті, словник довелося б ділити за типами сторінок, а у нашій версії бібліотеки перекладів вкладений провайдер не зливає розділи з батьківським — кожному типу довелося б везти ще й спільні розділи. Ми цього поки не робили.
Шапка з деревом меню послуг і далі займає 23 707 байтів у даних кожної сторінки. Це меню справжнє, ним користуються, і прибирати його немає підстав.
Час появи обкладинки після зміни ми окремо не заміряли, тому цифри «після» тут не буде. Відомо лише, що тепер браузер дізнається про неї з самого початку документа, з рядка попереднього завантаження. Та й цифри «до» — 1 094 мс і 184 мс — це один запуск трасування 5 вересня, а не медіана кількох прогонів: на штучно вповільнених мережі й процесорі такий замір гуляє від разу до разу.
У чату є свідома ціна: автоматичне відкриття через 25 секунд або на намір піти зі сторінки більше не працює, бо до кліку двигуна чату на сторінці немає.
І межа всього розбору. Ці кілобайти важать на повільному мобільному інтернеті й на слабких телефонах, де їх ще треба розібрати; на швидкому з'єднанні різниця майже непомітна. Заміри зроблені на одному сайті, на трьох типах сторінок, у два конкретні дні — це наш випадок, а не норматив. Якщо займатися цим самим немає часу, ми робимо прискорення сайту і окремо мобільну швидкість із такими самими замірами до і після.




