Skip to content

Instantly share code, notes, and snippets.

@Omranic
Last active August 1, 2023 23:04
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Omranic/4e648fa38caab7b8207d3e237fde0c77 to your computer and use it in GitHub Desktop.
Save Omranic/4e648fa38caab7b8207d3e237fde0c77 to your computer and use it in GitHub Desktop.
2. Use service workers to pre-cache the App Shell - Your First Progressive Web App

Your First Progressive Web App

Based on Abdelrahman Omran PWA presentation, and Google PWA Codelab


Step 1. Fast first load

Step 2. Use service workers to pre-cache the App Shell

Step 3. Use service workers to cache the forecast data

Step 4. Support native integration & Deploy online


Before starting, let's get familiar first with the Application tab in the DevTools.

Create Service Worker

Inside your work directory, beside the index.html file, create a new file named service-worker.js.

Register Service Worker

Open scripts/app.js and search for the following line:

  // TODO add service worker code here

Add the following code below the previous comment:

  // Check if browser supports service workers
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker
             .register('./service-worker.js')
             .then(function() { console.log('Service Worker Registered'); });
  }

Cache Assets

Open the newly created service worker file service-worker.js and add the following lines inside:

// Initialize required variables
var shellCacheName = 'pwa-weather-shell-v1';
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'
];

// Listen to installation event
self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(shellCacheName).then(function(cache) {
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    })
  );
});

Notes: Try now to access your app in Chrome, explore the DevTools

  • Service worker status: installing, activated and running, waiting to activate
  • You can manually unregister SW, or check Update on reload option, or Clear storate, or click skipWaiting beside SW waiting status
  • When SW get updated on server, and you've Update on reload option checked you may get a console error like the following, but it's safe to just ignore it:

(unknown): ServiceWorker was updated because "Force update on page load" was checked in DevTools Source tab.



### Update Assets Cache

In the same file `service-worker.js` add the following lines below the existing code:
```javascript
// Listen to activation event
self.addEventListener('activate', function(e) {
  console.log('[ServiceWorker] Activate');
  e.waitUntil(
    // Get all cache containers
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        // Check and remove invalid cache containers
        if (key !== shellCacheName) {
          console.log('[ServiceWorker] Removing old cache', key);
          return caches.delete(key);
        }
      }));
    })
  );
  
  // Enforce immediate scope control
  return self.clients.claim();
});

Note: at this point we've saved our app shell into the cache, but our app still doesn't support offline browsing since we still need to get cached resources on fetch requests.

Serve App Shell Offline From Cache

In the same file service-worker.js add the following lines below the existing code:

// Listen to fetching event
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);
    })
  );
});

Notes:

  • Your app now has offline support, try it out
  • Use a library like sw-precache to handle SW edge cases
  • Cache key must be updated with every change to redownload
  • When cache is being updated, it will be done in its entirety which isn't effecient
  • This codelab uses a cache-first strategy, beware of cache-first strategies in production
  • To start fresh, try clearing cached data through DevTools -> Application tab -> Clear storage -> Clear site data
  • Make sure that any HTTPS requests made in the installation step goes directly to the network and doesn't return a response from the browser's cache. Otherwise the browser may return the old, cached version, resulting in the service worker cache never actually updating!
@SebastianPokora
Copy link

// app.updateForecastCard(initialWeatherForecast);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment