Chrome Dev Summit 2020 is back & going virtual on December 9-10. Learn more

App Shell Модель

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

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

"Оболочка" приложения это минимальный набор HTML, CSS и JavaScript требуемый для включения пользовательского интерфейса,а когда кэшируется оффлайн может обеспечить мгновенную, надежную, хорошую производительность при повторном посещении пользователями. Это означает, что оболочка приложения не загружается из сети при каждом посещении пользователя. Из сети загружается только необходимый контент.

Для одностраничных приложений с их тяжелой JavaScript архитектурой, оболочка приложения это подход по умолчанию. Этот подход базируется на агрессивном кэшировании оболочки (используя service worker) для запуска приложения. Затем динамический контент загружается для каждой страницы с помощью JavaScript. App shell полезен для быстрого отображения начального HTML на экране, если сеть недоступна.

Application Shell architecture

Перефразируя, можно сказать, что оболочка приложения похожа на сборку, которую вы публикуете в app store, когда собираете нативное приложение. Она включает в себя каркас вашего UI и компоненты, необходимые для запуска приложения, но, скорее всего, не содержит данных.

Когда использовать app shell модель

Создание PWA не предполагает старта с нуля. Если вы строите современное single-page приложение, то вы, возможно, уже используете что-то подобное, называете вы его так или нет. Детали могут варьироваться, в зависимости от бибилиотек или фреймворков, которые вы использутете, но сама по себе концепция не зависит от фреймворков.

Application shell архитектура имеет наибольший смысл для приложений и сайтов с относительно неизменяемой навигацией и изменяемым контентом. Ряд современных JavaScript фреймворков и библиотек уже поддерживают отделение логики вашего приложения от его контента, делая его архитектуру более простой в применении. Для определённого класс веб-сайтов, которые имеют только статичный контент, вы также можете следовать этой модели, просто сайт будет на 100% app shell.

Чтобы увидеть как Google создавал app shell архитектуру, взгляните на Создание Прогрессивного Веб-приложения Google I/O 2016. Это реальное приложение начиналось с SPA до PWA, которое кэширует контент, используя service worker, динамически загружает новые страницы, плавно переходит между представлениями, и реиспользует контент, после первой загрузки.

Преимущества

Преимущества app shell архитектуры с service worker:

  • Постоянно быстрая, надежная производительность. Повторные посещения экстремально быстрые. Статические ресурсы и UI (например HTML, JavaScript, изображения и CSS) закэшированы при первом посещении, так что они загружаются мгновенно на последующих. Контент может быть закэширован при первом посещении, но обычно он загружается по мере необходимости

  • Взаимодействие, как с нативным приложением. Приняв модель app shell model, вы сможете создавать интерфейсы с быстрой, как-в-нативном-ниложении навигацией и взаимодействием, в комплекте с поддержкой offline.

  • Экономичное использование данных. Проектируйте для минимального использования данных и будьте благоразумны в том, что вы кэшируете, поскольку перечисление файлов, которые являются несущественными (большие картинки, которые не показываются на каждой странице, например) приводят к тому, что браузеры загружают больше данных, чем это строго необходимо. Даже если данные относительно дешевы в западных странах, то это не так на развивающихся рынках, где подключение является дорогостоящим, а данные дорогие.

Требования

В идеале app shell должно:

  • Быстро загружаться
  • Использовать как можно меньше данных
  • Использовать статические ресурсы из локального кэша
  • Отделять контент от навигации
  • Извлекать и отображать содержимое страницы (HTML, JSON, и т.д.)
  • Опционально, кэшировать динамический контент

App shell хранит ваш UI локально и получает контент динамически через API, но не жертвует связанностью и исследуемостью веба. В следующий раз, когда пользователь откроет ваше приложение, он автоматически увидит последнюю версию. Не нужно скачивать новые версии перед использованием приложений.

Создание вашего app shell

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

Offline Wikipedia app using an
application shell with content caching
Приложение Jake Archibald для оффлайн Wikipedia это хороший пример PWA, которое использует модель app shell. Оно загружается мгновенно, при повторных посещениях, но динамически получает контент, с помощью JS. Этот контент затем кэшируется в оффлайн для будущих посещений.

Пример HTML для app shell

Этот пример отделяет базовую инфраструктуру приложения и UI от данных. Важно сохранять начальную загрузку настолько простой, насколько это возможно, чтобы показать только раскладку страницы, как только приложение откроется. Некоторые из них поступают из индексного файла вашего приложения (втроенные DOM, стили), а остальные загружаются из внешних скриптов и таблиц стилей.

Весь UI и инфраструктура кэшируются локально с помощью service worker так, что при последующих загрузках возвращаются не все, а только новые или изменённые данные.

Ваш index.html в вашей рабочей директории должен выглядеть примерно как код ниже. Это лишь чать действительных данных и не является полностью завершенным индексным файлом. Давайте посмотрим, что он содержит.

  • HTML и CSS для "скелета" вашего пользовательского интерфейса, вместе с навигацией и заглушками для контента.
  • Внешний JavaScript файл (app.js) для управления навигацией и логикой UI, а также код для отображения сообщений, полученных с сервера, и сохраняющий их локально, используя механизм хранения, такой как IndexedDB.
  • Манифест веб-приложения и загрузчик service worker для включения возможностей оффлайн режима.
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>App Shell</title>
  <link rel="manifest" href="/manifest.json">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" type="text/css" href="styles/inline.css">
</head>

<body>
  <header class="header">
    <h1 class="header__title">App Shell</h1>
  </header>
  
  <nav class="nav">
  ...
  </nav>
  
  <main class="main">
  ...
  </main>

  <div class="dialog-container">
  ...
  </div>

  <div class="loader">
    <!-- Show a spinner or placeholders for content -->
  </div>

  <script src="app.js" async></script>
  <script>
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js').then(function(registration) {
      // Registration was successful
      console.log('ServiceWorker registration successful with scope: ', registration.scope);
    }).catch(function(err) {
      // registration failed :(
      console.log('ServiceWorker registration failed: ', err);
    });
  }
  </script>
</body>
</html>

Кэширование оболочки приложения

App shell может быть закэширована вручную написанным service worker или сгенерированным инструментом прекэширования статических ресурсов, например sw-precache.

Ручное кэширование app shell

Ниже пример кода service worker, который кэширует статический ресурс из app shell в Cache API, использую событие install:

var cacheName = 'shell-content';
var filesToCache = [
  '/css/styles.css',
  '/js/scripts.js',
  '/images/logo.svg',

  '/offline.html’,

  '/’,
];

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    })
  );
});

Использование sw-precache для кэширования app shell

Service worker, генерируемый sw-precache будет кэшировать и обслуживать ресурсы, которые вы сконфигурируете как часть процесса сборки. Вы можете кэшировать любые HTML, JavaScript, и CSS файлы, требуемые дял работы вашей app shell. Все будет работать в автономном режиме и быстро загружаться при последующих посещениях без каких-либо дополнительных усилий.

Здесь показан базовый пример использования sw-precache как части процесса gulp сборки:

gulp.task('generate-service-worker', function(callback) {
  var path = require('path');
  var swPrecache = require('sw-precache');
  var rootDir = 'app';

  swPrecache.write(path.join(rootDir, 'service-worker.js'), {
    staticFileGlobs: [rootDir + '/**/*.{js,html,css,png,jpg,gif}'],
    stripPrefix: rootDir
  }, callback);
});

Чтобы узнать больше о кэшировании статических ресурсов, смотрите лабораторную Добавление Service Worker, используя sw-precache.

Выводы

App shell, использующее Service worker это мощный шаблон для оффлайн кэширования, но кроме того он также предлагает значительные выигрыши производительности, в виде мгновенной загрузки при повторных посещениях вашего PWA. Вы можете закэшировать ваше оболочку приложения так, чтобы оно работало в оффлайн и заполнить его контентом, используя JavaScript.

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

Translated by