Basic Of Progressive Web Apps
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://github.com/Meggin/hello-world-pwa.
Create responsive hello-world app
Include viewport and stylesheet link in index.html (see also https://codepen.io/Meggin/pen/wrJgOX):
<!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 # Generate a firebase.json (REQUIRED)
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 <script>
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">
</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 128×128, 144×144, 152×152, 192×192, 512×512.
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"
}
Then link to manifest.json
in 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>
</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 (thanks, Stack Overflow):
- 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:
Source : https://medium.com/dev-channel/learn-how-to-build-a-pwa-in-under-5-minutes-c860ad406ed