Web Vitals — это набор метрик, разработанных для оценки качества пользовательского опыта на веб-страницах. В контексте прогрессивных веб-приложений (PWA) и офлайн-навигации их использование имеет специфические особенности, так как приложение может работать как онлайн, так и полностью офлайн, а метрики должны корректно измерять производительность в обоих режимах.
Ключевыми показателями являются Largest Contentful Paint (LCP), First Input Delay (FID) и Cumulative Layout Shift (CLS). Для PWA и офлайн-навигации к ним добавляются Time to Interactive (TTI) и Total Blocking Time (TBT), поскольку они позволяют учитывать время, необходимое для полной интерактивности после загрузки кешированных ресурсов.
Web Vitals предоставляются через официальную библиотеку
web-vitals. В PWA интеграция требует учета особенностей
Service Worker, так как данные о ресурсах могут приходить как из сети,
так и из кеша.
import { getLCP, getFID, getCLS, getTTFB } from 'web-vitals';
// Отслеживание Largest Contentful Paint
getLCP(metric => {
console.log('LCP:', metric.value);
});
// Отслеживание First Input Delay
getFID(metric => {
console.log('FID:', metric.value);
});
// Отслеживание Cumulative Layout Shift
getCLS(metric => {
console.log('CLS:', metric.value);
});
// Отслеживание Time to First Byte
getTTFB(metric => {
console.log('TTFB:', metric.value);
});
Особенность PWA заключается в том, что Service Worker может возвращать ресурсы мгновенно из кеша. Поэтому LCP и TTFB могут показывать лучшие значения, чем при реальном сетевом подключении. Чтобы корректно учитывать опыт пользователей, рекомендуется логировать источник ресурса: кеш или сеть.
Офлайн-навигация в PWA требует специальной логики, так как стандартные Web Vitals ориентированы на загрузку через HTTP(S). Для правильного измерения метрик можно использовать следующие подходы:
fromCache, которое потом
используется для анализа метрик:self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cachedResponse => {
if (cachedResponse) {
cachedResponse.headers.append('X-From-Cache', 'true');
return cachedResponse;
}
return fetch(event.request);
})
);
});
DOMContentLoaded и любых асинхронных операций
рендеринга:document.addEventListener('DOMContentLoaded', () => {
getLCP(metric => {
console.log('Offline LCP:', metric.value);
});
});
requestIdleCallback и
setTimeout для измерения времени блокировки.В PWA важно не только измерять базовые Web Vitals, но и учитывать специфические сценарии:
Пример расширенного использования:
const observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
if (entry.entryType === 'layout-shift' && !entry.hadRecentInput) {
console.log('CLS delta:', entry.value);
}
});
});
observer.observe({ type: 'layout-shift', buffered: true });
Для аналитики можно отправлять метрики в облачные сервисы с
дополнительной информацией о состоянии сети
(navigator.onLine), источнике ресурса и том, была ли
страница загружена офлайн. Это позволяет выявлять потенциальные проблемы
именно в PWA-режиме.