Максим Сальников
@webmaxru
Погружение в глубокий офлайн –
веб на это способен!
Что значит готовность веб-приложения к офлайн
И как еe достичь прямо сегодня
Максим Сальников
- 
	Организатор Mobile / Web / PWA митапов в Осло и Лондоне
- 
	Организатор конференций Mobile Era и ngVikings в Скандинавии
- 
	Ответственный за поток о веб-разработке 404fest в Самаре
Ответственный за успех Azure-разработчиков в Microsoft



- 
	The World Wide Web is the New Software Platform
- 
	The Web Browser is the New Operating System
- 
	JavaScript is the de facto Programming Language of the Web
Январь, 2008
Веб – отличная платформа для приложений
Браузеры
- 
	Почти на каждом устройстве с UI
- 
	Автообновляемые
- 
	API для доступа к аппаратным ресурсам

JavaScript
Браузеры
- 
	Разносторонний язык
- 
	Мощный инструментарий
- 
	Поступательно развивается в правильном направлении
Веб – отличная платформа для приложений
JavaScript
Движки JS
Браузеры
- 
	Курс на производительность
- 
	Возможности встраивания
Веб – отличная платформа для приложений
JavaScript
Движки JS
Интерфейсы
Браузеры
- 
	Удобные инструменты для создания адаптивных интерфейсов
- 
	Повышенное внимание доступности
- 
	Разнообразие высококачественных библиотек компонентов
Веб – отличная платформа для приложений
Сообщество
JavaScript
Движки JS
Интерфейсы
Браузеры

69.7%
Веб – отличная платформа для приложений
Сообщество
JavaScript
Движки JS
Интерфейсы
Браузеры
Проблемы?

Завязан на состояние подключения к сети
(по историческим причинам)
Веб – отличная платформа для приложений
Решения
Кэширование
Установка
- 
	HTTP Cache
- 
	AppCache
- 
	Save page as... (complete)
- 
	Chrome Apps
- 
	Electron
- 
	NativeScript, React Native
Еще одно определение PWA
PWA используют современные веб-API вкупе со стратегией прогрессивного улучшения для создания кросс-платформенных приложений.
Такие приложения запускаются везде и обладают рядом характеристик, обеспечивающих пользователей преимуществами, аналогичными тем, что доступны в нативных решениях.

работают везде*
* но не все возможности доступны везде**
нативно
** применяем стратегию прогрессивного улучшения
=
+
Application shell
Web App Manifest
Быстрые, адаптивные, mobile-first
Работают по HTTPS

Цель офлайнизации №1
Оболочка приложения
(Application Shell)
Спроектируем App shell
My App
- 
	Определим минимальный, но достаточный набор ресурсов, помним о версионности
- 
	При первой загрузке явно поместим эти ресурсы в Cache Storage
- 
	При последующих запусках будем пробовать выдавать эти ресурсы из кэша (иначе – сеть)
- 
	В то же время проверяем, не обновилась ли версия. Если да – обновляем кэш.
Сервис-воркеры
Логически
Физически
-файл(ы)
Вебсайт
Сервис-воркер
Браузер/ОС
Event-driven worker
Кэш
fetch
push
sync
Предварительное кэширование
self.addEventListener('install', event => {
  
    // Помещаем ресурсы app shell в Cache Storage
})self.addEventListener('activate', event => {
  
    // Удаляем из Cache Storage устаревшие версии
})handmade-service-worker.js
В реальности...
- 
	Необходимо следить за актуальностью списка ресурсов
- 
	Для некоторых видов ответов (opaque, redirected) потребуется специальная обработка
- 
	Пересоздание полной версии приложения в кэше при изменении любого из ресурсов неоптимально
- 
	Размеры кэша ограничены — нужен контроль
- 
	Придется подумать о механизмах инвалидации кэша
- 
	...
Перехватываем запросы
self.addEventListener('fetch', event => {
  if (event.request.url.indexOf('/api') != -1) {
    event.respondWith(
      // Реализуем стратегию Network-First (для API?)
    )
  } else {
    event.respondWith(
      // Реализуем стратегию Cache-First (для app shell?)
    )
  }
})handmade-service-worker.js
В реальности...
- 
	Реализация стратегий — не самая простая задача
- 
	Могут потребоваться и более сложные варианты, например, Stale-While-Revalidate
- 
	Даже в рамках одной стратегии для разных групп ресурсов могут потребоваться разные настройки
- 
	В итоге придется сделать собственную реализацию роутинга
- 
	Необходимо предусмотреть все варианты фолбеков
- 
	...
- 
	Оболочка приложения
- 
	Кеширование данных (runtime)
- 
	Повторение совершенных офлайн запросов
- 
	Двусторонняя коммуникация с приложением
- 
	Офлайн-аналитика (GA)
Все это в собственном сервис-воркере
Режимы работы
- 
	Workbox CLI
- 
	Плагин Webpack
- 
	Модуль для NodeJS
# Устанавливаем модуль Workbox для NodeJS
$ npm install workbox-build --save-devБилд-скрипт
// Используем режим injectManifest
const {injectManifest} = require('workbox-build')
// Конфигурируем (детали на следующем слайде)
var workboxConfig = {...}
// Вызываем метод и выводим результаты
injectManifest(workboxConfig).then(({count, size}) => {
    console.log(`Создан ${workboxConfig.swDest}, который
    закеширует ${count} файлов, ${size} байт.`)
})workbox-build-inject.js
Конфигурация
var workboxConfig = {
  globDirectory: 'dist/',
  globPatterns: [
    '**/*.{txt,png,ico,html,js,json,css}'
  ],
  swSrc: 'src/workbox-service-worker.js',
  swDest: 'dist/sw.js'
}
workbox-build-inject.js
Собственно, сам сервис-воркер
// Импортируем библиотеку Workbox с Google CDN
importScripts('https://googleapis.com/.../workbox-sw.js');
// Все остальное делается за нас
workbox.precaching.precacheAndRoute([])
src/workbox-service-worker.js

- 
	Предварительное кеширование и управление версиями
- 
	Перехват нужных запросов и выдача ресурсов из Cache Storage или сети
Что мы "инжектим"
[
  {
    "url": "index.html",
    "revision": "34c45cdf166d266929f6b532a8e3869e"
  },
  {
    "url": "favicon.ico",
    "revision": "b9aa7c338693424aae99599bec875b5f"
  },
  ...
]Совместим с билдом приложения
{
  "scripts": {
    "build-pwa": "npm run build-app &&
                  node workbox-build-inject.js"
  }
}package.json
Цель офлайнизации №2
Данные приложения
Перехват запросов
self.addEventListener('fetch', event => {
  if (event.request.url.indexOf('/api/breakingnews') != -1) {
    event.respondWith(
      // Реализуем стратегию Network-First
    )
  } else if (event.request.url.indexOf('/api/archive') != -1 {
    event.respondWith(
      // Реализуем стратегию Cache-First
    )
  }
})handmade-service-worker.js
Роутинг и стратегии
workbox.routing.registerRoute(
  new RegExp('/api/breakingnews'),
  new workbox.strategies.NetworkFirst()
);src/workbox-service-worker.js
workbox.routing.registerRoute(
  new RegExp('/api/archive'),
  new workbox.strategies.CacheFirst({
    plugins: [...]
  })
);Стратегии
- 	CacheFirst
- 	CacheOnly
- 	NetworkFirst
- 	NetworkOnly
- 	StaleWhileRevalidate
Плагины
- 
	Expiration
- 
	CacheableResponse
- 
	BroadcastUpdate
- 
	BackgroundSync
- 
	...ваши собственные?
Цель офлайнизации №3
Сохраняем и повторяем действия, совершенные офлайн
Фоновая синхронизация
- 
	Откладывает действия до тех пор, пока не будет установлено подключение
- 
	Синхронизация будет выполнена, даже если приложение уже закрыто
navigator.serviceWorker.ready.then( swRegistration => {
  return swRegistration.sync.register('myFirstSync');
});main.js
self.addEventListener('sync', event => {
  if (event.tag == 'myFirstSync') {
    event.waitUntil(
        // То, что было запланировано
    );
  }
});handmade-service-worker.js
const postTweetPlugin =
    new workbox.backgroundSync.Plugin('tweetsQueue', {
        maxRetentionTime: 24 * 60 // Лимит времени
    })src/workbox-service-worker.js
workbox.routing.registerRoute(
  /(http[s]?:\/\/)?([^\/\s]+\/)post-tweet/,
  new workbox.strategies.NetworkOnly({
    plugins: [postTweetPlugin]
  }),
  'POST'
)Цель офлайнизации №4
Управляем скачиванием и закачиванием и их результатами
Фоновая загрузка
- 
	Приостановка / возобновление загрузки при нестабильном подключении
- 
	Доступ к загруженным ресурсам и статусу загрузки из приложения
- 
	Продолжение загрузки после закрытия приложения
- 
	Нативные элементы интерфейса браузера / ОС для управления и получения статуса загрузки
const registration = await navigator.serviceWorker.ready;
await registration.backgroundFetch.fetch(
  'my-series',
  ['s01e01.mpg', 's01e02.mpg'],
  {
    title: 'Загрузка My Series',
    downloadTotal: 1000000000
   }
);main.js
const bgFetches =
  await registration.backgroundFetch.getIds();
console.log(bgFetches);addEventListener('backgroundfetchsuccess', event => {
  event.waitUntil(
    (async function() {
      try {
        // Сохраняем результаты в Cache Storage
        ...
        await event.updateUI({ title: `Загрузка завершена` });
      } catch (err) {
        await event.updateUI({ title: `Ошибка загрузки: ${err}` });
      }
    })()
  );
});src/service-worker.js
Подробнее и с примерами


Итого
- 
	Веб сегодня — полноценная платформа для приложений
- 
	Основы механизмов для работы офлайн доступны в стабильных версиях всех современных браузеров
- 
	Есть замечательные инструменты для автоматизации типовых задач подготовки к офлайн
- 
	Главный приоритет — обеспечение отличного пользовательского опыта

"Progressive Web Apps State of the Union" от Dominick Ng на BlinkOn 10

- 
	2000+ разработчиков
- 
	Представители основных браузеров, библиотек, фреймворков
- 
	Все о PWA на русском языке
Спасибо!
@webmaxru
Максим Сальников
Есть вопрос?
@webmaxru
Максим Сальников


#WSH?


Погружение в глубокий офлайн - веб способен на это!
By Maxim Salnikov
Погружение в глубокий офлайн - веб способен на это!
Прогрессивные веб-приложения уже получили действительно широкую известность и признание всеми вовлеченными сторонами: разработчиками браузеров (наконец, всеми!), разработчиками, пользователями. Идея приложений, не зависящих от подключения к сети, доказала свою жизнеспособность, и мы видим все больше и больше проектов, идущих по этому пути, что делает возможность работы в офлайне не только лучшей практикой, но просто и хорошей манерой в вебе. В моем докладе, основанном на глубоком исследовании возможностей Service Worker API (с использованием Cache Storage, Background Fetch, Background Sync) и собранных UX-находках, мы рассмотрим историю офлайн веба, важность рассмотрения подключения как привилегии, текущие проблемы (и их решения) и правильные инструменты. В течение докдада мы спроектируем приложение, готовое к работе офлайн, применяя лучшие технологии и UX-практики и добавляя возможности одна за одной: оболочка приложения, кеширование ресурсов и данных, синхронизация при подключении к сети. Все ради наших пользователей, которые требуют нового уровня отказоустойчивости и скорости работы наших приложений.
- 5,644
 
   
   
  