Service Workers in Loklak Search

Loklak search is a web application which is built on latest web technologies and is aiming to be a progressive web application. A PWA is a web application which has a rich, reliable, fast, and engaging web experience, and web API which enables us to get these are Service Workers. This blog post describes the basics of service workers and their usage in the Loklak Search application to act as a Network Proxy to and the programmatical cache controller for static resources.

What are Service Workers?

In the very formal definition, Matt Gaunt describes service workers to be a script that the browser runs in the background, and help us enable all the modern web features. Most these features include intercepting network requests and caching and responding from the cache in a more programmatical way, and independent from native browser based caching. To register a service worker in the application is a really simple task, there is just one thing which should be kept in mind, that service workers need the HTTPS connection, to work, and this is the web standard made around the secure protocol. To register a service worker

if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed ūüôĀ
console.log('ServiceWorker registration failed: ', err);
});
});
}

This piece of javascript, if the browser supports, registers the service worker defined by sw.js. The service worker then goes through its lifecycle, and gets installed and then it takes control of the page it gets registered with.

What does service workers solve in Loklak Search?

In loklak search, service workers currently work as a, network proxy to work as a caching mechanism for static resources. These static resources include the all the bundled js files and images. These bundled chunks are cached in the service workers cache and are responded with from the cache when requested. The chunking of assets have an advantage in this caching strategy, as the cache misses only happen for the chunks which are modified, and the parts of the application which are unmodified are served from the cache making it possible for lesser download of assets to be served.

Service workers and Angular

As the loklak search is an angular application we, have used the @angular/service-worker library to implement the service workers. This is simple to integrate library and works with the, CLI, there are two steps to enable this, first is to download the Service Worker package

npm install --save @angular/service-worker

And the second step is to enable the service worker flag in .angular-cli.json

"apps": [
   {
      // Other Configurations
      serviceWorker: true
   }
]

Now when we generate the production build from the CLI, along with all the application chunks we get, The three files related to the service workers as well

  • sw-register.bundle.js : This is a simple register script which is included in the index page to register the service worker.
  • worker-basic.js : This is the main service worker logic, which handles all the caching strategies.
  • ngsw-manifest.json : This is a simple manifest which contains the all the assets to be cached along with their version hashes for cache busting.

Future enhancements in Loklak Search with Service Workers

The service workers are fresh in loklak search and are currently just used for caching the static resources. We will be using service workers for more sophisticated caching strategies like

  • Dynamically caching the results and resources received from the API
  • Using IndexedDB interface with service workers for storing the API response in a structured manner.
  • Using service workers, and app manifest to provide the app like experience to the user.

 

Resources and Links

Continue Reading

Adding Service Workers In Generated Event Websites In Open Event Webapp

var urlsToCache = [
 './css/bootstrap.min.css',
 './offline.html',
 './images/avatar.png'
];
self.addEventListener('install', function(event) {
 event.waitUntil(
   caches.open(CACHE_NAME).then(function(cache) {
     return cache.addAll(urlsToCache);
   })
 );
});

All the other assets are cached lazily. Only when they are requested, we fetch them from the network and store it in the local store. This way, we avoid caching a large number of assets at the install step. Caching of several files in the install step is not recommended since if any of the listed files fails to download and cache, then the service worker won’t be installed!

self.addEventListener('fetch', function(event) {
event.respondWith(caches.match(event.request).then(function(response) {
     // Cache hit - return response
     if (response) { return response; }
     // Fetch resource from internet and put into cache
     var fetchRequest = event.request.clone();
     return fetch(fetchRequest).then(function(response) {
         var responseToCache = response.clone();
         caches.open(CACHE_NAME).then(function(cache) {
           cache.put(event.request, responseToCache);
         });
         return response;
       }).catch(function(err) {
         // Return fallback page when user is offline and resource is not cached
         if (event.request.headers.get('Accept').indexOf('text/html') !== -1) {
           return caches.match('./offline.html');
         }
       });
   })
 );
});

One thing which we need to keep in mind is that the website content should not become stale. Because it might happen that the website is updated but the actual content shown is older since response to every request is being fetched from the outdated cache. We need to delete the old cache and install a new service worker when the content of the site is updated. To deal with this issue, we calculate the hash of event website folder after the site has been generated. This value of the hash is used as the cache name inside which we keep the cached resources. When the content of the event website changes, the value of the hash changes. Due to this, a new service worker (containing the new value of the hash) is installed. After the currently open pages of the website are closed, the old service worker is killed and the activate event of the new service worker is fired. During this activate event, we clear the old cache containing the outdated content!  

// Hash of the event website Folder
var CACHE_NAME = 'Mtj5WiGtMtzesubewqMtdGS9wYI=';
self.addEventListener('activate', function(event) {
 event.waitUntil(caches.keys().then(function(cacheNames) {
   return Promise.all(cacheNames.map(function(cacheName) {
     if (cacheName !== CACHE_NAME) {
       console.log('Deleting cache ' + cacheName);
       return caches.delete(cacheName);
     }
   })
   );
 }));
});

Here are many screenshots showing service workers in action

  • When the site is updated, the outdated cache contents are cleared

29312352-87f9e8da-81d2-11e7-9f05-02a557a820da.png

  • On visiting a page which has not yet been cached, its contents are placed into cache for utilization on future visits

29312487-2155e70e-81d3-11e7-85c1-004c4a475e82.png

  • On visiting the cached page again, the assets will be served from the cache directly.

29312349-87f6c222-81d2-11e7-8fb4-c54feb175ed9.png

  • The page will comfortably load even on offline connections

29312351-87f8eec6-81d2-11e7-985a-7f1ba2dba482.png

  • On requesting for a page which has not yet been cached, we show a custom fallback page which shows a message

29312350-87f821c6-81d2-11e7-90e7-30f6467b2988.pngReferences:

Continue Reading
Close Menu