Перейти к содержимому

🎧pwa — технология (для Прогрессивных веб-приложение)

статья была создана 2022/10/09

pwa + SPA

SPA (Single Page Application, или «одностраничное приложение»)

— это веб-сайт, загружающий только одну HTML-страницу. Приложение динамически обновляет контент с помощью JavaScript (AJAX) без перезагрузки, создавая быстрый, бесшовный пользовательский опыт, похожий на мобильное приложение. Примеры включают Gmail, ВКонтакте, Trello.

Прогрессивное web-приложение — технология в web-разработке, которая визуально и функционально трансформирует сайт в приложение. Статистика говорит о том, что 66 % пользователей не скачивают ни одного приложения в месяц. Большую часть своего времени — примерно 85 % — пользователь проводит в пяти любимых приложениях.

PWA является гибридным решением и позволяет открыть приложение с помощью мобильного браузера. При этом полностью сохраняется функциональность нативного приложения:

  • отправка push-уведомлений (кроме устройств под управлением iOS);
  • работа в режиме офлайн;
  • доступ к аппаратному обеспечению устройства (с ограничениями);
  • установка ярлыка (иконки) на рабочий стол мобильного устройства, визуально не отличающегося от ярлыка нативного приложения, и пр.

URL источник — https://web.dev/learn/pwa/service-workers?hl=ru

Вот различные варианты обновления ресурсов:

  • Полное обновление: в этом случае каждый раз, когда вы вносите в приложение изменение, даже незначительное, ваш код снова загружает все ресурсы в кеш.
  • Частичное обновление: в этом подходе вы создаете метод для определения того, какие активы были обновлены, и обновляете только их, с участием пользователя или без него.
  • Непрерывное обновление: с помощью этого метода ваши ресурсы будут автоматически проверяться и обновляться при каждом использовании PWA индивидуально.

Что мне следует использовать?

Вот общая рекомендация по хранению ресурсов:

Вот почему их разделяют:

1. API Cache Storage (Специалист по файлам)

Это «шкаф» для ресурсов, которые браузер запрашивает через URL.

  • Что храним: Стили (CSS), скрипты (JS), картинки, шрифты.
  • Фишка: Он интегрирован с fetch. Когда браузер просит style.css, сервис-воркер мгновенно вытаскивает его из Cache Storage.
  • Почему не IndexedDB: Чтобы отдать файл из IndexedDB, тебе пришлось бы его сначала достать, превратить обратно в файл и только потом «скормить» браузеру. Это лишние тормоза.

2. IndexedDB (Специалист по базам данных)

Это мощная NoSQL база данных прямо в браузере.

  • Что храним: Сложные структурированные данные. Список товаров, история чата, настройки пользователя, черновики постов.
  • Фишка: Там есть поиск, фильтрация и индексы. Ты можешь быстро найти «все заказы дороже 1000 рублей».
  • Почему не Cache Storage: В кэше нельзя искать по свойствам. Ты можешь только достать файл целиком по его адресу (URL).

3. OPFS — Origin Private File System (Новинка для профи)

Это настоящая файловая система, скрытая от пользователя.

  • Что храним: Очень тяжелые файлы (видео 4K, огромные архивы, проекты для Photoshop).
  • Фишка: Она работает быстрее всех. Она позволяет «стримить» (читать по кусочкам) огромные файлы, не загружая их целиком в оперативную память.
  • Почему не остальные: IndexedDB и Cache захлебнутся, если ты попробуешь ворочать в них файлами по 2 Гб.

Главные отличия (Таблица для наглядности)

ИнструментДля чего лучшеАналог в обычном ПК
Cache StorageРесурсы сайта (чтобы он открылся)Временные файлы браузера
IndexedDBТекст, списки, настройкиБаза данных (Excel/SQL)
OPFSТяжелое видео, звук, работа с файламиЖесткий диск (папка с файлами)


Браузеры могут удалять ресурсы из-за нехватки места или после нескольких недель бездействия, если пользователь использует ваше PWA в браузере. На некоторых платформах, если пользователь установит ваше PWA, выселения не произойдет. Там, где это возможно, код может запросить постоянное хранилище через API, чтобы избежать такого вытеснения.

Ответ: О чем речь «Там, где это возможно, код может запросить постоянное хранилище через API, чтобы избежать такого вытеснения.» ?

Речь идет о битве за свободное место на устройстве. По умолчанию всё, что ты сохраняешь в PWA (Cache, IndexedDB), имеет статус «Best Effort» (на честном слове).

Если у пользователя на телефоне заканчивается память (осталось меньше 10-20%), браузер включает режим «вышибалы» и начинает молча удалять данные сайтов, которыми давно не пользовались.

Чтобы этого избежать, можно попросить у браузера статус Persistent Storage (Постоянное хранилище).

Как это работает?

В коде это выглядит как вежливый запрос к системе:

JavaScript

if (navigator.storage && navigator.storage.persist) {
  navigator.storage.persist().then((persistent) => {
    if (persistent) {
      console.log("Данные в безопасности, браузер их не удалит без спроса.");
    } else {
      console.log("Браузер отказал в постоянном хранении.");
    }
  });
}

На каких условиях браузер дает этот статус?

Браузер не раздает его всем подряд, иначе любая рекламная помойка забила бы память телефона. Решение принимается на основе «репутации» твоего PWA:

  • Установлено ли PWA: Если пользователь добавил иконку на рабочий стол, шансы получить вечное хранилище — почти 100%.
  • Частота использования: Если человек заходит в приложение каждый день.
  • Взаимодействие: Если пользователь разрешил уведомления или часто кликает по элементам.

Что это дает на практике?

  1. Гарантия: Браузер пообещает не удалять твои данные, даже если место на диске будет подходить к концу. Он скорее удалит кэш обычных вкладок, но твое PWA не тронет.
  2. Спокойствие: Ты можешь быть уверен, что если пользователь закачал в твое приложение 500 Мб аудиокниг для офлайна, они не испарятся через неделю.

Важный нюанс:

Даже «постоянное» хранилище не вечно. Если пользователь вручную зайдет в настройки браузера и нажмет «Очистить данные сайта» или просто удалит PWA с экрана, всё сотрется. Этот API защищает только от автоматической очистки системой.

Для этого используется StorageManager API. Одной командой ты можешь узнать, сколько «весит» твой сервис для пользователя и не уперся ли ты в потолок.

Код для проверки:

JavaScript

if (navigator.storage && navigator.storage.estimate) {
  navigator.storage.estimate().then((estimate) => {
    const usedMB = (estimate.usage / (1024 * 1024)).toFixed(2);
    const quotaMB = (estimate.quota / (1024 * 1024)).toFixed(2);
    const percent = ((estimate.usage / estimate.quota) * 100).toFixed(2);

    console.log(`Использовано: ${usedMB} МБ из ${quotaMB} МБ (${percent}%)`);
  });
}

Что важно знать про цифры:

  1. Quota (Квота): Это не весь объем памяти телефона. Браузер выделяет каждому сайту «кусок пирога» от свободного места (обычно это процент от остатка на диске).
  2. Usage (Использование): Сюда суммируется всё сразу: и твои картинки в Cache Storage, и данные в IndexedDB, и файлы в OPFS.
  3. Лимиты: В современных браузерах квоты огромные (могут достигать десятков гигабайт), но на iOS они жестче, чем на Android.

Зачем это в реальном приложении?

Представь, что ты делаешь музыкальный плеер. Прежде чем скачивать альбом, ты можешь проверить:

  • «Слушай, у нас осталось всего 100 МБ квоты, а альбом весит 200 МБ. Может, удалим что-то старое?» — это делает твой сервис профессиональным.

Подходим к финалу?

Мы разобрали:

  • Как работает «мозг» (Service Worker).
  • Как перехватывать запросы (Fetch).
  • Как обновлять и чистить кэш.
  • Где хранить данные и как защитить их от удаления.

Остался последний кирпичик — manifest.json. Это тот самый файл, который делает сайт «приложением»: задает имя, иконку и говорит телефону открывать сайт без адресной строки.


Папка, в которой находится ваш сервис-воркер, определяет область его действия. Сервис-воркер, расположенный по адресу example.com/my-pwa/sw.js , может управлять любой навигацией по пути my-pwa или под ним, например, example.com/my-pwa/demos/ . Сервис-воркеры могут управлять только элементами (страницами, воркерами, совместно именуемыми «клиентами»), находящимися в его области действия. Эта область действия распространяется на вкладки браузера и окна PWA.

В каждой области разрешен только один сервис-воркер. Когда сервис-воркер активен и запущен, обычно доступен только один экземпляр, независимо от количества клиентов (окон PWA или вкладок браузера) в памяти.

Внимание: Расположите область действия сервис-воркера как можно ближе к корню приложения, чтобы он мог перехватывать все запросы, связанные с вашим PWA. Не помещайте его, например, в папку JavaScript и не загружайте из CDN.

В Safari реализовано более сложное управление областями действия, известное как разделы, которое влияет на работу областей действия с кросс-доменными iframe. Подробнее о реализации в WebKit см. в публикации в блоге .

Жизненный цикл

У Service Worker есть жизненный цикл, который определяет, как они устанавливаются, отдельно от установки PWA.

Жизненный цикл сервис-воркера начинается с его регистрации. Затем браузер пытается загрузить и проанализировать файл сервис-воркера. Если анализ успешен, срабатывает событие install сервис-воркера. Событие install срабатывает только один раз.

Установка Service Worker происходит незаметно, без разрешения пользователя, даже если пользователь не устанавливает PWA. API Service Worker доступен даже на платформах, не поддерживающих установку PWA, например, в Safari и Firefox на настольных устройствах.

★ Совет: Регистрация и установка сервис-воркера — это связанные, но отдельные события. Регистрация происходит, когда страница запрашивает сервис-воркер, вызывая метод register() . Установка происходит, когда зарегистрированный сервис-воркер существует, может быть проанализирован как JavaScript и не вызывает ошибок при первом выполнении.

После установки сервис-воркер необходимо активировать, прежде чем он сможет управлять своими клиентами, включая ваш PWA. Когда сервис-воркер готов управлять своими клиентами, срабатывает событие activate . Однако по умолчанию активированный сервис-воркер не может управлять страницей, на которой он зарегистрирован, пока вы не перезагрузите её или не откроете PWA снова.

Вы можете прослушивать события в глобальной области действия Service Worker, используя объект self :

serviceworker.js

// This code executes in its own worker or thread
self.addEventListener("install", event => {
   console.log("Service worker installed");
});
self.addEventListener("activate", event => {
   console.log("Service worker activated");
});

Обновление сервисного работника

Service Workers обновляются, когда браузер обнаруживает, что Service Worker, управляющий клиентом, и новая версия файла Service Worker с сервера отличаются на один байт.

Внимание: при обновлении сервис-воркера сохраните имя файла прежним. Если вы измените имя, даже добавив хэши файлов, браузер никогда не получит новую версию.

После успешной установки новый сервис-воркер ожидает активации до тех пор, пока старый сервис-воркер не перестанет управлять клиентами. Это состояние называется «ожиданием», и именно так браузер обеспечивает работу только одной версии сервис-воркера одновременно.

Обновление страницы или повторное открытие PWA не приведёт к передаче управления новому сервис-воркеру. Пользователь должен закрыть или выйти из всех вкладок и окон, использующих текущий сервис-воркер, а затем вернуться обратно, чтобы передать управление новому сервис-воркеру. Подробнее см. в разделе «Жизненный цикл сервис-воркера» .

Жизненный цикл сервисного работника — https://web.dev/articles/service-worker-lifecycle?hl=ru