This is the first part of a three-part series about creating a Progressive Web App (PWA) which leverages the Web Push API and cron-schedule. In this article, we’ll cover the basics: the front-end, web app manifest and Service Worker aspect of the app, and we’ll be only using pure JavaScript to accomplish this. At the end of this post we’ll have a working PWA that’s cached so it can be accessed while offline.
My physician recently told me to take 3 pills a day. On my way back home I told myself: “I am a developer, I automate tasks, let’s build an app to help me take my pills”.
We’re going to build a simple Progressive Web App (PWA) which will remind me to take my pills every day.
Our app will have a web server powered by Express.js. Express will push notifications to the clients which subscribed to the push notifications. It will also serve the front-end app.
The app we’re building has to remind us to take pills even when the browser is not opened. So we need a Progressive Web App.
My first step building a PWA is to generate a manifest using this generator. This tool will create your manifest.json
file which holds all basic information about your app. It will also create some icons which will show on the user’s phones when they download the app.
Just unzip everything inside a folder at the root of our project that we’ll call public
. I decided to call my app Temporas.
"name": "Temporas",
"short_name": "Temporas",
"theme_color": "#222831",
"background_color": "#ffad17",
"display": "standalone",
"Scope": "",
"start_url": "/index.html",
"icons": [
// A lot of icons
]
PWAs rely on Service Workers. Service workers are little programs that run as soon as they are registered independently from the rest of your JavaScript code. Service workers can’t interact directly with the DOM but can send messages to the rest of your code (we’ll explore this in more detail in part 2 of this series).
Now let’s create our frontend and register our service worker:
<!DOCTYPE html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<meta name="theme-color" content="#222831">
<link rel='manifest' href='./manifest.json'>
<script>
// Registering our Service worker
if('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js', { scope: './' })
}
</script>
</head>
<body>
<div class="hero">
<h1>Temporas</h1>
<h2>Take your medicine my friend</h2>
<div id="status"></div>
<button id="unsubscribe">unsubscribe</button>
</div>
</body>
We are now one file away from having an installable web application. Let’s create our service worker:
const cacheName = 'Temporas';
// Cache all the files to make a PWA
self.addEventListener('install', e => {
e.waitUntil(
caches.open(cacheName).then(cache => {
// Our application only has two files here index.html and manifest.json
// but you can add more such as style.css as your app grows
return cache.addAll([
'./',
'./index.html',
'./manifest.json'
]);
})
);
});
// Our service worker will intercept all fetch requests
// and check if we have cached the file
// if so it will serve the cached file
self.addEventListener('fetch', event => {
event.respondWith(
caches.open(cacheName)
.then(cache => cache.match(event.request, { ignoreSearch: true }))
.then(response => {
return response || fetch(event.request);
})
);
});
✨✨ We have a PWA ✨✨
The PWA will not work if you just open /public/index.html
in your browser. We must serve our content from a web server.
First let’s set things up in our command line. In your root folder run:
$ npm init
$ npm install express body-parser
$ touch app.js
Inside of package.json
replace the scripts
field with:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node app.js"
}
And now let’s populate our app:
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const port = 3000;
// We want to use JSON to send post request to our application
app.use(bodyParser.json());
// We tell express to serve the folder public as static content
app.use(express.static('public'));
app.get('/public');
app.listen(port, () => console.log(`Listening on port ${port}!`));
Now you can run npm run start
. Go to http://localhost:3000, kill the server. Reload http://localhost:3000 and the app will look like it is still working! You can even turn off your laptop and go back to the web page on that port.
I highly advise disabling the caching mechanism of service workers when you are developing new features. It might cause some confusion.
Here’s a good post if you want to learn more about setting up an Express server.
To test your PWA I highly recommend using the Lighthouse extension to see if everything is working. Remember also that when comes the time to deploying your app on the web, it needs to be served over HTTPS to be considered a PWA and to be installable as an app.
You can find all the code in this Github repository.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Sign up for Infrastructure as a Newsletter.
Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Hello, where is the second part?