Progressive Web Application

Progressive Web Apps (PWAs) are regular web pages that can look like traditional desktop applications, or like modern native mobile Apps by combining modern browsers features.

The main keys for a web application to be considered a PWA are:

  • Progressive: should not have technological or accessibility restrictions.

  • Responsive: screens need to adapt to any device, and still be fully usable.

  • Network independent: able to start without network, and aware of network failures

  • App like: look like a native application

  • Fresh: updates happen transparently to the user

  • Safe: secure connections

  • Discoverable: user knows the App by visiting a page

  • Re-engageable: background notifications invite users to come back to the application

  • Installable: can be installed in the device home-screen, and opened like other native apps

  • Linkable: users can send links to the application

Bakery as a PWA

Bakery fulfills most of the requirements for a Progressive Web App:

  • Its UI is responsive, accessible, and looks like a native application, it gets updates from server on new versions, and all the stages of the application have a linkable URL.

  • Flow server automatically serves resources needed for PWA, such as manifest file that makes the App discoverable and installable, as well as a service worker that facilitates certain parts of the App to be cached for offline.

  • Bakery can be started when the device is offline, noticing to the user about the issue, and loading the UI when it is online.

  • It prevents the user to interact with the UI when the network is down.

Flow provides an easy way to configure a PWA application. In case of Bakery it is only needed to annotate a main layout MainView class with a @PWA, provide an offline-page.html and few info about the application:

@PWA(name = "Bakery App Starter", shortName = "###Bakery###",
		startPath = "login",
		backgroundColor = "#227aef", themeColor = "#227aef",
		offlinePath = "offline-page.html",
		offlineResources = {"images/offline-login-banner.jpg"})

Note that there should be allowed access to the resources: manifest.webmanifest, sw.js, offline-page.html, as long as to the images and icons. This is done in SecurityConfiguration class:

@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Override
  public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(
        ...
        "/manifest.webmanifest",
        "/sw.js",
        "/offline-page.html",
        ...
    );
  }
}

Discoverable and Linkable

We use Vaadin routing annotations so as each stage of the application has a unique URL that can be linkable.

As we already know manifest file is served and generated by Flow according to the provided @PWA configuration. There we can customize how the icon looks in the home-screen and task manager, as well as the splash-screen and background.

Installable

The presence of a manifest.webmanifest and a Service-Worker, allows that the user will be prompted to install the App when visiting the web site a few times.

Tip
Chrome criteria for displaying the install banner is to register a service worker, to serve the page over HTTPS, and to provide name, short_name, start_url and 192x192 icon in manifest.webmanifest.

Once you have the app-icon installed on your home-screen, click on it. Bakery will open in full-screen like a native app, you can see a splash-screen when it is opening.

In the following image, you can compare the App running in a tablet when it is opened from the home screen - looking as native, or in the browser - looking as a standard web page.

Starting the App from Home Screen

App Like, and Responsiveness

Bakery utilizes a bunch of techniques to look as a native application, and to adjust to the device screen size.

  • A responsive Web components selection:

    • vaadin-grid for displaying data without consuming so much resources.

    • vaadin-dialog is used for displaying forms, this guarantees that we can control whether the form is shown as a modal layer, or in full screen.

    • vaadin-form to configure responsive steps based on the viewport.

    • vaadin-tabs is able to adapt to the available space an show navigation arrows in case.

    • vaadin-board a responsive component used in the dashboard.

  • Vaadin themes for small visual variants in the components.

  • CSS media queryes for fine control, and to set CSS properties based on screen size.

Responsiveness
Note
in Bakery, custom styling of a specific template is done in its file, but component theming and common for the App styles are gathered in the shared-style.css file.

Accessibility

By using vaadin-core-elements it is guaranteed that screens are accessible

  • vaadin-text-field and vaadin-password-field for accessible text inputs.

  • vaadin-dialog deals with trapping the focus in the overlay and much more.

  • vaadin-date-picker and vaadin-combo-box are specialized form-components accessible for everyone.

  • vaadin-tabs allows navigate and announce pages with keyboard or mouse.

  • vaadin-grid makes easy to navigate cells with the keyboard.

Offline

Starting the App when Offline

The way to make an application available when offline, is by providing a Service Worker. The sw.js script is generated by Flow according to @PWA configration and it has all the magic for determining what should be cached, and what should be done in case of a network failure. Example of generated sw.js:

importScripts('/bakery/VAADIN/static/server/workbox/workbox-sw.js');

workbox.setConfig({
  modulePathPrefix: '/bakery/VAADIN/static/server/workbox/'
});
workbox.precaching.precacheAndRoute([
{ url: 'icons/icon-144x144.png', revision: '-1619375005' },
{ url: 'icons/icon-192x192.png', revision: '429260614' },
{ url: 'icons/icon-512x512.png', revision: '-381362175' },
{ url: 'icons/icon-16x16.png', revision: '1640292953' },
{ url: 'offline-page.html', revision: '-2067995194' },
{ url: 'manifest.webmanifest', revision: '-37768073' },
{ url: 'images/offline-login-banner.jpg', revision: '1610653180' }
]);
self.addEventListener('fetch', function(event) {
  var request = event.request;
  if (request.mode === 'navigate') {
    event.respondWith(
      fetch(request)
        .catch(function() {
          return caches.match('offline-page.html');
        })
    );
  }
 });

Interacting with the App when Offline

Due to the nature of Vaadin, the UI is managed from server side, thus the application will be unusable when the server is unavailable.

In Bakery, we provide a mechanism to notice the user about the offline issue when it happens. It shows an advice that covers the screen and prevents user interaction. The notice will disappear as soon as the network becomes available.

This is performed in the main-view.js template. The significant blocks here is the html defining the message to show, and the code detecting network changes.

   ...

    <div class="offline" hidden$="[[online]]">
      ...
    </div>

   ...

  <script>
    class MainView extends Polymer.Element {
      ...
      ready() {
        super.ready();
        this.online = window.navigator.onLine;
        window.addEventListener('online', () => this.online = true);
        window.addEventListener('offline', () => this.online = false);
      }
      ...
    }
  <script>

In the following screenshot, you can view how the message is displayed in Bakery when you check or uncheck the offline box in browser devtools.

Offline Screen