React Play: Building a Progressive Web Application (PWA) using React
How to create a progressive web app using service worker in a React

A self-taught frontend developer, designer, and writer
Search for a command to run...
How to create a progressive web app using service worker in a React

A self-taught frontend developer, designer, and writer
Great share! I really enjoyed reading this.
Thank you so much for the feedback🙂
Thank you so much for the feedback🙂
You are welcome
I appreciate you sharing this content. I'm looking for an article of this nature.
Thanks bro!
Thank you, Tapas. I appreciate.
If you’ve been coding in React JS, the front-end library for building user interfaces, you probably know that it’s the most popular front-end framework in the tech world. Today, we will go deeper into React and explore and compare class and functiona...
Authentication is a fundamental aspect of modern web and mobile applications. It ensures that users can securely access an app while protecting their data. Firebase, a platform developed by Google, offers a simple and efficient way to add authenticat...

Hello there! My name is Shivam, and today, I will show you how to create this beautiful horizontal scrolling parallax effect with HTML, CSS, and JavaScript. Wouldn't this look stunning on your blog or portfolio site? To achieve this effect, we will ...

Dealing with fonts can get quite overwhelming. For quite some time, I was searching for a way to self-host google fonts because the google fonts API's network request increased the render-blocking time more than I expected. I stumbled upon fontsource...

Our favorite month is here! And we have some amazing activities planned for our community 🤩 Yes, you are right. We are talking about Hacktoberfest! In this blog, we want to cover various ways you can participate in Hacktoberfest through the ReactPla...

The second edition of ReactPlay Hackathon is here!

In recent times, Progressive Web Apps have provided better web experience and rich user interactions thanks to their hybrid approach and progressive enhancement. Additionally, it is fast, safe to use, works without an Internet connection, and resolves some of the problems with websites and mobile apps.
In this tutorial, we will convert a React project to PWA. We will also explore some additional features like web app manifest and service worker.
Basic understanding of React.
A progressive web app is a modern web technology that has most of the benefits of native applications. It is a web development approach to creating similar experiences in native apps. It essentially combines the qualities of web and native apps to provide a better user experience and conversion rates.
Aside from providing better device integration, PWA has the following features:

PWAs consists of three main components namely:
These are integrated into the Web app, and built using web standards or frameworks like React to render content and test PWAs easier.
This is a W3C specification standard containing metadata that provides information about your web application. It is a JSON file that has details added to the server and referenced in the <link> tag.
This works like a proxy between the web app, browser, and the available network. It intercepts all network requests made by the application.
This maintains the interface and handles content with or without a network connection.
To create a progressive web application in a few simple steps, we’ll be using an already existing project - React Play, so we can focus on adding PWA functionalities. The next step is to fork the Github repository and run the following commands:
git clone https://github.com/reactplay/react-play.git
cd reactplay
npm install
#OR
yarn install
Use the following command to start the app in the development mode:
npm start
#OR
yarn start
Now, we should see this project in our browser https://localhost/3000
First, we navigate to public directory and generate a manifest.json file.
Set the icons and other options provided.
Let's first update public/manifest.json with the following code:
{
"short_name": "ReactPlay",
"name": "ReactPlay",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192x192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512x512.png",
"type": "image/png",
"sizes": "512x512"
},
{
"src": "maskable_icon.png",
"sizes": "64x64 32x32 24x24 16x16 512x512 192x192",
"type": "image/png",
"purpose": "maskable"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
So, What do these fields represent:
name: Name of the web app.short name: An exact easy-to-remember name, it could be an acronym.icons: Set of custom icons for the web app.start_url: Instructs the browser to load the home page when the PWA is launched.display: Appearance similar to native apps.theme_color: Color of the toolbar.background_color: Color of splash screen when the PWA is launched.You are required to create a custom icon for your project of sizes 16, 32, 48, 152, and 192 pixels of equal dimensions.
To ensure the PWA is well optimized, ensure the following meta tags are within the <head> in the index.html file:
<link rel="icon" href="./favicon.ico" />
<link rel="apple-touch-icon" href="./logo.png" />
<link rel="manifest" href="./manifest.json" />
In the src directory of our React app, create a service-worker.js and add the following logic:
import { createHandlerBoundToURL, precacheAndRoute } from "workbox-precaching";
import { clientsClaim } from "workbox-core";
import { registerRoute } from "workbox-routing";
import { CacheFirst, StaleWhileRevalidate } from "workbox-strategies";
import { ExpirationPlugin } from "workbox-expiration";
import { CacheableResponsePlugin } from "workbox-cacheable-response";
clientsClaim();
precacheAndRoute(self.__WB_MANIFEST);
const fileExtensionRegexp = new RegExp("/[^/?]+\\.[^/]+$");
registerRoute(({ request, url }) => {
if (request.mode !== "navigate") {
return false;
}
if (url.pathname.startsWith("/_")) {
return false;
}
if (url.pathname.match(fileExtensionRegexp)) {
return false;
}
return true;
}, createHandlerBoundToURL(process.env.PUBLIC_URL + "/index.html"));
registerRoute(
({ url }) => {
const formatImages = [".jpeg", ".jpg", ".png", ".svg", ".gif"];
const ifImage = formatImages.some((i) => url.pathname.endsWith(i));
return url.origin === self.location.origin && ifImage;
},
new StaleWhileRevalidate({
cacheName: "images-cache",
plugins: [new ExpirationPlugin({ maxEntries: 50 })],
})
);
registerRoute(
({ url }) => {
return url.origin === self.location.origin;
},
new CacheFirst({
cacheName: "api-cache",
plugins: [
new CacheableResponsePlugin({
statuses: [200],
}),
],
})
);
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") {
self.skipWaiting();
}
});
Next, create a registerServiceWorker.js in the same src directory.
import { Workbox } from "workbox-window";
const register = () => {
if (process.env.NODE_ENV !== "production") return;
if (navigator?.serviceWorker) {
const wb = new Workbox(`${process.env.PUBLIC_URL}/service-worker.js`);
const checkForUpdate = () => {
const isUpdate = window.confirm("New Update Available. Click OK to update");
if (isUpdate) {
wb.messageSkipWaiting();
}
};
wb.addEventListener("waiting", checkForUpdate);
wb.register();
}
};
export default register;
The next step is to register the web app service worker. So, import registerServiceWorker.js in index.js.
import register from "./registerServiceWorker";
Immediately after const container = document.getElementById("root");
createRoot(container).render(<Index />);, Call the register function:
register();
This implementation makes the app work offline and load faster.
Here’s how it should look:
import RouteDefs from "common/routing/RouteDefs";
import { SearchContext } from "common/search/search-context";
import "index.css";
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import reportWebVitals from "reportWebVitals";
import register from "./registerServiceWorker";
if (process.env.NODE_ENV !== "development") {
console.log = () => {};
console.debug = () => {};
console.info = () => {};
console.disableYellowBox = true;
}
const Index = () => {
const [searchTerm, setSearchTerm] = useState("");
const [showShareModal, setShowShareModal] = useState(false);
const [filterQuery, setFilterQuery] = useState({
level_id: "",
tags: [],
owner_user_id: "",
language: "",
});
const value = {
searchTerm,
setSearchTerm,
filterQuery,
setFilterQuery,
showShareModal,
setShowShareModal,
};
return (
<React.StrictMode>
<SearchContext.Provider value={value}>
<RouteDefs />
</SearchContext.Provider>
</React.StrictMode>
);
};
const container = document.getElementById("root");
createRoot(container).render(<Index />);
register();
Now, this icon should appear on your desktop browser tab for direct installation.
On a mobile device, the installation prompt looks a bit different.

On click, shows a popup to Install.

Web apps are required to pass certain criteria to be recognized as PWA. These criteria are measured using PWA tools like Lighthouse - An open-source Chrome tool for testing websites against PWA criteria.
Navigate to the Developer tools panel, select the Lighthouse, check Progressive Web App, and then Analyze page load. At the end of the analysis, it will display passed criteria and failed ones if any.
Passed criteria are given a
green check markwhile failed ones are indicated withred check markwith details of the issue.
Although PWA offers some of the qualities and features of native apps, they have some limitations and won't completely replace native apps.
As we have seen, converting a React app to a progressive web app comes with some advantages. I hope you have found this helpful and would consider integrating this feature into your next project.
Thanks for reading! If you have any follow-up questions or would like to connect with me, feel free to do so on Twitter.