Урок 48: Разработка PWA
Прогрессивные веб-приложения (PWA) объединяют лучшие свойства веб-сайтов и мобильных приложений. PWA обеспечивают быструю загрузку, офлайн-работу и возможность установки на устройство пользователя. В этом уроке мы рассмотрим основы PWA и создание простого прогрессивного веб-приложения.
Основы Progressive Web Apps
PWA — это веб-приложения, которые можно устанавливать на устройство пользователя и которые могут работать офлайн. Основные характеристики PWA включают:
- Прогрессивность: Работают для любого пользователя, независимо от выбора браузера.
- Отзывчивость: Адаптируются под любой размер экрана.
- Сетонезависимость: Могут работать в условиях плохого или отсутствующего интернета.
- Обновляемость: Всегда актуальны благодаря использованию сервис-воркеров.
- Безопасность: Используют HTTPS для обеспечения безопасности.
- Установка: Могут быть установлены на домашний экран пользователя.
Создание манифеста веб-приложения
Первый шаг в создании PWA — это создание файла манифеста, который описывает приложение и его поведение при установке. Пример манифеста:
{
"name": "Simple PWA",
"short_name": "PWA",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [
{
"src": "icon.png",
"sizes": "192x192",
"type": "image/png"
}
]
}
Регистрация сервис-воркера
Сервис-воркер — это скрипт, который браузер выполняет в фоновом режиме, отдельно от веб-страницы. Он позволяет управлять кэшированием и обработкой сетевых запросов. Пример регистрации сервис-воркера:
<!-- Регистрация сервис-воркера в index.html -->
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
</script>
// Service Worker registered with scope: /
Создание сервис-воркера
Сервис-воркер кэширует ресурсы и позволяет приложению работать офлайн. Пример простого сервис-воркера:
// service-worker.js
const CACHE_NAME = 'pwa-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles.css',
'/script.js',
'/icon.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
return response || fetch(event.request);
})
);
});
// Сервис-воркер создан и кэширует ресурсы
Создание простого PWA
Давайте соберем все вместе и создадим простое прогрессивное веб-приложение. Создадим структуру файлов и напишем необходимые скрипты.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="manifest" href="/manifest.json">
<title>Simple PWA</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<h1>Simple PWA</h1>
<script src="/script.js"></script>
</body>
</html>
/* styles.css */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 20px;
}
h1 {
color: #333;
}
// script.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
// JavaScript файл создан
Упражнения
Упражнение 1: Кэширование дополнительных ресурсов
Добавьте кэширование дополнительных ресурсов, таких как изображения и шрифты, в ваш сервис-воркер. Обновите манифест и сервис-воркер для кэширования этих ресурсов.
Решение:
// Обновление манифеста (manifest.json)
{
"name": "Simple PWA",
"short_name": "PWA",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [
{
"src": "icon.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
// Обновление сервис-воркера (service-worker.js)
const CACHE_NAME = 'pwa-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles.css',
'/script.js',
'/icon.png',
'/icon-512.png',
'/fonts/roboto.woff2'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
return response || fetch(event.request);
})
);
});
// Дополнительные ресурсы закэшированы
Объяснение: Мы обновили манифест и сервис-воркер для кэширования дополнительных ресурсов, таких как изображения и шрифты.
Упражнение 2: Обработка обновлений сервис-воркера
Реализуйте обработку обновлений сервис-воркера, чтобы автоматически обновлять кэшированные ресурсы при изменении сервис-воркера.
Решение:
// Обновление сервис-воркера (service-worker.js)
const CACHE_NAME = 'pwa-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles.css',
'/script.js',
'/icon.png',
'/icon-512.png',
'/fonts/roboto.woff2'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('activate', event => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName);
}
})
);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
return response || fetch(event.request);
})
);
});
// Обновления сервис-воркера обработаны
Объяснение: Мы добавили обработку обновлений сервис-воркера, чтобы автоматически обновлять кэшированные ресурсы при изменении сервис-воркера.