There are plenty of features and configurations for PWA, but we shall focus on the most basic.
PWA requirements
- HTTPS/SSL is mandatory, do check out some of our SSL related tutorials.
- Pages need to be responsive, do try Bootstrap.
Web App Manifest
Web App Manifest is a json file with basic info like name, icons, etc.
- Display:
standalone
(full-screen) orbrowser
{ "short_name": "My App", "name": "My Application", "icons": [ { "src": "/static/img/icon-48.png", "type": "image/png", "sizes": "48x48" }, { "src": "/static/img/icon-96.png", "type": "image/png", "sizes": "96x96" }, { "src": "/static/img/icon-192.png", "type": "image/png", "sizes": "192x192" }, { "src": "/static/img/icon-512.png", "type": "image/png", "sizes": "512x512" } ], "start_url": "/", "background_color": "#F2F2F2", "theme_color": "#2E2E2E", "display": "standalone", "orientation": "landscape"}
Add link tag to the manifest file in your HTML.
<!DOCTYPE html><html lang="en"><head> ... <link rel="manifest" href="/manifest.json"></head><body> ...</body></html>
To verify if your manifest file is configured properly, open Chrome DevTools
(Press F12 in Chrome) -> Application -> Manifest
NOTE: you probbaly want to get your manifest file absolutely correct before deploying to production as updating them later might be an issue (refer to this and this).
Service Worker for caching
A service worker is a type of web worker. It's essentially a JavaScript file that runs separately from the main browser thread, intercepting network requests, caching or retrieving resources from the cache, and delivering push messages.
We need to setup Service Worker to cache the start_url
in order to pass Lighthouse's PWA Audit and enable Add to homescreen
feature.
Add the following code to install and register a service worker. You can add it within your HTML file or put in within a javascript file (e.g. ./main.js
).
Note: if your start_url
is /
, the service worker path must be /service-worker.js
in order to cache it due to scope issues. /js/service-worker.js
can't cache /
as it can only cache content from /js/
.
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js') .then(function(registration) { console.log('Registration successful, scope is:', registration.scope); }) .catch(function(error) { console.log('Service worker registration failed, error:', error); });}
Add the following code in /service-worker.js
for enable Service Worker to cache the start_url
.
Note: if your start_url implement basic HTTP authentication
, you need to implement cache.addAll(urls.map(url => new Request(url, {credentials: 'same-origin'})))
in the install
event caching code.
// Listen for install event, set callbackself.addEventListener('install', function(event) { const CACHE_NAME = 'startup-v1'; const urls = [ '/' ]; event.waitUntil( caches.open(CACHE_NAME).then(function(cache) { return cache.addAll(urls.map(url => new Request(url))); // use the following code if basic HTTP authentication is implemented // https://stackoverflow.com/questions/38193221/how-to-use-a-service-worker-with-basic-authentication-ntlm-negotiate // return cache.addAll(urls.map(url => new Request(url, {credentials: 'same-origin'}))); }) );});self.addEventListener('activate', function(event) { console.log('activate');});self.addEventListener('fetch', function(event) { console.log('fetch: ' + event.request.url); const ignoreUrls = [ '/login', '/static/js/app.js' ]; const url = new URL(event.request.url); if (ignoreUrls.indexOf(url.pathname) > -1) { console.log('ignore'); return } // https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker event.respondWith( // Cache falling back to the network caches.match(event.request).then(function(response) { return response || fetch(event.request); }) );});
For deugging, open Chrome DevTools
(Press F12 in Chrome) -> Application -> Service Workers. If the Service Worker is installed and registered correctly, you should see the following.
If the caching is working, goto Chrome DevTools
-> Application -> Cache -> Cache Storage (Click to expand) and you should see the cache name startup-v1
with start_url
content being cached.
Refreshing both Service Worker and the Cache during development could be quite tricky.
- You can manually
ungister
the Service Worker atChrome DevTools
-> Application -> Service Workers, or enableUpdate on reload
. - You can change CACHE_NAME from
startup-v1
tostartup-v2
and increment it if changes are made to the cache, or you can clear the cache manually atChrome DevTools
-> Application -> Cache -> Cache Storage (Click to expand) -> startup-v1, right click and click onDelete
.
If the /service-worker.js
is served from nginx, you might want to disable HTTP caching by adding the following to nginx configuration.
server {
...
location /service-worker.js {
alias /myapp/static/js/service-worker.js;
expires -1;
}
}
References:
Lighthouse
Use Lighthouse to audit your PWA app. Goto Chrome DevTools
-> Audits and click on Perform an audit ...
. Check on Progressive Web App
only at this moment.
It shall prompt you of any additional changes required.
- You might get
Invalid properties found: {"shrink-to-fit": "no"}
, just ignore it based on this issue. - If you get
Failures: No '<meta name="theme-color">' tag found.
, include<meta name="theme-color" content="#2E2E2E" />
in your HTML. Though you already specifytheme_color
in manifest, you do need to specify in HTML as well based on this issue.
If the manifest and service worker caching is configured properly, your PWA should be ready with a Add to homescreen
prompt if tested on Android. On Desktop, you can test it at Chrome DevTools
-> Application -> Manifest -> Add to homescreen
.
Note: I did see the Add to homescreen
prompt once while testing on Desktop (Chrome 62 on Linux) once, but nothing happens (no error log) on subsequence click on Add to homescreen
at Chrome DevTools
. The Add to homescreen
prompt did work when I tested on Android.
Note: You might want to configure self-signed SSL for development testning.