

Build Progressive Web Apps with React — Part 1
source link: https://www.tuicool.com/articles/hit/zEfIFnU
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Build Progressive Web Apps with React — Part 1
How to transform a React application into a progressive web application with great performance — deep tutorial


Progressive Web Apps (PWA) are something that almost everyone in mobile app development is talking about. And though PWAs have been around for a while now, they have been gaining more and more attention every day.
Originally introduced by Google in 2015, PWA is an app that can contain features such as offline capability, push notifications, greater performance and speed, and local caching of assets.
With the help of PWA technology, even web developers can build great mobile apps using their own web stack. You don’t need to learn Java, Objective-C, Swift, or React Native. You can build PWAs with Angular, Vue, or React!
In this post, you will get to see how to turn a simple Web App built with React into a Progressive Web App! You will learn how to run the app completely offline, how to cache assets, how to use Workbox to create service workers, and finally how to install the PWA into your smartphone!
Prerequisites
Before getting started, let’s make sure that we have gathered all the “ingredients” required to cook this app.
First, make sure that you have the latest version of Node installed. Then, if you don’t already have a code editor installed, then go get one. I personally recommend the VS Code.
Instead of wasting time and text space on building a whole new web app, I am going to use one that I have already created. This app is going to be a simple Todo App built using React with Firebase and Redux. I have already written a post describing how to build this app.
Building A ToDo App in React with Firebase and Redux
Learn how to use Redux and Firebase Database in React by building a simple Todo App blog.bitsrc.io
If you are impatient and just want to get started with the PWA stuff, you clone the full web app using Git as shown below:
$ git clone https://github.com/rajatk16/firedux-todo.git
$ cd firedux-todo
$ npm install
This set of commands will download the project folder, and install the node modules.
It goes without saying that since we are building a React Progressive Web App, we need to have the React CLI installed on the system as well.
It’s also recommended to use Bit for the application’s components so that you won’t have to rewrite them in your next app. Instead, just share them with Bit and make them reusable from any other app you have no or in the future.
Service Workers
Service workers are what make Progressive Web Apps so amazing. Basically, a service worker is a script that is run by the browser in the background. It does not interact with the actual app and even the usual user won’t know anything about it.
Let’s take a look at the code in the index.js
file of our app.


The final line of code says serviceWorker.register();
. The older version of the Create-React-App CLI used to do it for us. But with version 2.0, the service worker is unregister();
ed by default. So make sure that you make the change to the code in your future PWAs.
React uses a “cache-first” strategy so that all the assets generated by the app get saved. Take a look at the register
function of serviceworker.js
file as shown below:


Here, the code says that the service worker will only register if the app is in production mode. You can change the code so that the service worker will worker will register in development mode, but that is usually not a good idea as it will cause problems with caching.
So what we can do is build a production version of the app and serve it as shown below:
$ yarn global add serve $ yarn build $ serve -s build
This will run the app on localhost:5000
in the browser. If you open the Developer tools and go to the console tab, you should get a couple of messages from Workbox about the pre-cache status of your app’s assets.


Create-React-App’s default service worker will only cache the static assets, so if you turn off your internet and refresh the browser, the app’s UI will load because it is a static asset. But the task, which is being fetched from Firebase will not load.


Updating the Service Worker
It is more difficult to debug a PWA than a regular app because of how they get cached the browser.
In Chrome’s DevTools, you will see a tab named Application. Inside you can see all the info related to the service worker of our app.


There are two ways by which we can update the service worker. One is by clicking on the “Update on Reload” option at the top, the other is by manually updating the service worker using the update link. You can also unregister the service worker and reload the browser to update the service worker.
Normally if you make any changes to your app, you would need to rebuild the production version of the app and re-launch it on the browser in order to see the changes.
But things get a little more complicated in case of Progressive Web Apps. That is because the service worker has cached the previous version’s assets, and we need to update the service worker, close all browser tabs that have the app opened in them, and open the app again to see the changes.
Try to change the name of the app from the generic “React App” that we see on the tab to something like “Firedux Todo”. To do this, you will first need to go to public/index.html
, change title
tag’s content to Firedux Todo
, and rebuild the production version of the app as shown below:
$ yarn build $ serve -s build
Then reopen the app in the browser. If the app’s title has not changed, then try to update the service worker and see if it works.
Creating Custom Service Workers
Create-React-App’s default service worker is good for caching static assets, but we want to do much more than that. For that, we need to disregard the default service worker and create one of our own.
The simplest way to do that is to go to the public
folder in our app’s directory and create a new service worker file. I am going to name it customWorker.js
. For now, let’s add a simple console log to check if it works.
console.log("Hello World");
The React App is still going to choose its default service worker. To fix this, open the src/serviceworker.js
and at line 34 you will find the following code:
window.addEventListener('load', () => { const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
Replace the service-worker.js
with the name of our custom service worker.
Run yarn build
and serve -s build
again to create a new production build and serve it. Reopen the app on chrome and check the console to see if you get the Hello World
message printed.
If you get any errors, try to unregister the service worker and reload the browser.


This is a very manual way of using custom service workers in our app. The drawback of this method is that our app can no longer use Workbox. Workbox provides us a with a lot of cool features so it would be better to be able to keep Workbox and create custom service workers. So lets undo all the changes that we made in this section and start over.
Now add a new developer dependency called react-app-rewired
which will help us rewrite the webpack config and take be able to use the Workbox.
$ yarn add -D react-app-rewired
Then open the package.json
file and rewrite the scripts
as shown below:
"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-app-rewired eject" }
Then create a new file named config.js
in the root of the project directory. We will import the workbox-webpack-plugin
and map
over all the plugins till we get to the GenerateSW
plugin, which we will then replace with InjectManifest
plugin from Workbox.
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/sw.js', swDest: 'service-worker.js' }) } return plugin }) return config }
We then need to create the sw.js
file in the src
folder. Inside, we will define the actual custom service worker. I will simply add a console log and call skipWaiting
and clientsClaim
, ensuring that the service worker gets installed on all the open clients.
console.log("Hello World") workbox.skipWaiting() workbox.clientsClaim()
Do not add the last two lines if you are going to write a complex service worker, which you probably are.
Rebuild the production version of the app and serve it on the browser. You should then get the Hello World
message printed in the console.
Pre-Cache the Static Assets
Our custom service worker now gets loaded onto the app, but its not really doing anything. In this section, we will write the code that will precache the static assets of the app.
The service worker will use a list of files from the _precacheManifest
, which is generated automatically by the InjectManifest
webpack plugin and cache those files at the correct route. So in the sw.js
file, remove the console.log
function and write the following at the end.
workbox.precaching.precacheAndRoute(self.__precacheManifest || [])
Rebuild the production version of the app and serve it on the browser. Then in the DevTool’s console tab, you will see that the pre-cache is responding to all the static assets of the app.
To verify if the precaching is working, go offline and reload the browser. The app should still reload. The only difference here is that none of the Todos will get loaded because it is not a static asset.
Listening for Install and Activate Events in a Service Worker
The code inside a service worker is purely event based. Two such events are the install
and activate
events. These events are executed code when the PWA gets installed on a device for the first time.
Inside the src/sw.js
file, add an EventListener
for the install
and activate
event as shown below:
self.addEventListener('install', event => { console.log('install') }) self.addEventListener('activate', event => { console.log('activate') })
After rebuilding and reserving the app, you will get to see the console print out install
and activate
in the browser’s console. If you don’t see these messages in the console, thats because the service worker is already installed and activated. You can try unregistering the service worker and reload the browser.
We can do more than just console out messages inside these callbacks. We can clean up old caches and interact with the local storage or indexedDB. Lets start with a setTimeout
wrapped inside a Promise
.
self.addEventListener('install', event => { const asyncInstall = new Promise(resolve => { console.log("Waiting to resolve...") setTimeout(resolve, 5000) }) event.waitUntil(asyncInstall) })
It is important that whatever Promise
we pass to the waitUntil
actually resolves or rejects. If we didn’t resolve in the timeout here, it would wait forever to install the service worker. Then it would never activate. The service worker would never work.
Caching Third Party Resources
Our custom service worker is currently caching only static assets that are included in the React App. So, if you have resources from a third party like Bootstrap, they won’t be included in the cache as they are not available at webpack compile time.
To fix this, we need to change the service worker to add caching for those by assets by using workbox’s registerRoute
method, and a regular expression to match the entire URL of the asset. We will pick the staleWhileRevalidate
cache strategy.
Inside src/sw.js
file, we can define and register a new route for the service worker. The first argument to registerRoute
is either a string that matches the resource that we are trying to cache or a RegExp
that matches it. We will say that anything that starts with https
and ends with min.css
or min.js
. The second argument to register a route tells workbox
what strategy to use when caching that resource.
workbox.routing.registerRoute( new RegExp('https:.*min\.(css|js)') workbox.strategies.staleWhileRevalidate() )
If we check the cache on the application tab, we will get to see that the assets are put into the runtime
cache instead of the pre-cache
. To fix this, we can give a name to the cache by adding the cacheName
option as shown below:
workbox.routing.registerRoute( new RegExp('https:.*min\.(css|js)') workbox.strategies.staleWhileRevalidate({ cacheName: 'cache' }) )
Conclusion
In this post, we saw how to create a Progressive Web App using React’s Create-React-App CLI. We started by talking about React’s default register worker and how it works and what it can do. Then we saw how to update any changes to our app by updating the service worker.
Then, we saw different ways of creating a service worker, and how by using the react-app-rewired
library we can still use the Workbox in our custom service worker. We then saw the code necessary to tell our custom service worker to cache the static and third party assets of our app.
In the next post, we will see how to:
- Add Custom Icons to the PWA
- Change the name and short name of the PWA
- Add the PWA to the Home Screen of a smartphone device and the Chrome App Home Screen
- Access the Camera of a smartphone device
- And more…
Thanks for reading this long post! I hope this post helped you understand React Progressive Web Apps a little better. If you liked this post, then please do give me a few :clap: and please feel free to comment below. Cheers!
You can also check out my posts about how to build Progressive Web Apps with Angular:
Building a Search-Engine Optimized PWA with Angular - Part 1
Progressive Web App + Angular + SEO = Awesome! Here's how blog.bitsrc.io
Recommend
-
18
Raymond Camden
-
10
In 2020, internet traffic is split 44/52 between desktop and mobile. As 71% of customers expect a comparable...
-
12
This week I had the pleasure of attending the Progressive Web Apps Dev Summit, an event organised by Google in the beautiful city of Amsterdam. These are my takeaways from the event.
-
13
Start Building with Web Bluetooth and Progressive Web AppsControlling the Bluetooth-Enabled World from the Comfort of the WebA Short IntroductionWeb Bluetooth is a a new technology that connects the Web w...
-
9
In 2020, internet traffic is split 44/52 between desktop and mobile. As 71% of customers expect a comparable...
-
9
What Are Progressive Web Apps?April 16th 2021 new story5
-
10
Table of contentsUse the Application panel to inspect, modify, and debug web app manifests, service workers, and service worker caches.Related Guides:
-
7
-
7
October 19, 2021 Learn to build great Progressive Web Apps Just last week, more than 5000 people attended the very first online
-
6
Not FoundYou just hit a route that doesn't exist... the sadness.LoginRadius empowers businesses to deliver a delightful customer experience and win customer trust. Using the LoginRadius Identity...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK