Максим Сальников
@webmaxru
Что мы узнали за 3 года использования PWA?
Full-stack разработчик "приложений из будущего" в ForgeRock
Эти приложения запускаются везде и обладают рядом характеристик, обеспечивающих пользователей преимуществами, аналогичными тем, что доступны в нативных решениях.
Для разработчиков
Service Worker API
Web App Manifest
Приложение
Сервис-воркер
'install'
Загрузка
Установка
Активация
Удален
'activate'
Ожидание
Активен
стремящийся к прогрессу, проникнутый передовыми идеями
постепенно возрастающий, увеличивающийся
if ('serviceWorker' in navigator) {
// Регистрируем сервис-воркер
}
if ('SyncManager' in window) {
// Реализуем функциональность для оффлайн-режима
}
if (!('PushManager' in window)) {
// Прячем интерфейс подписки на push-уведомления
}
if ('actions' in Notification.prototype) {
// Можем использовать кнопки с разными действиями
}
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw-workbox.js')
.then(...);
}
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw-workbox.js')
.then(...);
)};
}
platformBrowserDynamic()
.bootstrapModule(AppModule)
.then(() => {
// Регистрация сервис-воркера
});
self.addEventListener('install', () => {
self.skipWaiting();
});
self.addEventListener('activate', () => {
self.clients.matchAll({type: 'window'}).then(tabs => {
tabs.forEach(tab => {
tab.navigate(tab.url);
});
});
});
Cache-Control: no-cache
navigator.serviceWorker.register(`/sw.js?v=${VERSION}`);
navigator.serviceWorker.register('/sw.js', {
updateViaCache: 'none'
})
const appShellFilesToCache = [
...
'./non-existing.html'
]
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(cacheName).then((cache) => {
return cache.addAll(appShellFilesToCache)
})
)
})
if ('storage' in navigator && 'estimate' in navigator.storage) {
navigator.storage.estimate().then(({usage, quota}) => {
console.log(`Using ${usage} out of ${quota} bytes.`);
});
}
Chrome | <6% своб. пространства |
Firefox | <10% своб. пространства |
Safari | <50MB |
IE10 | <250MB |
Edge | Зависит от размера диска |
const appShellFilesToCache = [
...
'https://workboxjs.org/offline-ga.min.svg'
]
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(cacheName).then((cache) => {
return cache.addAll(appShellFilesToCache)
})
)
})
const noCorsRequest =
new Request('https://workboxjs.org/offline-ga.svg', {
mode: 'no-cors'
});
fetch(noCorsRequest)
.then(response => cache.put(noCorsRequest, response));
npm install -g sonarwhal
sonarwhal --init
sonarwhal https://airhorner.com
npm install -g lighthouse
lighthouse https://airhorner.com
Открыта регистрация на ваш рейс
MyAirline
myairline.com
Ваш рейс
MY 1228
Отправление
21.09 13:45
Нажмите здесь, чтобы зарегистрироваться
myairline.com
self.addEventListener('fetch', function(event) {
if(event.request.url.indexOf("download-file") !== -1) {
event.respondWith(event.request.formData().then( formdata => {
var response = new Response(formdata.get("filebody"));
response.headers.append('Content-Disposition',
'attachment; filename="' + formdata.get("filename") + '"');
return response;
}));
}
});
event.respondWith(async function() {
const response = await fetch(event.request);
const buffer = await response.arrayBuffer();
const WebPDecoder = await fetchWebPDecoder();
const decoder = new WebPDecoder(buffer);
const blob = await decoder.decodeToBMP();
return new Response(blob, { headers: { "content-type": "image/bmp",
"status": 200 } });
}());
navigator.serviceWorker.ready.then((registration) => {
registration.periodicSync.register({
tag: 'get-latest-news', // default: ''
minPeriod: 12 * 60 * 60 * 1000, // default: 0
powerState: 'avoid-draining', // default: 'auto'
networkState: 'avoid-cellular' // default: 'online'
}).then((periodicSyncReg) => {
// Задача успешно зарегистрирована
})
});
self.addEventListener('periodicsync', function(event) {
if (event.registration.tag == 'get-latest-news') {
event.waitUntil(fetchAndCacheLatestNews());
}
else {
// Неизвестная задача, лучше отменить регистрацию
event.registration.unregister();
}
});