App Shell — это архитектурный паттерн, ориентированный на ускорение загрузки веб-приложений, особенно прогрессивных (PWA). Идея заключается в том, чтобы отделить статическую структуру интерфейса (шапка, меню, контейнеры для контента) от динамических данных, которые подгружаются отдельно. Статический каркас приложения кэшируется сервис-воркером, что обеспечивает мгновенный отклик при повторных посещениях, даже при медленном соединении или оффлайн-режиме.
Ключевые аспекты паттерна App Shell:
Workbox предоставляет мощные средства для реализации App Shell через сервис-воркеры. Основной подход — кэшировать статические ресурсы приложения и настраивать стратегию их обновления.
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').then(registration => {
console.log('Service Worker зарегистрирован с областью:', registration.scope);
}).catch(err => {
console.log('Ошибка регистрации Service Worker:', err);
});
});
}
Workbox позволяет использовать precacheAndRoute для
предварительного кэширования всех необходимых файлов:
import { precacheAndRoute } from 'workbox-precaching';
precacheAndRoute([
{ url: '/', revision: '1' },
{ url: '/index.html', revision: '1' },
{ url: '/styles/main.css', revision: '1' },
{ url: '/scripts/main.js', revision: '1' },
{ url: '/images/logo.png', revision: '1' }
]);
revision используется для управления версионностью
ресурсов. При изменении файла воркер автоматически обновляет кэш.install event), что позволяет мгновенно
отрисовывать интерфейс при повторных посещениях.App Shell кэширует только каркас приложения. Динамические данные, такие как контент, списки, новости, подгружаются отдельно. Workbox предоставляет стратегии:
Пример стратегии Stale While Revalidate для
API-запросов:
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';
registerRoute(
({ url }) => url.origin === 'https://api.example.com',
new StaleWhileRevalidate({
cacheName: 'api-cache',
plugins: []
})
);
Workbox автоматически удаляет устаревшие версии файлов, когда
меняется revision. Для ручного управления можно
использовать cleanupOutdatedCaches():
import { cleanupOutdatedCaches } from 'workbox-precaching';
cleanupOutdatedCaches();
Для оффлайн-сценариев можно использовать
workbox-background-sync для хранения запросов и их
повторной отправки при восстановлении соединения.
import { Queue } from 'workbox-background-sync';
const queue = new Queue('offline-queue');
self.addEventListener('fetch', (event) => {
if (event.request.method === 'POST') {
event.respondWith(
fetch(event.request).catch(() => queue.pushRequest({ request: event.request }))
);
}
});
App Shell может загружать критические ресурсы сразу, а второстепенные
— по мере необходимости. Workbox поддерживает
workbox-precaching с возможностью
preload и lazy:
precacheAndRoute([
{ url: '/critical.js', revision: '1', preload: true },
{ url: '/optional.js', revision: '1', lazy: true }
]);
Для одностраничных приложений (React, Vue, Angular) App Shell обычно
состоит из HTML, CSS и минимального JS-бандла. Все маршруты SPA
обрабатываются через сервис-воркер, перенаправляющий запросы на основной
index.html:
registerRoute(
({ request }) => request.mode === 'navigate',
async () => caches.match('/index.html', { ignoreSearch: true })
);
revision
для точного контроля обновлений.App Shell в связке с Workbox обеспечивает быструю отрисовку интерфейса, эффективное кэширование и устойчивость приложения к оффлайн-режиму, что критически важно для современных PWA.