DEV Community

Cover image for How to transform a React app built on Webpack to PWA
Chukwunonso Orjiakor
Chukwunonso Orjiakor

Posted on • Updated on

How to transform a React app built on Webpack to PWA

Early this month, in my spare time I was able to transform one of my Solo React projects into a Progressive Web App (PWA). I accomplished this in less than a day and I will be writing on how I achieved this feat in this article.

First thing first, for some of you that are not familiar with PWA. According to Wikipedia, "A progressive web application (PWA) is a type of application software delivered through the web, built using common web technologies including HTML, CSS and JavaScript. It is intended to work on any platform that uses a standards-compliant browser. Functionality includes working offline, push notifications, and device hardware access, enabling creating user experiences similar to native applications on desktop and mobile devices".

List of companies that are currently using it for their user-facing apps is endless and it includes big names like Twitter, Instagram, Telegram, AliExpress, FlipBoard just to mention a few.

Pre-requisites

Before forging ahead with this article I expect you to have a working React application that is built on Webpack. Also, it will be a plus if the app is responsive and mobile-friendly, as this will give the users a feel of a native mobile app or desktop app.

Steps

To successfully transform a react app built on webpack into a PWA, we will be creating a manifest file and a service worker that will help us to achieve our aim. Read through the below steps to see how I accomplished it.

Create The Manifest File

According to this article, "The web app manifest is a JSON file that tells the browser about your Progressive Web App and how it should behave when installed on the user's desktop or mobile device. A typical manifest file includes the app name, the icons the app should use, and the URL that should be opened when the app is launched".
The manifest file is best put in the public folder where the index.html file can easily access it. Below is a sample of what the manifest file looks like in its simplest form:

{
  "short_name": "Football Update",
  "name": "Live Football Score Update",
  "icons": [
    {
      "src": "../images/favicon.gif",
      "sizes": "64x64",
      "type": "image/gif"
    },
    {
      "src": "../images/football-logo.png",
      "type": "image/png",
      "sizes": "256x256"
    }
  ],
  "start_url": "../",
  "display": "standalone",
  "theme_color": "#27ae60",
  "background_color": "#fff"
}
Enter fullscreen mode Exit fullscreen mode

You can read more on the manifest file and its properties here.

For the manifest file to take effect, ensure you deploy it in the index.html file by adding the below line of code in the <head> tag:

<link rel="manifest" href="manifest/manifest.json" />
Enter fullscreen mode Exit fullscreen mode

Generate The Service Worker

Sandoche ADITTANE in one of his articles titled How PWAs works and how I implemented it with React and Webpack described Service Worker as thus: "A service worker is a script that runs in the background of your browser separated from your website. You can use this script to cache files, send a push notification or do other background tasks like updating your page for example".

This helps to cache files such as logos, favicons, manifest and other resources that make the PWA run smoothly in the browser. You can read more on it from the above link or here or here.

To generate the Service Worker, you will have to add Webpack's Workbox plugin in your webpack.config.js file.

First, install the workbox-webpack-plugin node module by running:

npm install workbox-webpack-plugin --save-dev
Enter fullscreen mode Exit fullscreen mode

Then, in your webpack.config.js, add the following lines of code that starts with a +:

  const path = require('path');
  const webpack = require('webpack');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CopyWebpackPlugin = require('copy-webpack-plugin');
+ const WorkboxPlugin = require('workbox-webpack-plugin');
  const Dotenv = require('dotenv-webpack');

  module.exports = {
    ...
    plugins: [
      new Dotenv({
        safe: true,
        systemvars: true
      }),
      new HtmlWebpackPlugin({
 -      title: 'Football Update',
 +      title: 'Football Update WPA',
        template: path.resolve('public/index.html')
      }),
 +    new WorkboxPlugin.GenerateSW({
 +      // these options encourage the ServiceWorkers to get in there fast
 +      // and not allow any straggling "old" SWs to hang around
 +      clientsClaim: true,
 +      skipWaiting: true
 +    }),
      new CopyWebpackPlugin([
        { from: 'public/images', to: 'images' },
 +      { from: 'public/manifest', to: 'manifest' }
      ]),
      new webpack.HotModuleReplacementPlugin()
    ]
  };
Enter fullscreen mode Exit fullscreen mode

With the above addition, you will generate the Service Worker, and also expose the manifest file folder so that it can be accessed by the web browser.

When you run: npm build or yarn build in your project terminal, the Service Worker files should be generated as shown in the image below:
Generate Service Worker

Register Your Service Worker

Once Service Worker has been generated and you have your manifest.json file in the right place, open your index.js file which is the entry point into your app, and add the following codes to register the Service Worker.

  import React from 'react';
  import ReactDom from 'react-dom';

  import App from './App';
  import './assets/styles/index.css';

  ReactDom.render(<App />, document.getElementById('root'));

+ if ('serviceWorker' in navigator) {
+   window.addEventListener('load', () => {
+     navigator.serviceWorker.register('/service-worker.js')
+    .then(registration => {
+       console.log('SW registered: ', registration);
+     }).catch(registrationError => {
+       console.log('SW registration failed: ', registrationError);
+     });
+   });
+ }
Enter fullscreen mode Exit fullscreen mode

At this point, you have successfully created and linked the manifest.json to the index.html for your PWA, and also generated and registered a Service Worker for the background activities on the browser. You can now run your app to see the beauty of a PWA.

Here is a link to the PWA I built in this process: https://footballscores.netlify.app/.
It is an app that keeps football lovers updated with football matches scores, and it's still a work in progress which I add new features to whenever am less busy.
See screenshot of the app on a mobile device below:
Football App Screenshot

When you visit the link on your Android mobile device, it will prompt you to add the PWA icon to your home screen. Also, on your desktop browser (particularly Google Chrome version 70 and above), a plus (+) button appears at the right of the address bar when you visit the link. Click on it to add the icon of the WPA to your desktop like a native application.

Thanks for journeying with me through this article. Your feedback and comments will be highly appreciated. Kindly leave your comments in the comment section.

Top comments (7)

Collapse
 
johnclement20 profile image
john-clement20

Nice job

Collapse
 
bhargab profile image
BHARGAB KALITA

Hey, I have a question, in the src folder I have serviceWorker.js file ,what should I do with it? Should I delete it !!

Collapse
 
chuksjoe profile image
Chukwunonso Orjiakor

Good evening Kalita. Sorry I'm just replying your question.
If you've done your webpack setting rightly, the serviceWorker.js file will be auto generated when you build the app.

Also note that you don't need to use the create-react-app command, cos it sets up the PWA for you by default

Collapse
 
deadman67264369 profile image
m.m.behnasr

Here is a link to the WPA I built in this process:
your mean is pwa ???

Collapse
 
chuksjoe profile image
Chukwunonso Orjiakor

oh... thanks for your observation

Collapse
 
yougotwill profile image
Will G

Nice post. Always been interested in PWAs this makes things more clear.

Collapse
 
chuksjoe profile image
Chukwunonso Orjiakor

Am glad it did 😊