0

I'm developing an audio-based PWA and, since I'm not familiar with this technology, I have a couple of doubts regading the cache management and invalidation in the service worker.

The application need to work offline, that I covered using a SW precache.

My only doubt is the amount of data: in the experience there are 5 use case scenarios. Each scenario has ~30MB of audio content, that means around 150MB + all images, js and css in total to precache.

I know that this exceeds the limit of some browsers (se this question and this article) and in general you must be careful with the storage size, that also depends on the user's device available space on disk.

So that's what I thought: since between one scenario and another, the users will stop by a desk with WiFi connection, my idea is to empty the cache runtime after an user's action (like pressing a button), and replace it with thw new content. This way I would store only one scenario at a time, that means ~35MB, a reasonable size.

Do you think that's a good approach? What's the best way to implement this?

Here's my current code:

service-worker.js

 const PRECACHE = 'precache-test-v1';

 // A list of local resources we always want to be cached.
 const PRECACHE_URLS = [
   '/',
   '/audio/scenario1.mp3',
   '/audio/scenario2.mp3',
   '/audio/scenario3.mp3',
   '/audio/scenario4.mp3',
   '/audio/scenario5.mp3',
   '/css/style.css',
   '/js/bundle.js',
   '/img/favicon.png',
   '/img/logo.png',
   '/img/image1.png',
   '/img/image2.png',
   '/img/image3.png',
   '/img/image4.png',
   '/img/image5.png',
 ];

 // never cache these resources
 const TO_SKIP = [/* empty for now */];

// The install handler takes care of precaching the resources we always need.
self.addEventListener('install', event => {
  const now = new Date();
  console.log(`PWA Service Worker installing - :: ${now} ::`);
  event.waitUntil(caches.open(PRECACHE).then(cache => {
    return cache.addAll(PRECACHE_URLS).then(() => {
      self.skipWaiting();
    });
  }));
});

// The activate handler takes care of cleaning up old caches.
self.addEventListener('activate', event => {
  const now = new Date();
  console.log(`PWA Service Worker activating - :: ${now} ::`);
  const currentCaches = [PRECACHE];
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return cacheNames.filter(cacheName => !currentCaches.includes(cacheName));
    }).then(cachesToDelete => {
      return Promise.all(cachesToDelete.map(cacheToDelete => {
        return caches.delete(cacheToDelete);
      }));
    }).then(() => self.clients.claim())
  );
});

// The fetch handler serves responses for same-origin resources from a cache.
self.addEventListener('fetch', event => {
  // Skip cross-origin requests, like those for Google Analytics and the other provided urls.
  if (event.request.url.startsWith(self.location.origin) && TO_SKIP.every(url => !event.request.url.includes(url))) {
    event.respondWith(
      caches.match(event.request).then(resp => {
        return resp || fetch(event.request).then(response => {
          return caches.open(PRECACHE).then(cache => {
            cache.put(event.request, response.clone());
            return response;
          });
        });
      })
    );
  }
});

index.js

if ('serviceWorker' in navigator) {
   navigator.serviceWorker.register('/sw.js').then(registration => {
     console.log('Registration successful, scope is:', registration.scope);
   }).catch(error => {
     console.log('Service worker registration failed, error:', error);
   });
}

Thank you for your time, Francesco

1 Answers1

1

Hmm.. instead of precaching 5 videos, you could provide an button Save for offline so that the user can save only that videos that he wants to see later offline:

let videoUrl = url to that video:
button.addEventListener('click', function(event) {
  event.preventDefault();
  caches.open("myVideoCache").then(function(cache) {
    fetch(videoUrl)
     .then(function(video) {
        cache.add(video);
     });
  });
});

Do delete 1 entry you need to open your cache and delete it. Pass the path that you stored.

caches.open('myVideoCache').then(function(cache) {
  cache.delete('/path/to/audio.mp4').then(function(response) {
    console.log("entry deleted");
  });
})

More details you can find here: https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker

bill.gates
  • 14,145
  • 3
  • 19
  • 47
  • Hi @Ifaruki, thanks for your answer! This is a good approach, but what if when the user saves the third of fourth content (is actually audio not video, but whatever) the cache size exceeds the limit? Is there a way to target and delete the old content from the cache? – Francesco Cretti Jun 28 '20 at 19:46
  • @FrancescoCretti yes you can delete single entrys from the cache, you need to pass the url of that cached asset / file. if you use chrome, press F12. then go to applications. then go down to cache and click on cache storage to take a look inside your `myVideoCache` or the name what you choose. then you see the row `name` and thats your URL that you need to pass at your delete method – bill.gates Jun 28 '20 at 19:55