Статьи

Рецепты прогрессивных веб-приложений для GWT

Прогрессивный или не прогрессивный …

Если вы какое-то время занимались разработкой или разработкой веб-приложений, вы, вероятно, встречали бы термин «прогрессивное веб-приложение» множество раз и, вероятно, сделаете это в ближайшие годы. Вы, вероятно, задавались вопросом, что именно является определением PWA, как мы его идентифицируем и как мы его создаем. Согласно словарю, термин «прогрессивный» относится к чему-то, что улучшается или улучшается, но как это относится к веб-приложению? Мы действительно не знаем. PWAs кажется модным словом, изобретенным Google для того, чтобы заинтересовать людей, и на самом деле оно не имеет отношения к тому, чем в действительности являются PWA. Алекс Рассел определил PWA как «веб-сайты, которые принимали правильные витамины». Для простоты давайте начнем с того, что PWA — это веб-приложения, оптимизированные для использования в их среде: они могут играть роль собственных мобильных приложений на мобильных устройствах или планшетах и ​​роль обычных веб-приложений на ПК.

Обоснование PWA:

PWA — это альтернатива обычному веб-приложению и пакетному приложению для разных мобильных платформ. Поддержание и обновление всего этого может быть дорогостоящим, особенно если приложение часто меняется. В PWA есть только одно приложение, которое работает для всех платформ, которое доступно по ссылке в браузере. PWA предназначены для разработки с использованием подхода Mobile first. Они могут быть установлены, но они также работают как обычные веб-сайты. Google создал специальный веб-сайт для PWA и представляет различные примеры компаний, которые выиграли от конвертации своих приложений / веб-сайтов в PWA.

Характеристика PWA:

В одном из своих выступлений Роб Додсон , адвокат разработчика в Google, подчеркнул различные характеристики веб-приложения:
— Отзывчивый: адаптируется к устройствам
— Быстрая загрузка: оптимизирована для быстрого рисования или рендеринга
— Работа в автономном режиме: используйте сервисных работников для кэширования контента, чтобы разрешить использование приложения в автономном режиме или при медленном сетевом подключении
— Устанавливается: приложение может быть установлено на домашнем экране (как родное приложение)
— Вовлечение: информирование пользователя с помощью push-уведомлений.

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

Рецепты GWT для PWA:

    • # 1 Отзыв:

Чтобы сделать ваше приложение GWT отзывчивым, есть несколько вариантов для пользователей GWT. Если у вас есть навыки дизайна, вы можете сделать ваше приложение отзывчивым, используя пользовательский код и CSS. В противном случае вы можете положиться на другие рамки. Bootstrap для GWT ( https://github.com/gwtbootstrap3/gwtbootstrap3 ) — это первое, что приходит на ум. Он предоставляет все компоненты знаменитой платформы Twitter. Другой альтернативой является GWTMaterialDesign ( https://github.com/GwtMaterialDesign/gwt-material ). Он предоставляет готовый дизайн материалов, готовых к использованию. Наконец, gwt- Polymer-Element, который является упаковщиком Polymer для GWT, также предоставляет готовые к использованию адаптивные веб-компоненты и может пригодиться при проектировании создания адаптивного приложения. Мы предоставили руководство для начинающих по Polymer в одном из наших предыдущих сообщений.

    • Быстрая загрузка # 2:

Чтобы сократить время до первой краски, есть ряд вещей, которые можно сделать. Прежде всего, разделение кода можно использовать для уменьшения размера файла модуля gwt. Он в основном разбивает модуль на фрагменты, позволяя модулю GWT загружать только необходимые при запуске. Во-вторых, метод оболочки приложения, как указано в рекомендациях PWA, может быть применен к приложению GWT. Это можно сделать, извлекая статические элементы и данные из кода Java приложения и помещая их непосредственно в точку входа .html. Например:

Обычная практика, которую делают пользователи GWT, это иметь пустое тело .html и программно добавлять свои представления из приложения:

1
2
3
  
<body>    
</body>
1
2
3
4
5
//....
 
AppMainView view = AppMainView();
 
RootPanel.get().add(view);

Хотя в этой практике нет ничего плохого, она может замедлить время загрузки приложения, поскольку в файле модуля .js будет больше инструкций, и, следовательно, для его выполнения потребуется больше времени. В качестве исправления мы можем попытаться идентифицировать все статические элементы в наших представлениях и поместить их в .html, а затем мы можем загрузить отдельные представления из нашей точки входа:

1
2
3
<div id="appShell"><img src="logo.png" alt="" />
<div id="menu"></div>
<div id="mainContent"></div>
1
2
3
4
5
6
//...
MenuView menu = new MenuMeview();
ContentView content = new ContentView();
 
RootPanel.get("menu").add(menu);
RootPanel.get("mainContent").add(content);

Это, конечно, упрощенный пример для иллюстрации. Мы уже видели, как разделение кода и оболочка приложения могут сократить время рендеринга приложения. Существует также атрибут асинхронного сценария HTML5, который не является специфическим для GWT. Например:

1
2
<!-- Inside HEAD --!>
<script src="polymerstarter/polymerstarter.nocache.js" async="" type="text/javascript">

Это будет указывать браузеру не блокировать синтаксический анализ и загружать скрипт приложения, как только он станет доступен.

Другой вариант — поместить скрипт приложения в тело.

    • № 3 Работа в автономном режиме:

Это можно сделать в основном с помощью сервисных работников. Официальных библиотек GWT для взаимодействия с работниками сферы обслуживания не существует. Даже gwt-Polymer-Elements не упаковывает Platinum Elements, которые являются Polymer-элементами, предназначенными для взаимодействия с работниками сервиса браузера. Пользователям GWT придется написать несколько Javascript вручную, чтобы реализовать механизм кэширования для ресурсов приложения. JSNI или Jsinterop можно использовать для взаимодействия с браузером и вызова сервисных работников. Сценарий работника сервиса, который определяет события кэширования, должен быть в отдельном скрипте, поэтому на данный момент довольно сложно смешивать как код работника сервиса, так и код модуля приложения GWT в одном файле .js. Единственная задача, которую можно выполнить из GWT, — это регистрация работника сервиса. Мы продемонстрируем это позже в следующем разделе. Также обратите внимание, что сервисные работники доступны не во всех браузерах, более подробную информацию об этом можно найти на странице документации API Mozilla .

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

    • # 4 Intstallable:

Этот рецепт также не специфичен для GWT. Чтобы сделать веб-приложение устанавливаемым, вам нужно добавить файл json с именем app manifest и связать его с точкой входа .html:

1
<link rel="manifest" href="manifest.json">

Инструкции по написанию файла манифеста вы можете найти в рекомендациях W3C: https://www.w3.org/TR/appmanifest/ . Вы также можете использовать этот онлайн-инструмент: http://brucelawson.github.io/manifest/, который генерирует ваш манифест для вас, но ваше заявление должно быть уже онлайн. Вы можете либо использовать баннер, чтобы попросить пользователя установить приложение, либо позволить ему сделать это вручную из настроек браузера.

    • # 5 Вовлечение:

Еще раз нет официальной библиотеки push-уведомлений для GWT. Это может быть призыв к сообществу GWT восполнить этот пробел. До этого пользователи GWT могут использовать JSNI или Jsinterop для взаимодействия с браузером и подписываться на push-уведомления.

Демо приложение

Чтобы проиллюстрировать вышеприведенные характеристики, мы создали приложение карты, используя gwt- Polymer-Elements и Gwty-leaflet . Приложение отображает любимые карты пользователя.

источник: https://github.com/gwidgets/gwt-pwa-demo
в прямом эфире: https://gwt-pwa-demo.herokuapp.com/pwademo.html/

с помощью Polymer наше приложение реагирует по умолчанию, поэтому этот шаг сделан.

Чтобы ускорить загрузку приложения, мы сначала сняли все статические html и поместили в файл точек входа .html: https://github.com/gwidgets/gwt-pwa-demo/blob/master/src/main /webapp/pwademo.html

Мы использовали Polymer elemental для взаимодействия с элементами dom. Например:

1
2
PaperMenuLEement paperMenu = (PaperMenuElement) Polymer.getDocument().getElementById("paperMenu");
  paperMenu.select("paris");

Мы также заставили наш скрипт приложения загружаться асинхронно:

1
<script type="text/javascript" language="javascript" src="pwademo/pwademo.nocache.js" async></script>

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
loadStartupMap();
         
         
        //Maps are not loaded on start up, but only when iron selector selects a new map
ironPages.addEventListener("iron-select", e -> {
              
    if(ironPages.getSelected().equals("london") && !londonMapInitialized){
                 
                //Some code splitting to reduce initial module size
      GWT.runAsync(new RunAsyncCallback(){
        @Override
        public void onFailure(Throwable reason) {
    Document.get().getElementById("londonMap").setInnerHTML("Could not load this map, please try again later");
                    }
        @Override
        public void onSuccess() {
        Maps.initializeLondonMap();
                }});
        londonMapInitialized = true;
            }
});

Мы также добавили манифест приложения, чтобы приложение могло быть установлено вручную

01
02
03
04
05
06
07
08
09
10
11
12
13
{
  "name": "Favorite Maps PWA",
  "short_name": "Favorite Maps PWA",
  "icons": [{
        "src": "image/mapicon.png",
        "sizes": "144x144",
        "type": "image/png"
      }],
  "start_url": "/pwademo.html",
  "display": "standalone",
  "background_color": "#3E4EB8",
  "theme_color": "#2E3AA1"
}

Наконец, мы добавили классы JsInterop для регистрации работника сервиса.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
if (Navigator.serviceWorker != null) {
            Navigator.serviceWorker.register("sw.js")
                    .then(new Function<JavaScriptObject, JavaScriptObject>() {
                        @Override
                        public JavaScriptObject call(JavaScriptObject arg) {
                            GWT.log("registred service worker successfully");
                            return null;
                        }
                    });
        } else {
 
            GWT.log("service worker unavailable in this browser");
 
        }

и мы создали сценарий сервисного работника с именем sw.js и добавили его в ресурсы приложения.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
var cacheName = 'GWT-PWA'
var filesToCache = [ 
                     '/gwt-pwa/pwademo.html'
                     '/gwt-pwa/pwademo.css'
                     '/gwt-pwa/styles/app-theme.html'
                     '/gwt-pwa/styles/shared-styles.html'
                     '/gwt-pwa/leaflet/leaflet.js'
                     '/gwt-pwa/leaflet/leaflet.css',
                     '/gwt-pwa/image/mapicon.png',
                      '/gwt-pwa/pwademo/pwademo.nocache.js'];
 
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); 
    }) 
  ); 
});
 
 
self.addEventListener('activate', function(e) { 
      console.log('[ServiceWorker] Activate'); 
      e.waitUntil( 
        caches.keys().then(function(keyList) { 
          return Promise.all(keyList.map(function(key) { 
            console.log('[ServiceWorker] Removing old cache', key); 
            if (key !== cacheName) { 
              return caches.delete(key); 
            
          })); 
        }) 
      ); 
    });
 
self.addEventListener('fetch', function(e) { 
      console.log('[ServiceWorker] Fetch', e.request.url); 
      e.respondWith( 
        caches.match(e.request).then(function(response) { 
          return response || fetch(e.request); 
        }) 
      ); 
    });

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

После загрузки приложения мы можем найти наши активы в кеш-хранилище в Google Chrome:

http://www.g-widgets.com/wp-content/uploads/2016/08/cacheChrome.png

если мы отключим сеть в Google Chrome и попытаемся запустить приложение, мы получим что-то вроде (Карта не отображается, потому что она не кэшируется):

Приложение обслуживает даже без сети. Если мы посмотрим на сетевые запросы в инструментах разработчика Chrome, то заметим, что ресурсы приложения обслуживаются работником сервиса:

Поскольку это демонстрационное приложение, мы не добавили push-уведомления, так как оно требует настройки push-сервера.

Мы установили приложение на домашний экран с телефона Android и получили что-то вроде:

Вывод

PWA все еще являются чем-то новым в мире веб-разработки. Некоторые предсказывают, что они возьмут на себя нативные приложения в ближайшие годы. Мы знаем, что разработчики GWT используют Phonegap для преобразования своего веб-приложения в мобильное собственное приложение, и, возможно, с PWA им больше не придется это делать. В этом руководстве мы увидели, как GWT можно использовать для создания PWA с использованием таких библиотек, как Polymer. До сих пор нет библиотек GWT для взаимодействия с работниками службы браузера, поэтому сообщество GWT должно заполнить этот пробел.

Интересные ссылки

Руководство для начинающих Адди Османи : https://addyosmani.com/blog/getting-started-with-progressive-web-apps/

Spring IO 2016, поговорим о PWA и Spring Boot: https://www.youtube.com/watch?v=zAZQeQ0CRpQ

Сводная инфографика случаев использования PWA от https://skilled.co/ , интернет-агентства веб-разработки:


Представлено Skilled.co

Ссылка: Рецепты прогрессивных веб-приложений для GWT от нашего партнера по JCG Закарии Амине в блоге G-Widgets .