Let's start with PWA
Tags: progressivewebapp, serviceworker, javascript
Published: 2019-04-15 09:10:12

---
title: Let's start with PWA
published: true
description: Build easily your first pwa and understand concept
tags: progressivewebapp, serviceworker, javascript
---

One off the most prometting technology that show up these last year are Progressive Web Apps(PWA). No more pain for building an app per mobile store, each with their constraint and specificity (store rules, language, platform limitation, ect), your website **IS** your application, and it work (at this time) in a lots of Androids and latest iOs (https://caniuse.com/#feat=serviceworkers)

But even is this tech is awesome, it is easy to get lost when you want to build your own PWA, due to his youth, there are not so much tuturials or even solutions on stackOverflow.

###What will you learn

- Build a PWA
- Use ServiceWorker
- Use Offline fonctionality

### What you will not learn

- Use of framework like Workbox.js
- Ultimate answer of life, universe and everything else (sorry !)

## Let's start

###Requirements

To make a mobile client install a pwa, (with a native popup on android for exemple), you neede to achieve some requierements : 
- Your site must be on HTTPS
- Have a valid webmanifest
- Register a service worker

### HTTPS

I'm not going to explain how to set your site on https, sevrals tuto already exist on this subject, but if your goal is just to discover and test PWA, this part is not required is you local server use `http://localhost/` on chrome as multiple security check are turn off on this url like https requirement for service worker !

### Webmanifest

One easy thing to do, is to implement a correct webmanifest to tell navigator you have an PWA ! so let's do it

```html
<!-- in your html head -->
<link rel="manifest" href="/manifest.json">
```
```javascript
// in /manifest.json
{
  "short_name": "PWA",
  "name": "My first PWA",
  "icons": [
    {
      "src": "/images/icons-192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "/images/icons-512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": "/?source=pwa",
  "background_color": "#000000",
  "display": "standalone",
  "scope": "/",
  "theme_color": "#FFFFFF"
}
```
There aren't so mch things to say here, except that `name`(or `short_name`), `icons`, `start_url` and `display` are required.

You can find more information on webmanifest for PWA here : https://developers.google.com/web/fundamentals/web-app-manifest/

### Service Worker

This is it, heart of any PWA, a Service Worker(SW) but you can be wondering what is it and what it do ? 

- It's a Javascript worker so it can receive instruction, even when your PWA or navigator is closed.
- Act as a fully configurable network proxy, to handle offline case.

One thing to know about SW is it's heavily rely on `promise`, so if you don't understand it, I advise you to learn a little about it !

#####Register a SW

```html
<script type="text/javascript">
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js', {'scope': '/').then(function(registration) {
    // Registration was successful
    console.log('ServiceWorker registration successful with scope: ', registration.scope);
  }, function(err) {
    // registration failed :(
    console.log('ServiceWorker registration failed: ', err);
  });
}
</script>
```
*Just put it a before `</body>` for exemple*

This is a basic SW registration, we test if navigator support fonctionnality then we just add it to client. Pretty simple no ?

Scope of service worker is important ! If it's at site root, it can listen to any request from anyhere in your site, but if it's in `/assets/` it will only listen to request comming from `/assets/*` pages.

#####Lifecycle

SW have an "Apps" like life cycle, let's see it.

![service worker lifecycle](https://thepracticaldev.s3.amazonaws.com/i/vvzhocwty8gre1vd1sei.png)

One off most important thing to reminder is that Service Worker is active beyond your website tabs, it's directly executed in browser so it's still alive and ready when an user close your site, permitting him to received push notification or content sync at anytime !

##### Let's begin

Now that everything is ready, let's code your first service worker with basic installation

```javascript
//sw.js
const cacheName = 'my-cache';
const filesList = [
  '/assets/style.css',
  '/assets/main.js'
];
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(cacheName)
      // Add your file to cache
      .then( (cache) => {
        return cache.addAll(filesList);
      })
      // Tell SW to end 'waiting' state
      .then(() => self.skipWaiting())
  );
})

self.addEventListener('activate', (event) => {
  event.waitUntil(
    // tell browser to use this service worker and not outdated one
    self.clients.claim()
  );
})
```

To see if your SW have corectly installed, on chrome for exemple, open DevTools and go in Application tab, you should see something like this : 

![DevTools Service Worker]
(https://thepracticaldev.s3.amazonaws.com/i/lkvclvt3uzubkyesr9kf.jpg)

### PWA

Now that your first SW is ready, let's upgrade it to a pwa, and to achieve this goal, we only need to make your Service Worker respond with something, like a generic offline page, when we aren't online.

```javascript
const cacheName = 'my-cache';
const offlinePage = '/offline.html';
const filesList = [
  '/assets/style.css',
  '/assets/main.js',
  offlinePage
];
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(cacheName)
      // Add your file to cache
      .then( (cache) => {
        return cache.addAll(filesList);
      })
      // Tell SW to end 'waiting' state
      .then(() => self.skipWaiting())
  );
})

self.addEventListener('activate', (event) => {
  event.waitUntil(
    // Tell browser to use this service worker and not outdated one
    self.clients.claim()
  );
})

self.addEventListener('fetch', (event) => {
  // If we don't have internet connection and it's a navigation request
  if (!navigator.onLine && event.request.mode === 'navigate') {
    event.respondWith( caches.open(cacheName)
      .then( (cache) => {
        // If we find our offline page in cache, respond with it
        return cache.match(offlinePage)
          .then( (response) => response);
      })
    );
  } else {
    // Return null let browser do his normal behavior
    return;
  }
```

So we just add on more file to get cached at beginning and a `fetch` listener. For those who wonder, this transform your SW into a local proxy, so every request comming from your website will be catch by your Service Worker and processed before doing anything (like let request pass or directly respond with a cached file).

### Enjoy

Your first PWA is now ready to use ! for those who just want a fast try, I make a fully fonctionnal github.

{% github ekanSSS/pwa %}