Skip to content
← Back to Community
How to make a PWA
Profile icon
TheBest156

(PWA stands for Progressive Web App)

One of the most important characteristics of Progressive Web Apps (PWAs) is the “progressive”. You don’t have to implement every feature of a PWA to consider your site a PWA. Instead, the idea is that you implement a range of steps, each making your app better for your end users.

This blog post makes a key assumption. There are many developers out there who want to make their apps progressively better, but they want to do it in 5 minutes or less. And that’s what this blog aims to show you.

It’s a very basic PWA hello-world, showing you a set of simple steps to re-work your own app. Words are kept to a minimum, linking to docs for those who need or want to read more. Feel free to skip the blog altogether, and just clone the app: https://replit.com/@TheBest156.

Create responsive hello-world app

Include viewport and stylesheet link in index.html (see also https://replit.com/@TheBest156):

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My hello world page</title>
<link rel="stylesheet" type="text/css" href="hello-world.css" media="all">
</head>
<body>
<h1 class="vertical-container">Hello World</h1>
</body>
</html>
//Use flexbox in hello-world.css to center text responsively://
body { background-color: #FF9800; color: black; } .vertical-container { height: 300px; display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; -webkit-justify-content: center; justify-content: center; } 'h1.vertical-container { font-size: 275%; }

Host with Firebase

Create Firebase project

Create Firebase project in Firebase console and add project to index.html:

IMPORTANT: you will need to replace all Firebase project details in sample code throughout this blog with your own Firebase project details.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#008000"/>
<title>My hello world page</title>
<link rel="stylesheet" type="text/css" href="hello-world.css" media="all">
</head>
<body>
<h1 class="vertical-container">Hello World</h1>
<script src="https://www.gstatic.com/firebasejs/4.4.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = { apiKey: "AIzaSyAXK4Orxl2CghIQvKiUPtkhEngSgzteqE0", authDomain: "hello-world-pwa-8669c.firebaseapp.com", databaseURL: "https://hello-world-pwa-8669c.firebaseio.com", projectId: "hello-world-pwa-8669c", storageBucket: "hello-world-pwa-8669c.appspot.com", messagingSenderId: "660239288739" }; firebase.initializeApp(config);
</script>
</body>
</html>

Initialize Firebase project

Make sure node.js is installed and then run:

$ npm install -g firebase-tools
$ firebase init

Select Hosting:

Guided by Firebase, select your project, change public directory to src, configure as single-page app, and DO NOT overwrite index.html.
Deploy Firebase project

$ firebase deploy
Go to URL and check it looks like this:

Run Lighthouse
Get Lighthouse extension and run lighthouse tool on hosted site:

Register Service Worker
Add service worker
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#008000"/>
<title>My hello world page</title>
<link rel="stylesheet" type="text/css" href="hello-world.css" media="all">
</head>
<body>
<h1 class="vertical-container">Hello World</h1>
<script src="https://www.gstatic.com/firebasejs/4.4.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = { apiKey: "AIzaSyAXK4Orxl2CghIQvKiUPtkhEngSgzteqE0", authDomain: "hello-world-pwa-8669c.firebaseapp.com", databaseURL: "https://hello-world-pwa-8669c.firebaseio.com", projectId: "hello-world-pwa-8669c", storageBucket: "hello-world-pwa-8669c.appspot.com", messagingSenderId: "660239288739" };
firebase.initializeApp(config);
</script>
<script>
if('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(function() { console.log('Service Worker Registered'); }); }
</script>
</body>
</html>

Cache Static Resources

Create sw.js and add index.html and hellow-world-pwa.css to hello- world-page cache:

var cacheName = 'hello-world-page';
var filesToCache = [ '/', '/index.html', '/hello-world.css' ];
self.addEventListener('install', function(e) { console.log('[ServiceWorker] Install'); e.waitUntil( caches.open(cacheName).then(function(cache) { console.log('[ServiceWorker] Caching app shell'); return cache.addAll(filesToCache); }) ); });
self.addEventListener('activate', event => { event.waitUntil(self.clients.claim()); });
self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request, {ignoreSearch:true}).then(response => { return response || fetch(event.request); }) ); });

Test resources cached

Re-deploy, open Chrome DevTools, and check Cache storage under Application tab:

Create an icon

Create an icon and save in sizes 128x128, 144x144, 152x152, 192x192, 512x512.

Create manifest.json

To support add to homescreen feature, create manifest.json:

{ "name": "Hello World PWA", "short_name": "Hi", "icons": [{ "src": "icons/icon-128x128.png", "sizes": "128x128", "type": "image/png" }, { "src": "icons/icon-144x144.png", "sizes": "144x144", "type": "image/png" }, { "src": "icons/icon-152x152.png", "sizes": "152x152", "type": "image/png" }, { "src": "icons/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "icons/icon-512x512.png", "sizes": "512x512", "type": "image/png" } ], "start_url": "/index.html", "gcm_sender_id": "103953800507", "display": "standalone", "background_color": "#FF9800", "theme_color": "#FF9800" }

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#008000"/>
<title>My hello world page</title>
<link rel="stylesheet" type="text/css" href="hello-world.css" media="all">
<link rel="manifest" href="manifest.json">
</head>
<body>
<h1 class="vertical-container">Hello World</h1>
<script src="https://www.gstatic.com/firebasejs/4.4.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = { apiKey: "AIzaSyAXK4Orxl2CghIQvKiUPtkhEngSgzteqE0", authDomain: "hello-world-pwa-8669c.firebaseapp.com", databaseURL: "https://hello-world-pwa-8669c.firebaseio.com", projectId: "hello-world-pwa-8669c", storageBucket: "hello-world-pwa-8669c.appspot.com", messagingSenderId: "660239288739" };
firebase.initializeApp(config);
</script>
<script>
if('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(function() { console.log('Service Worker Registered'); }); }
</script>
</body>
</html>

Set up Push Notification

Add user permission request to index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#008000"/>
<title>My hello world page</title>
<link rel="stylesheet" type="text/css" href="hello-world.css" media="all">
<link rel="manifest" href="manifest.json">
</head>
<body>
<h1 class="vertical-container">Hello World</h1>
<script src="https://www.gstatic.com/firebasejs/4.4.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = { apiKey: "AIzaSyAXK4Orxl2CghIQvKiUPtkhEngSgzteqE0", authDomain: "hello-world-pwa-8669c.firebaseapp.com", databaseURL: "https://hello-world-pwa-8669c.firebaseio.com", projectId: "hello-world-pwa-8669c", storageBucket: "hello-world-pwa-8669c.appspot.com", messagingSenderId: "660239288739" };
firebase.initializeApp(config);
</script>
<script>
if('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(function() { console.log('Service Worker Registered'); }); }
</script>
<script>
const messaging = firebase.messaging(); messaging.requestPermission() .then(function() { console.log('Notification permission granted.'); return messaging.getToken(); }) .then(function(token) { console.log(token); }) .catch(function(err) { console.log('Unable to get permission to notify.', err); })
</script>
</body>
</html>

Get service worker to handle push events in new file, firebase-messaging-sw.js:

importScripts('https://www.gstatic.com/firebasejs/4.4.0/firebase-app.js'); importScripts('https://www.gstatic.com/firebasejs/4.4.0/firebase-messaging.js'); var config = { apiKey: "AIzaSyAXK4Orxl2CghIQvKiUPtkhEngSgzteqE0", authDomain: "hello-world-pwa-8669c.firebaseapp.com", databaseURL: "https://hello-world-pwa-8669c.firebaseio.com", projectId: "hello-world-pwa-8669c", storageBucket: "hello-world-pwa-8669c.appspot.com", messagingSenderId: "660239288739" };
firebase.initializeApp(config); const messaging = firebase.messaging(); messaging.setBackgroundMessageHandler(function(payload) { const title = 'Hello World'; const options = { body: payload.data.body };
return self.registration.showNotification(title, options); });

Test Push Notification

To set up push notifications using Firebase Cloud Messaging:

Get your Firebase project’s server key:

Click the settings icon/cog wheel next to your project name at the

top of the new Firebase Console.

Click Project Settings.

Click the Cloud Messaging tab. Copy key under Server Key.

Redeploy your Firebase app: $ firebase deploy.

Open Chrome DevTools console, and copy the token in the console ### log.

Test push notification from the command line (replace YOUR_SERVER_KEY with the copied key and DEVICE_REGISTRATION_TOKEN with the copied token):

curl -X POST -H "Authorization: key=YOUR_SERVER_KEY" -H "Content-Type: application/json" -d '{ "notification": { "title": "Hello World PWA", "body": "Hi", }, "to": "DEVICE_REGISTRATION_TOKEN" }' "https://fcm.googleapis.com/fcm/send"

Run Lighthouse Again

Deploy and run Lighthouse again. It’s not perfect but it is progressively enhanced

Copyright 2021 by @TheBest156 See Profile Below

https://replit.com/@TheBest156

Voters
Profile icon
JBloves27
Profile icon
firefish
Profile icon
Retrospicer
Profile icon
lilykhan
Profile icon
TheBest156
Comments
hotnewtop
Profile icon
RixTheTyrunt

D:

Profile icon
RixTheTyrunt

I need a Node.js server instead of a HTML CSS and JavaScript website!

Profile icon
DynamicSquid

Use three backticks to format code :)

Profile icon
EpicGamer007

@DynamicSquid dang, the creator probably had an exteremly hard time adding ``` to everything.

Profile icon
TheBest156

@DynamicSquid Thx for the notice!

Profile icon
HahaYes

@DynamicSquid Well hello DynamicSquid! Its been a while

Profile icon
DynamicSquid

@HahaYes hellooo!

Profile icon
TheBest156

Worked so hard on MARKDOWN Hope this helps anybody :)

Profile icon
Retrospicer