Unsere Konfiguratoren sind ja hauptsächlich JavaScript-Anwendungen, die sich aus einem Backend Daten und Assets besorgen. Da liegt es nahe, sich mit einer Technik zu befassen, die mit JavaScript-Frontends die nativen Apps ersetzen will.
Progressive Webapps sind Bündel aus HTML-Seiten, CSS, Assets und JavaScript-Programmen, die auf dem Gerät gecached werden und Eigenschaften haben, die sie in die Nähe von nativen Apps rücken:
Zukünftig sollen weitere APIs hinzukommen. Die perspektive ist, dass PWAs irgendwann native Apps ersetzen können.
Damit PWAa gecached und sinnvoll auf dem Homescreen installiert werden können, werden sie durch eine Manifest-Datei beschrieben. Der Browser ruft das Manifest ab und nutzt die Informationen, um die PWA komplett zu laden und zu installieren.
Der Schlüssel zu den Offline-Funktionen und den Push-Notifications sind Service-Worker. Dabei handelt es sich um JavaScript-Code, der asynchron ausgeführt wird ohne Verbindung zu der Webseite, die ihn geladen hat. Er hat dementsprechend keinen Zugriff zum DOM. Er wird auch dann noch ausgeführt, wenn die landende Seite verlassen oder Tab geschlossen wurde.
Alle Aufrufe über xhr und fetch werden durch einen dedizierten ServiceWorker geschleust. Er kann Requests und Ergebnisse cachen und so die offline-Fähigkeit herstellen. Da er auch dann läuft, wenn die Seite nicht mehr angezeigt wird, kann er auch Push-Notifications vom Server empfangen sie vom System darstellen lassen.
In der Praxis wird die Manifest-Datei automatisch erzeugt. Zum Beispiel, indem man das Modul webpack-pwa-manifest
als dev dependency nutzt und in der webpack.config.js
:
new WebpackPwaManifest({
name: 'DevCafe-PWA',
short_name: 'OCPWA',
description: 'A example Progressive Web App!',
background_color: '#ffffff',
icons: [
{
src: path.resolve('src/assets/android-chrome-192x192.png'),
sizes: [96, 128, 192, 256, 384, 512], // multiple sizes
purpose: "any maskable"
},
],
ios: {
"apple-touch-icon": path.resolve('src/assets/apple-touch-icon.png'),
},
theme_color: '#ffffff'
}),
Im Großen und Ganzen kommt das übergebene JSON dann als Manifest heraus und wird im Head der HTML-Datei so eingebunden:
<link rel="manifest" href="manifest.325024171c377a85180d34c599497c0b.json" />
Ansonsten sieht die HTML-Seite genauso aus wie immer.
Der Service-Worker wird in der index.js
eingebunden:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js', {scope: '/'}).then(registration => {
console.log('SW registered: ', registration);
}).catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}
Den Serice-Worker kann man natürlich selbst schreiben. Aber seine Arbeit (Anfragen cachen) ist eigentlich ziemlich generisch. Daher kann man ihn auch automatisch erzeugen lassen, z.B. mit workbox.
Das wird in der webpack.config
einfach als Plugin eingetragen:
const WorkboxPlugin = require('workbox-webpack-plugin');
...
plugins: [
...
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true,
})
]
Es erzeugt dann die service-worker.js
, die oben im Beispiel oben eingebunden wird.
Die App selbst kann dann natürlich mit jedem beliebigen Framework geschrieben sein, zum Beispiel React.