Progressive web apps (PWAs) have rapidly grown in popularity as essentially fast, performance-based web applications streamlined for delivering mobile app-like experiences. Progressive web apps are built using front-end technologies like HTML, CSS, and JavaScript to create a level of usability and performance that’s in parity with native mobile applications. They are responsive, consume lesser data and storage space, and supports push notifications and offline usage in the browser.
Also Read:- What is difference between Node.JS and Express.JS?
Progressive web apps (PWAs) came in the lime light recently. It uses the best of web and the best of apps to give a smooth experience to users and feels like native app. PWAs are responsive and fast, consume less data, need less storage space, support push notifications and offline use in browser. Twitter recently launched mobile.twitter.com which delivers mobile app like experience to users in browser without actually installing on user device. This article focuses upon building progressive web app with React JS
Building a progressive web app has now become a web development trend every enterprise wants to follow. Big players such as Twitter and Flipboard recently launched their Progressive web apps to deliver mobile experiences to users, without requiring them to install the app. In this article, you will learn how to build a progressive web app using React. So, let’s get started.
We’re going to build a simple PWA in this article. You can use this code as boilerplate for further PWA developments.
Also Read:- Progressive Web Applications and Service Workers
Getting Started with PWA
First let’s generate a React application with create-react-app. You can run the following commands to generate the React app.
npm install -g create-react-app
create-react-app pwa-app
Also Read:-How to Deploy a Simple HTML/CSS/Javascript Application on Heroku
Next we will install React Router:
cd pwa-app
npm install --save react-router@3.0.5
Also Read:- Uploading files with ReactJS and NodeJS
Now replace your src/App.js
content with below gist. It will give us a basic template with navigation.
import React, { Component } from 'react';
import { Router, browserHistory, Route, Link } from 'react-router';
import './App.css';
const NavBar = () => (
<div className="navbar">
<Link to="/">Feed</Link>
<Link to="/profile">Profile</Link>
</div>
);
const Template = ({ title }) => (
<div>
<NavBar />
<p className="page-info">
This is the {title} page.
</p>
</div>
);
const Feed = (props) => (
<Template title="Feed"/>
);
const Profile = (props) => (
<Template title="Profile"/>
);
class App extends Component {
render() {
return (
<Router history={browserHistory}>
<Route path="/" component={Feed}/>
<Route path="/profile" component={Profile}/>
</Router>
);
}
}
export default App;
Also Read:- List of Top Mobile Apps Develop In React Native
Next we need to update the default styles a bit to make our app look clean. Replace your src/App.css `with below styles.
.navbar {
background-color: #01C8E5;
text-align: center;
}
.navbar a {
display: inline-block;
padding: 10px;
color: #fff;
text-decoration: none;
}
.page-info {
text-align: center;
font-weight: bold;
}
How to Develop a Blog App Using NextJS
Finally run npm start
to check the app in the browser. Now this is a basic app with 2 routes. We will now convert it to PWA.
Install Lighthouse and Audit
Lighthouse is an open-source, automated tool which helps us to test our app against PWA checklist. It also provides audits for performance, accessibility, and more. You can download and install in your chrome browser by following this link.
Also Read : 5 Best Examples of Progressive Web Apps in 2019
Next let’s test our app using Lighthouse. Click on Lighthouse icon in the top right corner of Chrome and then click on Generate Report button. This is how the generated report looks like –
Register a Service Worker
Services worker act as proxy servers that sit between app and network. Using this we will intercept network requests and serve cached files. It will allow our web app to work even if network is offline.
Also Read:- How To Use the New React Context API
First create a blank worker.js file in public folder of the app and add this block of code in that file.
// Flag for enabling cache in production
var doCache = false;
var CACHE_NAME = 'pwa-app-cache';
// Delete old caches
self.addEventListener('activate', event => {
const currentCachelist = [CACHE_NAME];
event.waitUntil(
caches.keys()
.then(keyList =>
Promise.all(keyList.map(key => {
if (!currentCachelist.includes(key)) {
return caches.delete(key);
}
}))
)
);
});
// This triggers when user starts the app
self.addEventListener('install', function(event) {
if (doCache) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
fetch('asset-manifest.json')
.then(response => {
response.json();
})
.then(assets => {
// We will cache initial page and the main.js
// We could also cache assets like CSS and images
const urlsToCache = [
'/',
assets['main.js']
];
cache.addAll(urlsToCache);
})
})
);
}
});
// Here we intercept request and serve up the matching files
self.addEventListener('fetch', function(event) {
if (doCache) {
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
}
});
We will check whether the browser supports service workers, and then register our worker.js. To do so add the below script to public/index.html. (Notice that we have removed “shrink-to-fit=no” from viewport meta tag.)
Also Read:- How to setup Google reCAPTCHA in a ReactJS app?
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('worker.js').then(function(registration) {
console.log('Worker registration successful', registration.scope);
}, function(err) {
console.log('Worker registration failed', err);
}).catch(function(err) {
console.log(err);
});
});
} else {
console.log('Service Worker is not supported by browser.');
}
</script>
</body>
</html>
Restart you app and reload the browser. You will see “Worker registration successful” message in developer console. Now let’s re-generate the Lighthouse report.
Improve Progressive Nature of the app
Currently, our app renders empty root div till the JavaScript loads and React hooks up the initial route. We need make sure our app works without any JavaScript loading and displays some HTMl and CSS before React comes into the play. Here’s how our updated index.html looks like.
Also Read:- A Simple CRUD App Using GraphQL, NodeJS, and MongoDB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.navbar {
background-color: #01C8E5;
text-align: center;
}
.navbar a {
display: inline-block;
padding: 10px;
color: #fff;
text-decoration: none;
}
.page-info {
text-align: center;
font-weight: bold;
}
</style>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root">
<div class="navbar">
<a href="/">Feed</a>
</div>
<p class="page-info">
Loading an awesome app...
</p>
</div>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('worker.js').then(function(registration) {
console.log('Worker registration successful', registration.scope);
}, function(err) {
console.log('Worker registration failed', err);
}).catch(function(err) {
console.log(err);
});
});
} else {
console.log('Service Worker is not supported by browser.');
}
</script>
</body>
</html>
Re-audit the app using Lighthouse and you will see the performance is improved;
Add Splash Icons
We need to add a 512×512 icon to show up on splash screen. For doing so we need to update the manifest.json and put the icon in public folder.
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
We also need to add these meta tags to inform the browser that our app is a PWA.
<!-- Tell the browser it's a PWA -->
<meta name="mobile-web-app-capable" content="yes">
<!-- Tell iOS it's a PWA -->
<meta name="apple-mobile-web-app-capable" content="yes">
Also Read:- Top 10 Things You Can Build With Reactjs
Let’s Deploy
We’re now only missing HTTPS and caching which will be fixed after deploy. Update the doCache flag to true in worker.js file. Next, create a new project in firebase-console with name Pwa App. Run the following commands in project directory.
npm install -g firebase-tools
firebase login
firebase init
Make sure your firebase.json looks like this-
{
"hosting": {
"public": "build",
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
After initialisation build the app and deploy.
npm run build
firebase deploy
Now when we do audit using Lighthouse on deployed URL. We should see this result.
We’re done! Now we have a working base for building progressive web app with React JS.?We’re ready for the future of web applications.