Skip to content

mohanramphp/pwa-tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Pre-requesties


  1. Install/Update chrome to 60 or above.
  2. Install chrome web server Chrome Web Server
  3. Install Chrome in mobile phone
  4. Install firesbase tool via npm
npm install -g firebase-tools

Steps for our demo (Weather App)

  1. Go to workspace folder in your laptop/desktop and clone the repository below
C:\workspace> git clone https://github.com/mohanramphp/pwa-tutorial.git
C:\workspace> cd pwa-tutorial
C:\workspace\pwa-tutorial> cd demo
C:\workspace\pwa-tutorial\demo> cd work
C:\workspace\pwa-tutorial\demo\work>code .
  1. Go to chrome apps in chrome and launch 200 ok!
chrome://apps/
  1. Choose your work folder and stop and start the server and click on the url shown below web browser URL(s)

  2. To run the app with initial data

    1. In index.html, uncomment below line
    <!--<script src="scripts/app.js" async></script>-->
    1. uncomment the following line at the bottom of your app.js file
    // app.updateForecastCard(initialWeatherForecast);
    1. comment the line in #2 again its just to check app works with fake data.
  3. Find the below TODO line in app.js and add code below.

// TODO add saveSelectedCities function here
// Save list of cities to localStorage.
  app.saveSelectedCities = function() {
    var selectedCities = JSON.stringify(app.selectedCities);
    localStorage.selectedCities = selectedCities;
  };
  1. Find the below TODO line in app.js and add code below.
// TODO add startup code here
  app.selectedCities = localStorage.selectedCities;
  if (app.selectedCities) {
    app.selectedCities = JSON.parse(app.selectedCities);
    app.selectedCities.forEach(function(city) {
      app.getForecast(city.key, city.label);
    });
  } else {
    app.updateForecastCard(initialWeatherForecast);
    app.selectedCities = [
      {key: initialWeatherForecast.key, label: initialWeatherForecast.label}
    ];
    app.saveSelectedCities();
  }
  1. We have to save the selected city in local storage
document.getElementById('butAddCity').addEventListener('click', function() {
  // Add the newly selected city
  var select = document.getElementById('selectCityToAdd');
  var selected = select.options[select.selectedIndex];
  var key = selected.value;
  var label = selected.textContent;
  if (!app.selectedCities) {
    app.selectedCities = [];
  }
  app.getForecast(key, label);
  app.selectedCities.push({key: key, label: label});
  app.saveSelectedCities();
  app.toggleAddDialog(false);
});

Test it out

  1. When first run, your app should immediately show the user the forecast from initialWeatherForecast.
  2. Add a new city (by clicking the + icon on the upper right) and verify that two cards are shown.
  3. Refresh the browser and verify that the app loads both forecasts and shows the latest information.
  1. Use service workers to pre-cache the App Shell
    1. Find the below TODO line in app.js and add code below.
// TODO add service worker code here
if ('serviceWorker' in navigator) {
    navigator.serviceWorker
             .register('./service-worker.js')
             .then(function() { console.log('Service Worker Registered'); });
}
  1. Add this code to your new service-worker.js file
var cacheName = 'weatherPWA-step-6-1';
var filesToCache = [];

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);
    })
  );
});
  1. Now, reload your page. Open the service worker pane in chrome developer
  2. Add the following script, below the install event in service-worker.js
self.addEventListener('activate', function(e) {
  console.log('[ServiceWorker] Activate');
});
  • The activate event is fired when the service worker starts up
  • Basically, the old service worker continues to control the page as long as there is a tab open to the page
  1. Enable update on reload option in Chrome dev tool
  2. Add the following code to update the cache
self.addEventListener('activate', function(e) {
  console.log('[ServiceWorker] Activate');
  e.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (key !== cacheName) {
          console.log('[ServiceWorker] Removing old cache', key);
          return caches.delete(key);
        }
      }));
    })
  );
  return self.clients.claim();
});

Case in which the app wasn't returning the latest data so to avoid that self.clients.claim() is used

  1. Replace filesToCache variable declaration
var filesToCache = [
  '/',
  '/index.html',
  '/scripts/app.js',
  '/styles/inline.css',
  '/images/clear.png',
  '/images/cloudy-scattered-showers.png',
  '/images/cloudy.png',
  '/images/fog.png',
  '/images/ic_add_white_24px.svg',
  '/images/ic_refresh_white_24px.svg',
  '/images/partly-cloudy.png',
  '/images/rain.png',
  '/images/scattered-showers.png',
  '/images/sleet.png',
  '/images/snow.png',
  '/images/thunderstorm.png',
  '/images/wind.png'
];
  1. Let's now serve the app shell from the cache. Add the following code to the bottom of your service-worker.js file
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);
    })
  );
});

Your app is now offline-capable! Let's try it out. Test it out.

  1. Reload your page and then go to the Cache Storage pane on the Application panel of DevTools.
  2. Right click Cache Storage, pick Refresh Caches, expand the section and you should see the name of your app shell cache listed on the left-hand side.
  3. When you click on your app shell cache you can see all of the resources that it has currently cached.
  4. In Service Worker pane of DevTools and enable the Offline checkbox. After enabling it, you should see a little yellow warning icon next to the Network panel tab. This indicates that you're offline.
  5. Reload your page to see the initial rendering with fake data
  1. Use service workers to cache the forecast data
  2. Add the following line to the top of your service-worker.js file
var dataCacheName = 'weatherData-v1';
  1. Update the code in activate event handler
if (key !== cacheName && key !== dataCacheName) {
  1. Update the fetch event
self.addEventListener('fetch', function(e) {
  console.log('[Service Worker] Fetch', e.request.url);
  var dataUrl = 'https://query.yahooapis.com/v1/public/yql';
  if (e.request.url.indexOf(dataUrl) > -1) {
    e.respondWith(
      caches.open(dataCacheName).then(function(cache) {
        return fetch(e.request).then(function(response){
          cache.put(e.request.url, response.clone());
          return response;
        });
      })
    );
  } else {
    e.respondWith(
      caches.match(e.request).then(function(response) {
        return response || fetch(e.request);
      })
    );
  }
});
  1. Get data from the cache - Find the TODO add cache logic here comment in app.getForecast() in app.js
//TODO add cache logic here
if ('caches' in window) {
  /*
    * Check if the service worker has already cached this city's weather
    * data. If the service worker has the data, then display the cached
    * data while the app fetches the latest data.
    */
  caches.match(url).then(function(response) {
    if (response) {
      response.json().then(function updateFromCache(json) {
        var results = json.query.results;
        results.key = key;
        results.label = label;
        results.created = json.query.created;
        app.updateForecastCard(results);
      });
    }
  });
}
  1. Notice how the cache request and the XHR request both end with a call to update the forecast card. How does the app know whether it's displaying the latest data? This is handled in the following code from app.updateForecastCard
var cardLastUpdatedElem = card.querySelector('.card-last-updated');
var cardLastUpdated = cardLastUpdatedElem.textContent;
if (cardLastUpdated) {
  cardLastUpdated = new Date(cardLastUpdated);
  // Bail if the card has more recent data then the data
  if (dataLastUpdated.getTime() < cardLastUpdated.getTime()) {
    return;
  }
}

The app should be completely offline-functional now. Test it now.

  1. Save a couple of cities and press the refresh button on the app to get fresh weather data
  2. then go offline and reload the page.
  3. go to the Cache Storage pane on the Application panel of DevTools. Expand the section and you should see the name of your app shell and data cache listed on the left-hand side. Opening the data cache should should the data stored for each city.
  1. Web App Install Banners and Add to Homescreen for Chrome on Android
  2. Create a file named manifest.json in your work folder and copy/paste the following contents
{
  "name": "Weather",
  "short_name": "Weather",
  "icons": [{
    "src": "images/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    }, {
      "src": "images/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    }, {
      "src": "images/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    }, {
      "src": "images/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    }, {
      "src": "images/icons/icon-256x256.png",
      "sizes": "256x256",
      "type": "image/png"
    }],
  "start_url": "/index.html",
  "display": "standalone",
  "background_color": "#3E4EB8",
  "theme_color": "#2F3BA2"
}
  1. Tell the browser about your manifest file. Now add the following line to the bottom of the <head> element in your index.html file
<link rel="manifest" href="/manifest.json">
  1. Add to Homescreen elements for Safari on iOS. In your index.html, add the following to the bottom of the <head> element
<!-- Add to home screen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Weather PWA">
<link rel="apple-touch-icon" href="images/icons/icon-152x152.png">
  1. Tile Icon for Windows. In your index.html, add the following to the bottom of the <head> element
<meta name="msapplication-TileImage" content="images/icons/icon-144x144.png">
<meta name="msapplication-TileColor" content="#2F3BA2">

Open up the Manifest pane on the Application panel. you'll be able to see it parsed and displayed in a human-friendly format on this pane.

  1. Deploying our application in firebase
    1. Create a new app at https://firebase.google.com/console/
    2. open cmd prompt from work folder and run
    firebase login 
    1. Initialize your app and provide the directory (likely "./")
    firebase init 
    1. Finally, deploy the app to Firebase
    firebase deploy
    1. done! Your app will be deployed to the domain: https://YOUR-FIREBASE-APP.firebaseapp.com

Find demo application @ Weather App

About

Step by step tutorial to develop Progressive web apps

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published