Skip to content

Instantly share code, notes, and snippets.

@MarcoHengstenberg
Last active September 15, 2016 15:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MarcoHengstenberg/ccf45f618e1e89ac498a82c3af818d42 to your computer and use it in GitHub Desktop.
Save MarcoHengstenberg/ccf45f618e1e89ac498a82c3af818d42 to your computer and use it in GitHub Desktop.
How url/undefined landed in my cache storage

So I didn't want a certain script to be cached by the serviceworker I'm working on. That's how it wasn't in the array of assets and urls to cache.

When I tested the worker I got all assets and pages I had in the array, as expected. But I also found https://url/undefined | OK on the list in the cache storage (in Chrome and Firefox).

When I navigated to the URL (https://url/undefined) I got the contents of the script not being on the list in the first place.

Does it make sense?

Here the contents of the script when the error occured (note that there is a scriptfile not being listed which is part of the smashingconf install though, when I added that to the urlsToCache array the undefined cache item was gone):

/**
 *  smashingconf.serviceworker.js
 *
 *  Author  | Marco Hengstenberg
 *  Version | 1.5.0 (Dev)
 *
 *  Purpose | The Service Worker makes smashingconf.com available offline. I've been following the tutorial at http://www.html5rocks.com/en/tutorials/service-worker/introduction/ by Matt Gaunt
 *  License | There is no license, no copyright, no warranty, no guarantee and no support for the code provided. Handle with care though!
 *
 *  To Do   | Make updates on contents automatically available with skipWaiting
 **/

'use strict';

/*!
 * This is a simple test to ensure that all of the ES2015 features used here are
 * present in the browser before executing. If it fails, the worker will not be
 * installed. As of March 2016, all browsers that support service worker APIs
 * also support these features.
 */
try {
  [
    'var {$$test} = {$$test: null}',
    '[$$test] = [null]',
    '$$test = Object.assign({}, {})',
    '$$test = (...args) => args',
    '$$test = new Map()',
    '$$test = new Set()',
    'delete $$test'
  ].forEach(eval);
} catch (err) {
  console.warn(err);
  throw 'Service worker unmet feature dependencies';
}

/*!
 * Prefix for all cache keys.
 *
 * It should be updated to a new unique value (e.g. timestamp) to force the
 * service worker to update its registrations (causing reinstallation). Changing
 * this value will result in all caches being deleted.
 */
const CACHE_NAME = 'devcache-1.5.0';

/*!
 * This is the list of files to precache. These URLs will be fetched and added
 * to the cache during the `install` event handling.
 *
 * If any of these files are missing, the caching for the entire set will fail,
 * but the installation will continue (with the cache being empty initially).
 */
const urlsToCache = [
  '/',
  '/about',
  '/app-icon-192x192.png',
  '/app-icon-256x256.png',
  '/app-icon-384x384.png',
  '/app-icon-512x512.png',
  '/assets/images/anniversary.png',
  '/assets/images/background.png',
  '/assets/images/buschi.png',
  '/assets/images/confetti-vitaly.png',
  '/assets/images/german-flag.png',
  '/assets/images/hausi-mit-katzi-und-apfeli.png',
  '/assets/images/katzi-kuchi-buschi.png',
  '/assets/images/logo.svg',
  '/assets/images/mystery-smashingconf.png',
  '/assets/images/offline.png',
  '/assets/images/scenery.png',
  '/assets/images/social/email.png',
  '/assets/images/social/lanyrd.png',
  '/assets/images/social/twitter.png',
  '/assets/images/soldout.png',
  '/assets/images/spanish-flag.png',
  '/assets/images/speakers/aagu.png',
  '/assets/images/speakers/aagu-hov.png',
  '/assets/images/speakers/adho.png',
  '/assets/images/speakers/adho-hov.png',
  '/assets/images/speakers/daru.png',
  '/assets/images/speakers/daru-hov.png',
  '/assets/images/speakers/demi.png',
  '/assets/images/speakers/demi-hov.png',
  '/assets/images/speakers/evlola.png',
  '/assets/images/speakers/evlola-hov.png',
  '/assets/images/speakers/lydaga.png',
  '/assets/images/speakers/lydaga-hov.png',
  '/assets/images/speakers/modi.png',
  '/assets/images/speakers/modi-hov.png',
  '/assets/images/speakers/ms.png',
  '/assets/images/speakers/msh.png',
  '/assets/images/speakers/nacu.png',
  '/assets/images/speakers/nacu-hov.png',
  '/assets/images/speakers/olre.png',
  '/assets/images/speakers/olre-hov.png',
  '/assets/images/speakers/pall.png',
  '/assets/images/speakers/pall-hov.png',
  '/assets/images/speakers/podema.png',
  '/assets/images/speakers/podema-hov.png',
  '/assets/images/speakers/sadr.png',
  '/assets/images/speakers/sadr-hov.png',
  '/assets/images/speakers/unkr.png',
  '/assets/images/speakers/unkr-hov.png',
  '/assets/images/union-jack-badge.png',
  '/assets/images/usa-flag.png',
  '/assets/styles/fr16.min.css',
  '/attendees',
  '/codeofconduct',
  '/contact',
  '/content/01-home/anniversary.png',
  '/content/02-speakers/00-oliver-reichenstein/oliver-reichenstein.jpg',
  '/content/02-speakers/00-una-kravets/una-kravetz.jpg',
  '/content/02-speakers/01-polle-de-maagt/polle-de-magt.jpg',
  '/content/02-speakers/02-sarah-drasner/sarah-drasner.jpg',
  '/content/02-speakers/03-dave-rupert/dave-rupert.jpg',
  '/content/02-speakers/04-eva-lotta-lamm/eva-lotta-lamm.jpg',
  '/content/02-speakers/05-aaron-gustafson/aaron-gustafson.jpg',
  '/content/02-speakers/05-lyza-danger-gardner/lyza-danger-gardner.jpg',
  '/content/02-speakers/06-paul-lloyd/paul-lloyd.jpg',
  '/content/02-speakers/07-monica-dinculescu/monica-dinculescu.jpg',
  '/content/02-speakers/10-adrian-holovaty/adrian-holovaty.jpg',
  '/content/02-speakers/11-denys-mishunov/denys-mishunov.jpg',
  '/content/02-speakers/12-nathan-curtis/nathan-curtis.jpg',
  '/content/02-speakers/15-the-mystery-speaker/mystery-alt.png',
  '/content/04-workshops/03-eva-lotta-lamm/eva-lotta-lamm.jpg',
  '/content/04-workshops/04-nathan-curtis/nathan-curtis.jpg',
  '/content/04-workshops/04-vitaly-friedman/vitaly-friedman.jpg',
  '/content/05-locations/parking-in-freiburg.png',
  '/content/05-locations/02-hotels/01-intercity-hotel/hotel-intercity.jpg',
  '/content/05-locations/02-hotels/02-hirschen-hotel/hotel-hirschen.png',
  '/content/05-locations/02-hotels/03-rappen-hotel/rappen.jpg',
  '/content/05-locations/02-hotels/04-best-western-victoria/hotel-best-western-victoria.jpg',
  '/content/05-locations/02-hotels/06-city-hotel/cityhotel.jpg',
  '/content/05-locations/02-hotels/07-hotel-am-stadtgarten/stadtgarten.jpg',
  '/content/05-locations/02-hotels/08-park-hotel-post/park-hotel.jpg',
  '/content/05-locations/02-hotels/09-hotel-rheingold/rheingold.jpg',
  '/content/06-sponsors/01-wifi-lounge/00-microsoft/ms-edge.png',
  '/content/06-sponsors/03-party-sponsor/00-virtual-identity/virtual-identity.png',
  '/content/06-sponsors/03-silver/00-haufe-lexware/haufe-lexware.png',
  '/content/06-sponsors/03-speaker-dinner-host/00-mediatemple/mediatemple.png',
  '/content/06-sponsors/04-coffee/00-iconfinder/iconfinder.png',
  '/content/06-sponsors/05-virtual/00-kirby/kirbyicon.png',
  '/content/06-sponsors/05-virtual/00-startup-vitamins/startup-vitamins.jpg',
  '/content/06-sponsors/05-virtual/00-stickermule/stickermule.jpg',
  '/content/06-sponsors/05-virtual/00-tesla-amazing/ta-logo.png',
  '/content/06-sponsors/05-virtual/00-typeform/typeform-logo.png',
  '/content/06-sponsors/05-virtual/00-uxpassion/wot-opt.png',
  '/content/07-about/freiburg-location.jpg',
  '/content/07-about/workshops-preview.jpg',
  '/favicon.ico',
  '/favicon.png',
  '/imprint',
  '/locations',
  '/offline',
  '/registration',
  '/schedule',
  '/schedule/day:monday',
  '/schedule/day:tuesday',
  '/speakers',
  '/speakers/oliver-reichenstein',
  '/speakers/una-kravets',
  '/speakers/polle-de-maagt',
  '/speakers/sarah-drasner',
  '/speakers/dave-rupert',
  '/speakers/eva-lotta-lamm',
  '/speakers/aaron-gustafson',
  '/speakers/lyza-danger-gardner',
  '/speakers/paul-lloyd',
  '/speakers/monica-dinculescu',
  '/speakers/adrian-holovaty',
  '/speakers/denys-mishunov',
  '/speakers/nathan-curtis',
  '/speakers/the-mystery-speaker',
  '/sponsors',
  '/terms',
  '/workshops',
  '/workshops/eva-lotta-lamm',
  '/workshops/nathan-curtis',
  '/workshops/vitaly-friedman',
];

// Now, let's wait for the install-event
self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        return cache.addAll(urlsToCache);
      }).then(function() {
        return self.skipWaiting();
      }).catch(function() {
        console.log('Oh noes. Seems the install event failed.');
      })
  );
});

// Then we can start fetching stuff
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {

        // Cache hit - return response
        if (response) {
          return response;
        }

        // IMPORTANT: Clone the request. A request is a stream and
        // can only be consumed once. Since we are consuming this
        // once by cache and once by the browser for fetch, we need
        // to clone the response
        var fetchRequest = event.request.clone();

        return fetch(fetchRequest).then(
          function(response) {

            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            // IMPORTANT: Clone the response. A response is a stream
            // and because we want the browser to consume the response
            // as well as the cache consuming the response, we need
            // to clone it so we have 2 stream.
            var responseToCache = response.clone();

            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.get, responseToCache);
              });

            return response;
          }
        );
      })
    );
});


// Activation
self.addEventListener('activate', function(event) {

  var cacheWhitelist = CACHE_NAME;

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );

  return self.clients.claim();
});
@wanderview
Copy link

This code in your fetch event handler should use event.request instead of event.get:

            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.get, responseToCache);
              });

@MarcoHengstenberg
Copy link
Author

MarcoHengstenberg commented Sep 15, 2016

How does that change the behaviour of the worker?
Because when I added the script into the list of files and pages to cache, the worker did what I expected it to do.

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