> Markdown version of [Progressive Web Application](https://vaadin.com/docs/v10/bakeryflow/pwa). Section index: [llms.txt](https://vaadin.com/docs/v10/bakeryflow/llms.txt)

# 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

## <a id="bakery-as-a-pwa"></a>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.

- It comes with a `manifest.json` file that makes the App discoverable and installable, as well as with 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.

### <a id="discoverable-and-linkable"></a>Discoverable and Linkable

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

In addition, Bakery provides a `manifest.json` file indicating to browsers that the page is an application, it also has the name of the application, colors and icons.

By changing these parameters, you can customize how the icon looks in the home-screen and task manager, as well as the splash-screen and background.

```javascript
{
  "name": "Bakery",
  "short_name": "Bakery",
  "start_url": "login",
  "display": "standalone",
  "theme_color": "#227aef",
  "background_color": "#227aef",
  "icons": [
    {
      "src": "icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    ...
  ]
}
```

In the `CustomBootstrapListener.java` we announce to the web browser where the manifest is by modificating the bootstrap page:

```java
public class CustomBootstrapListener implements BootstrapListener {
  @Override
  public void modifyBootstrapPage(BootstrapPageResponse response) {
    ...
    final Element head = response.getDocument().head();
    // manifest needs to be prepended before scripts or it won't be loaded
    head.prepend("<meta name=\"theme-color\" content=\"#227aef\">");
    head.prepend("<link rel=\"manifest\" href=\"manifest.json\">");
    ...
  }
}
```

### <a id="installable"></a>Installable

The presence of a `manifest.json` 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.json`.

[Image: Adding App to Home Screen]

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.

[Image: Starting the App from Home Screen]

### <a id="app-like-and-responsiveness"></a>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.

[Image: 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.

### <a id="accessibility"></a>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.

### <a id="offline"></a>Offline

#### <a id="starting-the-app-when-offline"></a>Starting the App when Offline

The way to make an application available when offline, is by providing a Service Worker. Bakery `CustomBootstrapListener.java` class, includes the necessary javascript code to register the script `sw.js` as a Service Worker.

```java
public class CustomBootstrapListener implements BootstrapListener {
  @Override
  public void modifyBootstrapPage(BootstrapPageResponse response) {

    // Add service worker
    response.getDocument().body().appendElement("script")
      .text("if ('serviceWorker' in navigator) navigator.serviceWorker.register('sw.js')");

  ...
  }
}
```

The `sw.js` script has all the magic for determining what should be cached, and what should be done in case of a network failure.

The significant part in this file is the variables to define which files need to be cached and used when the application is offline:

```javascript
// Important: update the version each time you change any of the files listed below
var version = 2;
// define your offline-page and assets used by it
var manifest = 'manifest.json';
var offlinePage = 'offline-page.html';
var offlineAssets = [
  'images/offline-login-banner.jpg'
]
```

In addition, the `SecurityConfiguration` class need to be updated with the list of files that should be ignored.

```java
@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

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

#### <a id="interacting-with-the-app-when-offline"></a>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.html` template. The significant blocks here is the html defining the message to show, and the code detecting network changes.

```html
   ...

    <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 next screenshot, you can view how the message is displayed in Bakery when you check or uncheck the offline box in browser devtools.

[Image: Offline Screen]

## <a id="resources"></a>Resources

Here are some further topics you might want to review:

- [Progressive Web Apps](https://developers.google.com/web/progressive-web-apps/)

- [Service Workers](https://developers.google.com/web/fundamentals/primers/service-workers/)

- [Manifest Json](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json)

- [How are PWAs different than normal web apps](https://vaadin.com/progressive-web-applications/learn/how-are-pwa-different-than-normal-web-apps)

- [PWAs in Java](https://vaadin.com/blog/progressive-web-apps-in-java)

- [Progressive Web App Architectures](https://developers.google.com/web/ilt/pwa/introduction-to-progressive-web-app-architectures)
