PageSpeed Front-end (NDA): Як реально прискорити сайт без зламу продуктового потоку
PageSpeed Front-end (NDA): Як реально прискорити сайт без зламу продуктового потоку
Більшість команд приходять до теми продуктивності занадто пізно.
Спочатку все виглядає добре: анімації плавні на робочому ноутбуці, дизайн погоджений, спринт закритий. А потім приходить звіт з реального телефону на слабкому інтернеті, і сторінка, яка здавалася нормальною, відкривається як важкий десктопний додаток.
Цей матеріал не про гонитву за ідеальним скріном Lighthouse. Він про те, як зробити сайт швидким для людей, у яких немає ідеального заліза, стабільного Wi-Fi і зайвого часу.
На одному контентному проєкті з модалками, медіа-блоками та інтерактивом найбільший приріст дав простий зсув мислення: перестати вантажити все "про всяк випадок".
Починати треба з composables, а не з латок
Більша частина проблем з оптимізацією народжується там, де логіка UI вшита прямо в сторінку. Поки код склеєний з п'яти різних зон відповідальності, безпечно відкладати завантаження майже неможливо.
Тому перший крок архітектурний: ізолювати поведінку.
Невеликий useModal добре це показує. Він не знає, яка саме модалка відкривається і які поля в ній є. Його зона відповідальності тільки стан і блокування прокрутки.
~~~ts import { ref } from 'vue'
export function useModal() { const isOpen = ref(false)
const open = () => { isOpen.value = true document.body.classList.add('modal-open') }
const close = () => { isOpen.value = false document.body.classList.remove('modal-open') }
return { isOpen, open, close } } ~~~
Коли така логіка ізольована, її можна підвантажувати рівно в момент реального наміру користувача.
Динамічний імпорт по кліку: попросив користувач, тоді і вантажимо
Якщо відвідувач не відкриє форму зворотного зв'язку, немає сенсу парсити її валідації, маски та допоміжні модулі під час першого рендера.
~~~ts
let modalModulePromise: Promise
export async function openFeedbackModal() { if (!modalModulePromise) { modalModulePromise = import('@/features/feedback-modal') }
const modalModule = await modalModulePromise modalModule.mountFeedbackModal() } ~~~
Такий кеш-патерн прибирає повторні витрати і робить повторні відкриття практично миттєвими.
Динамічний імпорт по скролу: підвантаження тільки біля зони видимості
Красиві інтерактивні блоки часто коштують дорого для браузера. Слайдери, 3D та галереї мають ініціалізуватися тоді, коли користувач наближається до них, а не на старті сторінки.
~~~ts
export function observeAndLoad(
target: Element,
loader: () => Promise
observer.observe(target) } ~~~
Використання у сторінці залишається простим:
~~~ts const galleryRoot = document.querySelector('[data-gallery-root]')
if (galleryRoot) { observeAndLoad(galleryRoot, async () => { const { initGallery } = await import('@/widgets/gallery') initGallery(galleryRoot) }) } ~~~
Правило прозоре: якщо людина не доскролила до блоку, ви не платите за нього байтами та CPU.
Поділ SVG-спрайта: непомітний крок, який дає відчутний ефект
Один великий файл спрайта зручний у розробці, але в продакшені часто стає прихованим боргом. Браузер все одно обробляє великий шматок розмітки, навіть коли на сторінці потрібні дві іконки.
Практична схема:
- base-sprite.svg для глобальних іконок каркаса сайту
- home-sprite.svg, pricing-sprite.svg, blog-sprite.svg для локальних потреб сторінок
Медіа-стратегія, яка поважає трафік користувача
Швидкість сторінки часто вирішується поведінкою зображень і відео, а не вибором фреймворку.
Використовуйте сучасні формати, реальні розміри і lazy loading для контенту нижче першого екрана.
~~~html
~~~
~~~ts
const mediaNodes = document.querySelectorAll
const mediaObserver = new IntersectionObserver((entries, observer) => { for (const entry of entries) { if (!entry.isIntersecting) continue const img = entry.target as HTMLImageElement img.src = img.dataset.src || img.src observer.unobserve(img) } }, { rootMargin: '120px' })
mediaNodes.forEach((node) => mediaObserver.observe(node)) ~~~
Сторінка стає відчутно плавнішою, бо не бореться за мережу з ресурсами, які ще не потрібні.
Кеш і CDN працюють як мультиплікатор, а не як лікування
Cloudflare і кеш-заголовки підсилюють хороший застосунок. Вони не рятують перевантажений.
Якщо стартова вага сторінки завелика, а main thread забитий виконанням JavaScript, CDN лише швидше доставляє важкі файли. Спочатку чистимо архітектуру: розбиваємо код, відкладаємо не критичне, оптимізуємо медіа, прибираємо зайві залежності. Після цього інфраструктурні кроки дають максимум.
Що змінюється в процесі команди
Найбільший довгостроковий буст дає культура: кожен merge request оцінюється не тільки за коректністю, а й за вагою.
Сильна команда завжди запитує:
- Наскільки виріс entry bundle?
- Чи можна відкласти цей модуль до кліку або видимості?
- Чи збільшили ми навантаження на CPU під час першого рендера?
Підсумок
Щоб прискорити продукт, не обов'язково робити повний перепис. Потрібна архітектура, яка дозволяє вибіркове завантаження, і командна дисципліна, яка захищає цю архітектуру щотижня.
Ось це і є справжня система оптимізації: менше героїзму, більше інженерної послідовності.

Коментарі
0Щоб залишати коментарі, увійдіть у свій акаунт.