How to use Workbox to implement Service worker in your React app?

Workbox is a great library by Google to add offline support to your web apps via service worker. It takes care of most of the boilerplate which developers have to code to implement offline support.

One of the major features of workbox is their routing and caching strategy modules. Below are the strategies which Workbox supports :-

  • Stale While Revalidate
  • Network First
  • Cache First
  • Network Only
  • Cache Only

I will be using workbox for one of my side project which is built using React with SSR to demonstrate the usage of this. Workbox has a webpack plugin which is what we will use.

  1. Install workbox webpack plugin :-

    npm i workbox-webpack-plugin --save-dev

  2. Make sure you disable the caching of your webpack generated assets at the server side. If we were not using something like workbox, then we usually cache the assets generated in the below manner :-

    app.use(express.static('public', {maxAge: '30d'}))

  3. Lets configure the caching strategy within our webpack file :-

    We will be using the GenerateSW plugin to generate the service worker and add it to the webpack assets. For this example, we will be using cacheFirst strategy for images, fonts and for all other we will be using networkFirst strategy.

    const {GenerateSW} = require('workbox-webpack-plugin')
    ...
    ...
    plugins: [
        new GenerateSW({
            runtimeCaching: [
                {
                    urlPattern: /images/,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: new RegExp('^https://fonts.(?:googleapis|gstatic).com/(.*)'),
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /.*/,
                    handler: 'networkFirst'
                }
            ]
        })
    ]
    

    There are some other options as well which you can provide within the webpack :-

    • swDest: file name of the service worker which will be generated. If nothing is provided, it will take the default file name which is service-worker.js. The parent directory for this file will be based on your output.path webpack configuration.

    • clientsClaim: instructs the latest service worker to take control of all clients as soon as it’s activated

    • skipWaiting: instructs the latest service worker to activate as soon as it enters the waiting phase.

  4. Once you run your webpack build, you will see that it has generated a file named service-worker.js in your output directory. If you open that, you will see something like the below code :-

    Dont make modifications to this file as this is auto generated by the webpack plugin.

     /**
     * Welcome to your Workbox-powered service worker!
     *
     * You'll need to register this file in your web app and you should
     * disable HTTP caching for this file too.
     * See https://goo.gl/nhQhGp
     *
     * The rest of the code is auto-generated. Please don't update this file
     * directly; instead, make changes to your Workbox build configuration
     * and re-run your build process.
     * See https://goo.gl/2aRDsh
     */
    
     importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.0.1/workbox-sw.js");
    
     importScripts(
     "/precache-manifest.3ff7b9253d76be179f9406284ec2a485.js"
     );
    
     /**
     * The workboxSW.precacheAndRoute() method efficiently caches and responds to
     * requests for URLs in the manifest.
     * See https://goo.gl/S9QRab
     */
     self.__precacheManifest = [].concat(self.__precacheManifest || []);
     workbox.precaching.suppressWarnings();
     workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
    
     workbox.routing.registerRoute(/images/, workbox.strategies.cacheFirst(), 'GET');
     workbox.routing.registerRoute(/^https:\/\/fonts.(?:googleapis|gstatic).com\/(.*)/, workbox.strategies.cacheFirst(), 'GET');
     workbox.routing.registerRoute(/.*/, workbox.strategies.networkFirst(), 'GET');
    
    
  5. The final step is to call this generated service worker. Since i am using this in a React SSR app, i will add the below code to my Appshell.

     <script>
         if ('serviceWorker' in navigator) {
             window.addEventListener('load', function() {
                 navigator.serviceWorker.register('/service-worker.js');
             });
         }
     </script>
    
  6. Now lets bring up our app and see how the service worker is behaving. The first thing you will see when you bring up the app is that it has preached files which were generated via webpack.

    Workbox initial view

    You could also browse through the preached and runtime assets for your app within the Chrome developer tools.

    Workbox preached and runtime assets

  7. Now, lets reload the app and see which are the resources is it fetching from going to network and the ones its fetching from cache. When you do this make sure, you dont enable Disable Cache. When you look athe console, you would see the details as below :-

    Workbox initial view

    You can see that its fetching images, JS/CSS bundles & fonts from cache, thereby drastically reducing the loading time of the app. Do, make sure that whenever you generate JS bundle, you are appending a unique hash to it. Whenever you make any subsequent change, the JS bundle will be created with a new hash and thus the workbox router will go against network to fetch it.

  8. Now, lets see how our app behaves in offline mode. You will see something like below.

    • First of all the workbox router went against network to fetch the root HTML.
    • As no network as present, it checked whether there was a cached response of the same.
    • The workbox router responded with a cached response of the same.

    Workbox initial view

    So you could see that your app is fully functional even when there is no network connection.

  9. Finally, lets see whats the PWA lighthouse score for our app. Along with workbox, several other factors are also responsbile for that high score.

    Workbox initial view

Resources

  • https://developers.google.com/web/tools/workbox/
comments powered by Disqus