Einleitung
In diesem Tutorial möchte ich das Problem lösen, dass Benutzerinnen alte Versionen deiner Web App nutzen. Das kann z.B. dann passieren, wenn Benutzerinnen nicht mitbekommen, dass eine neue Version verfügbar gemacht wurde, während die App benutzt wird. Als Beispielanwendung wird eine React App genutzt, aber nach diesem Tutorial solltest du die gelernten Prinzipien auf alle npm basierten Single Page Applications anwenden können.
Voraussetzungen
- Grundlegende JavaScript/ReactJS Kenntnisse
- Grundlegende npm Kenntnisse
- Ein klein bisschen bash
- npm und git
Schritt 1 - Das Projekt aufsetzen
Anmerkung: Du kannst auch ein bereits bestehendes Projekt benutzen, welches mit create-react-app
aufgesetzt wurde und diesen Schritt überspringen.
Im ersten Schritt setzen wir das projekt mit create-react-app auf. Wenn du npx create-react-app version-check-example --use-npm
in der Kommandozeile ausführst, wird ein Ordner version-check-example
mit allen notwendigen React Dependencies und npm Konfigurationen erstellt. Es wird außerdem ein git Repository und npm Projekt initialisiert.
Schritt 2 - Während der Laufzeit die Versionsnummer benutzen
Unsere Quelle für die Versionsnummer unserer App ist das "version"
Feld in der package.json
Datei. Nach dem Anlegen des neuen Projekts ist diese standardmäßig "version": "0.1.0"
und wird hochgezählt während du deine App etnwickelst.
Wenn das Projekt gebaut wird (npm build
), kann dank npm die Umgebungsvariable namens $npm_package_version
verwendet werden. Diese können wir jedoch noch nicht in unserer React App verwenden. Dafür müssen wir eine datei .env
im Projektordner erstellen und die folgende Zeile einfügen:
REACT_APP_VERSION=$npm_package_version
Alle Variablen in dieser Datei, welche mit REACT_APP
anfangen, werden (dank webpack) unserer App während der Laufzeit zur Verfügung stehen. Unsere Variable kann nun folgendermaßen verwendet werden:
const version = process.env.REACT_APP_VERSION
Schritt 3 - (Regelmäßige) Versionsprüfung
In diesem Schritt erstellen wir ein Script, welches die neueste Versionsnummer vom Server lädt und sie mit der aktuellen Clientversion abgleicht. Dieses Script kann anschließend periodisch aufgerufen werden.
Zuerst legen wir deine Datei an, die die neuste Versionsummer enthält.
Diese können wir dann in unserer App abrufen und mit der Clientversion vergleichen. Im nächsten Schritt wird diese Datei automatische erstellt.
Wir legen nun also eine Datei namens version
im public
Ordner ab und fügen den folgenden Inhalt (die aktuelle Versionsnummer) ein:
0.1.0
Wichtig: Die Datei darf außer der aktuellen Version keine weiteren Zeichen wie Leerzeichen oder Zeilenumbrüche enthalten.
Danach erstellen wir eine Datei namens version-check.js
im src/utils
Ordner mit folgendem Inhalt:
// Lädt die derzeitige App Versionsnummer vom Server und gibt sie als String zurück
const fetchVersion = async () => {
const response = await fetch('/version')
if (!response.ok) {
throw new Error('Error fetching version')
}
return response.text()
}
export const checkForNewVersion = async () => {
// lade die Versionsnummer vom Server
let serverVersion
try {
serverVersion = await fetchVersion()
} catch (error) {
console.error(error)
return
}
// Vergleiche die Versionsnummer vom server mit der vom Client
// Du könntest außerdem selbst einen Test hinzufügen um zu prüfen ob die Server version tatsächlich neuer ist, als die Clientversion
// Damit verhindert man Probleme z.B. mit alten Versionen im Cache des Servers
if (process.env.REACT_APP_VERSION === serverVersion) {
return
}
// Zeige eine Benachrichtigung
window.alert('Eine neue Version der Anwendung ist verfügbar. Bitte laden Sie die Seite neu.')
}
Anmerkung: create-react-app
stellt im Entwicklungsprozess (mit npm run start
) alle Dateien im public
Ordner zur Verfügung. Deshalb kann mit fetch('/version')
die Datei geladen werden. In Production muss diese Datei vom Server bereitgestellt werden. Hier kannst du mehr darüber erfahren.
Die Funktion checkForNewVersion
kann nun an einer beliebigen Stelle in der Anwendung periodisch aufgerufen werden, z.B. in der Datei src/App.js
:
import React, { useEffect } from 'react'
import checkForNewVersion from './utils/checkForNewVersion'
export const App = () => {
// Erstelle ein Intervall wenn die Komponente im Browser eingebunden wird und prüfe die Version alle 5 Minuten
useEffect(() => {
const interval = setInterval(checkForNewVersion, 5 * 60 * 1000) // prüfe alle 5 Minuten
// Lösche das Intervall, wenn die Komponente entfernt wird
return () => clearInterval(interval)
}, [])
return (
<div>...</div>
)
}
Wenn du nun die App mit npm run start
startest und dann den Inhalt der Datei public/version
zu 0.1.1
änderst, sollte 5 Minuten nachdem du die App geladen hast, ein Alert-Fenster angezeigt werden.
Schritt 4 - Automatisches Generieren und Aktualisieren der Versionsdatei basierend auf der aktuellen Version
npm bietet uns die Möglichkeit die Version unserer App zu verwalten. Diese Version kann durch folgende Befehle erhöht werden:
npm version major
npm version minor
npm version patch
npm erhöht nun die Versionsnummer in der package.json
Datei entsprechend der Semantic Versioning Regeln.
Immer wenn npm version
ausgeführt wird, werden zusätzlich bestimmte Scripte ausgeführt, welche in der package.json
Datei angegeben werden können:
- preversion
- version
- postversion
Wir erstellen jetzt ein bash Script, welches den Wert der Umgebungsvariable $npm_package_version
in die public/version
Datei schreibt. Das Script legen wir im scripts
Ordner ab und nennen es version.sh
.
echo -n $npm_package_version > public/version
git add public/version
- Die erste Zeile schreibt den Wert der Variable
$npm_package_version
in die Dateipublic/version
- Die zweite Zeile fügt die Änderungen zu git hinzu, sodass die diese beim von npm erstellten
git tag
einbezogen werden
Danach fügen wir die folgende Zeile zum scripts
Bereich der Datei package.json
hinzu:
"version": "bash ./scripts/version.sh"
Anmerkung: Es kann sein, dass die Datei version.sh
erst ausführbar gemacht werden muss, z.B. indem man chmod +x scripts/version.sh
ausführt.
Step 5 - Testen
Führe npm version patch
in der Kommandozeile aus. Dies sollte das version
Feld in der Datei package.json
(und package-lock.json
) von 0.1.0
auf 0.1.1
aktualisieren. Der Inhalt der Datei public/version
sollte nun ebenfalls 0.1.1
sein.
Wenn du git log
in der Kommandozeile ausführst, sollte dort außerdem der folgende Eintrag angezeigt werden:
commit your-commit-hash (HEAD -> master, tag: v0.1.1)
...
Fazit
Wir haben einen automatisierten Prozess erstellt, der Benutzer*innen benachrichtigt, sobald eine neue Version der App veröffentlicht wurde. Immer wenn die Version mit npm version [major/minor/patch]
geändert wird, wird ein Script ausgeführt, welches automatisch die Versionsdatei aktualisiert, die Änderungen in git übernimmt und einen git tag erstellt.
Die App lädt periodisch über einen Endpunkt die Versionsnummer und vergleicht sie mit der lokalen Version, welche derzeit im Browser läuft. Unterscheiden sich die Versionen, werden nun die Benutzer*innen benachrichtigen, und zum neu laden der Anwendung aufgefordert.