Using Service Workers with create-react-app

By Shaumik Daityari

  • They improve the performance of your website. Caching key parts of your website only helps in making it load faster.
  • Enhances user experience through an offline-first outlook. Even if one loses connectivity, one can continue to use the application normally.
  • They enable notification and push APIs, which are not available through traditional web technologies.
  • They enable you to perform background sync. You can defer certain actions until network connectivity is restored to ensure a seamless experience to the user.

Service Workers: Lifecycle

The lifecycle of a service worker typically needs to be coded by the developer. In case of service workers in React, the life cycle management is handled by React itself, which makes the process easier for a developer to enable and use service workers.

Image for post
Image for post
Service Worker Lifecycle (Source)

React Service Workers: Key Considerations

  • Service workers are executed by the browser in their own global script context. This means that you do not have direct access to your page’s DOM elements. Therefore, you need an indirect way for service workers to communicate with pages that they are supposed to control. This is handled through the postMessage interface.
  • Service workers run only on the HTTPS protocol. The only exception here is when you run it in localhost.
  • They are not tied to a particular page, and therefore, can be reused.
  • Service workers are event-driven. This means that service workers can not retain any information once they shut down. In order to access information from earlier states, you need to use the IndexedDB API.

Activate React Service Workers

├── README.md├── node_modules├── package.json├── .gitignore├── build├── public│ ├── favicon.ico│ ├── index.html│ └── manifest.json└── src ├── App.css ├── App.js ├── App.test.js ├── index.css ├── index.js ├── logo.svg

└── serviceWorker.js

Notice the serviceWorker.js file in the src directory. By default, this file is generated when you create a React application.

At this stage, your service worker is not registered, so you will have to first register it before utilizing it in your application.

To register the service worker, navigate to the src/index.js file, and look for the following line:

serviceWorker.unregister();

Change it to the following line.

serviceWorker.register();

This single line change will now enable you to use service workers in your React application.

In a general web application, you would have to code the whole lifecycle of a service worker. However, React enables service workers by default and allows a developer to directly get into working with them. Navigate to the src/serviceWorker.js file and you will notice that the underlying methods of a service worker are present.

Working with React Service Workers in Development Environment

  • You can remove this condition from the function register() to enable it in development mode. However, this could potentially lead to some caching issues.
  • A cleaner way of enabling service workers is to create a production version of your React app, and then serve it. You can run the following commands to do so:
$ yarn global add serve$ yarn build

$ serve -s build

Head over to localhost:5000 in a browser to check the served application.

Configure a Custom Service Worker to CRA

Around line 34 in the serviceWorker.js file, look for the load() even listener and add your custom file to it.

window.addEventListener('load', () => { const swUrl = `${process.env.PUBLIC_URL}/custom-service-worker.js`; ...

}

Next, update the package.json file as below.

"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-app-rewired eject"

},

In this step, we will invoke Google’s Workbox plugin.

npm install --save-dev workbox-build

Next, you need to create a config file to instruct CRA to insert our custom service worker.

const WorkboxWebpackPlugin = require("workbox-webpack-plugin");module.exports = function override(config, env) { config.plugins = config.plugins.map((plugin) => { if (plugin.constructor.name === "GenerateSW") { return new WorkboxWebpackPlugin.InjectManifest({ swSrc: "./src/custom-service-worker.js", swDest: "service-worker.js" }); } return plugin; }); return config;

};

You can then proceed to create the custom service worker to cache a particular directory as shown below.

workbox.routing.registerRoute( new RegExp("/path/to/cache/directory/"), workbox.strategies.NetworkFirst());

workbox.precaching.precacheAndRoute(self.__precacheManifest || [])

Ensure that you build your application again for the changes to take effect.

Final Thoughts

In case you are interested to explore this further, here is a complete tutorial on creating a progressive web app in React.

Learn More