---
# System prepended metadata

title: <center>Developing Progressive Web Apps</center>

---

# <center>Developing Progressive Web Apps</center>

<center>https://codelabs.developers.google.com/dev-pwa-training/</center>

---
## 01.0 Welcome to the Course

This course shows how to convert web pages to Progressive Web Apps (PWAs). PWA use a web-development approach that combines tools and technologies to create targeted, ideal user experiences on mobile devices. PWAs use service workers, modern browser APIs, and an application shell architecture to give users meaningful offline experiences, fast first load, and easy reengagement on repeat visits to the app.

### Prerequisites

+ Comfortable using HTML and CSS
+ Modest facility with JavaScript

[Source Code](https://github.com/google-developer-training/pwa-training-labs)

### Content


+ 1.0 Welcome (this codelab!)
+ 2.0 Offline quickstart
+ 3.0 Scripting the service worker
+ 3.1 Promises
+ 3.2 Fetch API
+ 4.0 Workbox
+ 4.1 Gulp setup
+ 5.0 Caching files with the service worker
+ 6.0 Cloud Firestore
+ 7.0 Integrating Google Analytics
+ 8.0 Integrating web push
+ 9.0 Responsive design
+ 9.1 Responsive images
+ 10.0 IndexedDB API

---
## 02.0 Offline Quick Start

### What will learn

+ How to audit sites with Lighthouse
+ How to add offline capabilities to an application

### What will need

+ Computer with terminal/shell access
+ Connection to the internet
+ Chrome browser (for using Lighthouse)
+ A text editor
+ Optional: Chrome on an Android device

### Step 1 : Get Set Up
 Navigate into `offline-quickstart-lab/app/ap`.
```
cd offline-quickstart-lab/app
npm install
node server.js
```
Open in browser `localhost:8081`

### Step 2 : Audit with Lighthouse
Open Chrome DevTools <b>audits</b> and then click <b>Run Audits</b>.
![](https://codelabs.developers.google.com/codelabs/pwa-offline-quickstart/img/f563fd774d4d0b5d.png)

And then light house will scores our site.
![](https://codelabs.developers.google.com/codelabs/pwa-offline-quickstart/img/a04fbe987867d477.png)
![](https://codelabs.developers.google.com/codelabs/pwa-offline-quickstart/img/8ce3de94fa0d4691.png)

### Step 3 : Register a Service Worker

Add this script in `index.html`.
```htmlmixed=
<script>
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('service-worker.js')
      .then(reg => {
        console.log('Service worker registered! 😎', reg);
      })
      .catch(err => {
        console.log('😥 Service worker registration failed: ', err);
      });
  });
}
</script>
```
This script will run the service worker.
And then add this script in `service-worker.js`
```javascript=
const cacheName = 'cache-v1';
const precacheResources = [
  '/',
  'index.html',
  'styles/main.css',
  'images/space1.jpg',
  'images/space2.jpg',
  'images/space3.jpg'
];

self.addEventListener('install', event => {
  console.log('Service worker install event!');
  event.waitUntil(
    caches.open(cacheName)
      .then(cache => {
        return cache.addAll(precacheResources);
      })
  );
});

self.addEventListener('activate', event => {
  console.log('Service worker activate event!');
});

self.addEventListener('fetch', event => {
  console.log('Fetch intercepted for:', event.request.url);
  event.respondWith(caches.match(event.request)
    .then(cachedResponse => {
        if (cachedResponse) {
          return cachedResponse;
        }
        return fetch(event.request);
      })
    );
});
```
Now service worker is registered in your site. And chaced resources.

![](https://codelabs.developers.google.com/codelabs/pwa-offline-quickstart/img/35efeeeabb7cd6ee.png)

Reaudit again and you will see improvment.

### Step 3 : Add to Home Screen

Create file `manifest.json`
```json=
{
  "name": "Space Missions",
  "short_name": "Space Missions",
  "lang": "en-US",
  "start_url": "/index.html",
  "display": "standalone",
  "theme_color": "#FF9800",
  "background_color": "#FF9800",
  "icons": [
    {
      "src": "images/touch/icon-128x128.png",
      "sizes": "128x128"
    },
    {
      "src": "images/touch/icon-192x192.png",
      "sizes": "192x192"
    },
    {
      "src": "images/touch/icon-256x256.png",
      "sizes": "256x256"
    },
    {
      "src": "images/touch/icon-384x384.png",
      "sizes": "384x384"
    },
    {
      "src": "images/touch/icon-512x512.png",
      "sizes": "512x512"
    }
  ]
}
```
Add following HTML to the bottom of `<head>`
```htmlmixed=
<link rel="manifest" href="manifest.json">

<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="application-name" content="Space Missions">
<meta name="apple-mobile-web-app-title" content="Space Missions">
<meta name="theme-color" content="#FF9800">
<meta name="msapplication-navbutton-color" content="#FF9800">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="msapplication-starturl" content="/index.html">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<link rel="icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="apple-touch-icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="icon" sizes="192x192" href="icon-192x192.png">
<link rel="apple-touch-icon" sizes="192x192" href="/images/touch/icon-192x192.png">
<link rel="icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="apple-touch-icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="apple-touch-icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="icon" sizes="512x512" href="/images/touch/icon-512x512.png">
<link rel="apple-touch-icon" sizes="512x512" href="/images/touch/icon-512x512.png">
```

To active install prompt after `<main>`
```htmlmixed=
<section id="installBanner" class="banner">
    <button id="installBtn">Install app</button>
</section>
```
Add styles `styles/main.css`
```css=
.banner {
  align-content: center;
  display: none;
  justify-content: center;
  width: 100%;
}
```
Save file and then add this script in `index.html`

```htmlmixed=
 <script>
    let deferredPrompt;
    window.addEventListener('beforeinstallprompt', event => {

      // Prevent Chrome 67 and earlier from automatically showing the prompt
      event.preventDefault();

      // Stash the event so it can be triggered later.
      deferredPrompt = event;

      // Attach the install prompt to a user gesture
      document.querySelector('#installBtn').addEventListener('click', event => {

        // Show the prompt
        deferredPrompt.prompt();

        // Wait for the user to respond to the prompt
        deferredPrompt.userChoice
          .then((choiceResult) => {
            if (choiceResult.outcome === 'accepted') {
              console.log('User accepted the A2HS prompt');
            } else {
              console.log('User dismissed the A2HS prompt');
            }
            deferredPrompt = null;
          });
      });

      // Update UI notify the user they can add to home screen
      document.querySelector('#installBanner').style.display = 'flex';
    });
  </script>
```

Use [remote debugging](https://developers.google.com/web/tools/chrome-devtools/remote-debugging/) to open in android device.
![](https://imgur.com/L2wEsB3.jpg)
![](https://imgur.com/ZRC0uaF.jpg)

---

## 03.0 Scripting the Service Worker

### What will learn

+ Create a basic service worker script, install it, and do simple debugging

### What will need

+ Computer with terminal/shell access
+ Connection to the internet
+ A browser that supports service workers
+ A text editor

### Step 1 : Get Set Up
Navigate into `service-worker-lab/app/ap`.
```
cd service-worker-lab/app
npm install
node server.js
```
Open in browser `localhost:8081`

### Step 2 : Register Service Worker

Inside the `<script>` tags, add the following code to register the service worker:
```javascript=
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('service-worker.js')
    .then(registration => {
      console.log('Service Worker is registered', registration);
    })
    .catch(err => {
      console.error('Registration failed:', err);
    });
  });
}
```

![](https://codelabs.developers.google.com/codelabs/pwa-scripting-the-service-worker/img/e7f833e549e1ee5f.png)

You can see service worker is working.

### Step 3 : Listening for life cycle events

Add in service worker:
```javascript=
self.addEventListener('install', event => {
  console.log('Service worker installing...');
  // Add a call to skipWaiting here
});

self.addEventListener('activate', event => {
  console.log('Service worker activating...');
});
```

If you change the service worker and then save it.

![](https://codelabs.developers.google.com/codelabs/pwa-scripting-the-service-worker/img/e11f7fd7ee1efd5f.png)

### Step 4 : Intercept Network
Add this to `service-worker.js`
```javascript=
self.addEventListener('fetch', event => {
  console.log('Fetching:', event.request.url);
});
```
### Step 5 : Scripting the Service Worker

Update `index.html`
```javascript=
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('service-worker.js')
    .then(registration => {
      console.log('SW registered with scope:', registration.scope);
    })
    .catch(err => {
      console.error('Registration failed:', err);
    });
  });
}
```
And then change service worker to folder below.
![](https://codelabs.developers.google.com/codelabs/pwa-scripting-the-service-worker/img/290daea91df4c1a4.png)

---
## 03.1 Promises

