Skip to content

Instantly share code, notes, and snippets.

@GautamPanickar
Last active July 19, 2020 07:48
Show Gist options
  • Save GautamPanickar/fa7f6dc5a5ce8bf45dc2327dbf2125bd to your computer and use it in GitHub Desktop.
Save GautamPanickar/fa7f6dc5a5ce8bf45dc2327dbf2125bd to your computer and use it in GitHub Desktop.
Service worker with Google's Workbox for Angular App - handler file
export const BG_IMAGES_CACHE = 'bg-images-cache';
export class ServiceWorkerHandler {
private dbPromise: IDBOpenDBRequest;
constructor(dbPromise: IDBOpenDBRequest) {
this.dbPromise = dbPromise;
}
/**
* Handler for caching background images.
*/
public bgImagesCacheHandler = async ({ request, url, event }) => {
const cacheURL = this.getCacheImageURL(url);
return caches.match(cacheURL).then(respFromCache => {
if (respFromCache) {
// If the image was available in cache return it from cache.
return respFromCache;
}
// Fetch the response from server and cache it.
return fetch(event.request).then(respFromServer => {
let respClone = respFromServer.clone();
caches.open(BG_IMAGES_CACHE).then(bgCache => {
bgCache.put(cacheURL, respClone);
});
return respFromServer;
});
});
}
/**
* Handler for fetching/putting bg images in IndexedDB.
*/
public bgImagesDBHandler = async ({ request, url, event }) => {
const imageID = this.getImageIdFromURL(url);
return this.fetchImageFromDB(imageID).then((imageResult: Blob) => {
if (imageResult) {
// If image is directly available in DB then return the blob as the response.
return new Response(imageResult);
} else {
// If the image is unavailable, fetch the image by resuming the intercepted request to the server.
return fetch(event.request).then(response => {
const respClone = response.clone();
return respClone.blob()
}).then(imageBlob => {
return this.putImageInDB(imageID, imageBlob).then((resolvedImage: Blob) => {
return new Response(resolvedImage);
});
});
}
});
}
/**
* Fetches the image from DB.
*/
private fetchImageFromDB(imageId: string) {
return new Promise((resolve, reject) => {
const tx = this.dbPromise.result.transaction('images', 'readonly');
const store = tx.objectStore('images');
const imageInStoreReq = store.get(imageId);
imageInStoreReq.onsuccess = (evt) => {
resolve(imageInStoreReq.result);
};
imageInStoreReq.onerror = (evt) => {
reject('Something went wrong while fetching image from DB ');
};
});
}
/**
* Puts the image in DB. And returns the image.
*/
private putImageInDB(imageId: string, blob: Blob) {
return new Promise((resolve, reject) => {
const tx = this.dbPromise.result.transaction('images', 'readwrite');
const store = tx.objectStore('images');
const imagePutReq = store.put(blob, imageId);
imagePutReq.onsuccess = (evt) => {
const imageInStoreReq = store.get(imageId);
imageInStoreReq.onsuccess = (evt) => {
resolve(imageInStoreReq.result);
};
};
imagePutReq.onerror = (evt) => {
reject('Something went wrong while putting image in DB ');
};
});
}
/**
* Returns the formatted URL which will be used as the key for caching images.
* Strips of any query params if present.
*/
private getCacheImageURL(url: URL): string {
const urlString = url.toString();
if (urlString.indexOf('?') >= 0) {
return urlString.substring(0, urlString.indexOf('?'));
} else {
return urlString;
}
}
/**
* Returns the image Id to be saved in the DB.
*/
private getImageIdFromURL(url: URL): string {
const urlString = url.toString();
const start = urlString.lastIndexOf('/') + 1;
const end = urlString.indexOf('?') >= 0 ? urlString.indexOf('?') : urlString.length;
const imageId = urlString.substring(start, end);
const imagePrefix = urlString.indexOf('bg_images') >= 0
? ' BG-' : ' IMG-;
return imagePrefix + imageId;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment