PWA (прогрессивные веб-приложения) — это горячая вещь для веб-разработки в 2018 году, поскольку все больше и больше платформ поддерживают базовые API, такие как Service Workers или Push-уведомления.
Если вы начинаете новый существующий проект веб-приложения, вполне вероятно, что вы создаете PWA. Но что с устаревшими приложениями? С теми, для которых не предвидится рефакторинг или бюджет (или время, или…)?
Самая популярная функция — это кеширование и возможность офлайн с помощью Service Workers.
Наиболее важные функции PWA: Кэширование/офлайн (более 80%). 66 % считают, что Добавить на главный экран или запрос на установку приложения являются обязательными в PWA, тогда как 60 % считают, что push-уведомления являются ключевыми для создания PWA.
https://medium.com/progressive-web-apps/ 2018-состояние прогрессивных веб-приложений-f7517d43ba70
Эта статья покажет вам, как реализовать эти две основные функции в реальном веб-приложении.
Трансформация
Поскольку я сейчас разрабатываю новое веб-приложение, в котором у меня есть возможность интегрировать Service Workers, Web Workers и все причудливые PWA-материалы в основную архитектуру приложения, мне было любопытно, могу ли я добавить Service Worker в один из моих существующих проектов. для быстрой победы и быстрого преобразования в PWA с незначительными настройками или даже без них.
Предпосылки
- Знание JavaScript
- представление о том, что такое PWA и особенно Service Workers
- и устаревшее веб-приложение;)
HTTPS
Прежде чем мы сможем начать, позвольте мне добавить еще одно предварительное условие для разработки PWA. Для некоторых веб-разработчиков барьер для входа в квест Service Worker может быть высоким, потому что запросы к серверу должны доставляться через HTTPS. Это означает, что вам нужны SSL-сертификаты и для вашей локальной среды разработки.
Я использую Nginx в Ubuntu с самоподписанными сертификатами (https://ram.k0a1a.net/self-signed_https_cert_after_chrome_58) в качестве платформы для разработки.
Поскольку политики браузера время от времени становятся более строгими, будет сложно поддерживать рабочую настройку.
Если у вас есть рабочие примеры для других платформ, поделитесь ими в комментариях ниже.
Совет. Если это применимо к вашей конфигурации, Service Workers можно обслуживать через HTTP с localhost в качестве имени домена.
Манифест
У меня есть еще один. Если на вашем сайте его еще нет, я рекомендую вам создать файл веб-манифеста. Вместе с Service Workers вы получаете бесплатную функцию Добавить на главный экран.
Хорошей отправной точкой является PWABuilder (https://www.pwabuilder.com/) где вы можете создать файл веб-манифеста, а также код JavaScript для различных сценариев Service Worker. Он также проверяет требования для различных целевых платформ, например требуемые размеры значков.
Действие
А теперь приступим!
Инициализировать
Первым шагом является инициализация Service Worker в основном файле JavaScript.
В качестве альтернативы инициализация может также выполняться в HTML-разметке на целевой странице в разделе ‹script›‹/script›.
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('//' + window.location.hostname + '/servicewoker.js', { scope: '/' }).catch(function (error) { console.log('service worker registration failed: ' + error); }); navigator.serviceWorker.ready.then(function () { return console.log('service worker is ready'); }); }
Ваш файл serviceworker.js должен находиться в корневом каталоге вашего домена, если вы хотите охватить весь сайт (он же область действия).
сервисворкер.js
Я буду использовать стандартную нотацию ECMAScript (также известную как JavaScript). Если вы используете, например, TypeScript, ваша IDE будет рада преобразовать код для вас.
Мы начнем с инициализации строки кэша для управления версиями и возможности удаления старого кэшированного контента.
Затем мы определяем все файлы, которые будут загружены при первой загрузке страницы, чтобы кэшировать их, несмотря на алгоритм кэширования, и чтобы они уже присутствовали при первой перезагрузке или повторном посещении страницы.
Также один файл для оффлайн и один для ошибочные ответы. Вы также можете указать активы, такие как изображения или файлы, которые вам понадобятся позже в рабочем процессе вашего приложения.
var CACHE = '20180531'; var cacheFiles = [ '/', '/js/main.js', '/css/main.css', '/image/logo.png', '/offline.html', '/error.html' ].map(function (path) { return "" + path; });
Жизненный цикл
Жизненный цикл Service Worker включает в себя события «установка», «активация» и «выборка». Мы реализуем прослушиватели событий для этих трех.
Установить
Первые два события не очень интересны. Событие «установить» кэширует данные активы.
self.addEventListener('install', function (event) { event.waitUntil(caches.open("" + CACHE).then(function (cache) { return cache.addAll(cacheFiles); }).then(function () { return self.skipWaiting(); })); });
Активировать
Немного домашнего хозяйства. В событии активировать существующее старое содержимое кеша удаляется. Остерегайтесь квоты (https://medium.com/dev-channel/offline-storage-for-progressive-web-apps-70d52695513c)!
self.addEventListener('activate', function (event) { event.waitUntil(caches.keys().then(function (cacheKeys) { var oldCacheKeys = cacheKeys.filter(function (key) { return (key.indexOf(CACHE) !== 0); }); var deletePromises = oldCacheKeys.map(function (oldKey) { return caches.delete(oldKey); }); return Promise.all(deletePromises); }).then(function () { return self.clients.claim(); })); });
Стратегия кэширования
Поскольку веб-приложение с самого начала не было PWA, я хотел использовать консервативную стратегию кэширования, не нарушающую какие-либо функции, а также обеспечить полную автономную работу, что было моей главной целью.
Я также не хотел слишком простых, таких как «сеть или кеш» или «кэш и обновление», поскольку они не будут работать в моем случае или приведут к изменению пользовательского опыта.
Я стремился всегда обслуживать статический контент из кеша, определенные запросы всегда из сети с резервным кешем, а другие из кеша или сети (если они еще не кэшированы).
Принести
Магия начинается здесь. Слушатель событий «fetch» направляет каждый сетевой запрос Service Worker.
Часть I
Сначала определяются запросы (или их части), которые всегда следует пытаться получить из сети (например, запрос к URL-адресу https://example.com/live/request/get/new/emails
).
Поскольку, как уже упоминалось, каждый сетевой запрос будет обрабатываться этим прослушивателем событий, также все внешние запросы к CDN или рекламным сетям потенциально будут кэшироваться. Чтобы предотвратить это, я указал только домены в массиве, который обслуживает приложение.
self.addEventListener('fetch', function(event) { var exclude = false; var excludes = ['/live/request', '/important/request']; var domain = false; var domains = ['https://example.com', 'https://example.org']; excludes.forEach(function (item) { if (event.request.url.indexOf(item) > -1) { exclude = true; } }); domains.forEach(function (item) { if (event.request.url.indexOf(item) === 0) { domain = true; } });
Часть II
Если правило исключения не применяется и запись в кэше существует, будет возвращен кешированный ответ.
В случае запроса по сети ответ будет возвращен и кэшируется только в том случае, если домен совпадает с определенным, статус ответа HTTP соответствует «200» (ОК) и метод запроса относится к типу «GET».
Если возникает ошибка, будет возвращена страница ошибки (или необработанный ответ от других доменов, например, отсутствующий ресурс изображения из рекламной сети).
event.respondWith( caches.match(event.request).then(function(cache) { if (!exclude && cache) { return cache; } return fetch(event.request).then(function(response) { if (domain && response.status >= 400) { return caches.match('/error.html'); } return caches.open("" + CACHE).then(function (cache) { if (domain && response.status === 200 && event.request.method === 'GET') { cache.put(event.request, response.clone()); } return response; }); });
Часть III
В последней части прослушивателя 'fetch' будет перехвачена возникшая ошибка (скорее всего, если устройство находится в автономном режиме).
Пользователю может быть представлен оффлайн сообщение. Вместо этого может быть возвращен ответ JSON, если он лучше соответствует потребностям веб-приложения.
}).catch(function(error) { return caches.match(event.request).then(function (value) { if (domain && value === undefined) { return caches.match('/offline.html'); } return value; }); }) ); });
(serviceworker.js из этого примера: https://gist.github.com/timog/e287d417da995932da7271f6a3fa24f1)
Вот и все! На сцену выходит (простой) новый PWA.
Возможность работы в автономном режиме
После начальной загрузки страницы большинство ресурсов теперь обслуживаются Service Worker без сетевого запроса. Это обеспечивает автономные возможности веб-приложения и обеспечивает гораздо лучший пользовательский интерфейс, чем «офлайн-страница ошибок».
Подводные камни
На момент написания отладка могла быть грубой по краям. Мне пришлось несколько раз очистить кеш и перезапустить браузер (Chrome), потому что DevTools не делал того, что я хотел.
Признаюсь, кое-что мне пришлось изменить. Но это было не совсем изменение кода. Статические ресурсы, такие как файлы .js и .css, обслуживались из дополнительного поддомена (например, https://static.example.org/css/main.css
). Поэтому было невозможно предварительно кэшировать эти активы.
Но поскольку мне нравится менять архитектуру своего приложения после некоторых колебаний, я избавился от поддомена.
Совместимость
В настоящее время все основные браузеры поддерживают Service Workers.
https://caniuse.com/#feat=serviceworkers
Также настольные операционные системы, такие как Chrome OS, macOS и Windows 10, будут поддерживать PWA.
Если используется неподдерживаемая платформа, устаревшее веб-приложение будет работать точно так же, как и раньше.
TODO
Есть много других функций, которые могут быть реализованы с этого момента, например, улучшенная работа в автономном режиме (кеширование отправленных запросов и их отправка при повторном подключении к сети), push-уведомления и т. д. Вам нужно решить, стоит ли погружаться глубже в океан PWA для ваш проект.
И, очевидно, улучшить качество кода.
Заключительные слова
Я надеюсь, что смогу направить того или другого на правильный путь, чтобы превратить устаревшее веб-приложение в PWA.
Спасибо за чтение и не забудьте проверить связанные ресурсы в этой статье, а также ниже.
рекомендуется дальнейшее чтение
Использование сервис-воркеров
https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers
Кэширование файлов с помощью Service Worker
https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker
Поваренная книга сервис-воркера
https://serviceworke.rs/
/* продолжайте любопытствовать */