Frontend-Applikation - Anzeige der korrekten Versionsnummer
Semantic-Verisoning im Frontend – die Versionsnummer soll Teil des Build-Artefakts sein und im Frontend angezeigt werden. Daran habe ich mir bisher die Zähne ausgebissen – hier mein finaler Ansatz inklusive der notwendigen Anpassungen, um das Problem ein für alle Mal zu lösen.

Hintergrund
Bei der Versionierung von Software nutzen wir bei konzentrik das Konzept von Semantic Versioning
. Dabei erhält das kommende Release anhand der Änderungshistorie automatisiert eine Versionsnummer. Diese wird bei uns beim Erstellen des Produktivcodes automatisch anhand der Commits ermittelt.
In unserem Fall soll diese Versionsnummer im Frontend immer verfügbar werden. Einerseits "unsichtbar" im Header der index.html
falls der Kunde keine Anzeige wünscht, oder andererseits z. B. in der Sidebar, sodass diese Kennung für den Kunden sichtbar ist. Bei Bug-Reports ist der Kunde angehalten, diese Versionsnummer beim Report anzugeben.
Problem der bisherigen Lösungsansätze
Im Rahmen unserer Automatisierung wird die neue Versionsnummer als GitHub Action in die package.json
in das Feld version
geschrieben. Dies ist der letzte Schritt im automatischen Prozess für den Fall eines erfolgreichen Releases. Es erfolgt hierfür ein Commit mit der Änderung der package.json
.
Für die Anzeige im Frontend haben wir eine Konstante genutzt, die im React-Kontext definiert ist. Dieser Wert gibt die Zeichenkette aus dem Feld version
der package.json
zurück. Dadurch, dass wir die neue Version am Ende des Workflows schreiben, ist die Versionsnummer im gebauten Paket nicht die aktuelle, sondern die vorherige Versionsnummer.
const appVersion = VERSION
Den Workflow anzupassen, ist der naheliegende Schluss – jedoch keine gute Idee. Erst wenn alle Schritte erfolgreich durchlaufen sind, können wir sicher sein, dass die neue Version gebaut werden kann. Und entsprechend erst zu dem Zeitpunkt das Commit erstellen. Wie also kommen wir aus diesem Henne-Ei-Problem heraus?
Die neue Lösung
Das Ziel bleibt: Das Build-Artefakt, ob in einem Docker-Container, als Zip-Datei oder direkter Upload zu einem Server, soll die korrekte Versionsnummer enthalten. Die Nutzung der Konstante zum Auslesen aus der package.json
ist ausgeschlossen.
Folglich muss vor dem Bauen des Frontend-Codes die Versionsnummer ermittelt und in den HTML-Header und die Sidebar geschrieben werden. Erst danach kann der npm run build
Befehl ausgeführt werden. Die notwendigen Anpassungen in der GitHub-Action-YAML sind folgende:
- Im Sourcecode Platzhalter für die Versionsnummer vorbereiten
In der index.html
folgende Zeile im HTML-Header einfügen
Zusätzlich noch im EnvVar-Service, der gekapselten Zugriff auf Environment Variablen im Frontend bietet, den Platzhalter einfügen. Damit kann z. B. in der Sidebar auf den Wert zugegriffen werden. Oder woanders im Frontend, wie immer die genau UI-Vorlage aussieht.
const appVersion = 'SEMANTIC_RELEASE_VERSION'
- Notwendige Abhängigkeiten installieren und in
.releaserc
Plug-ins eintragen
npm install -D semantic-release-export-data
// in .releaserc
// ...
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"semantic-release-export-data",
"@semantic-release/github",
// ...
- Ausführen sämtlicher Vorbedingungen, wie Check-out, Abhängigkeiten installieren, Tests, Linter, etc. innerhalb der GitHub-Action-YAML
- Dry-Run von Semantic Release ermöglicht danach Zugriff auf die nächste Version via
${{ steps.get-next-version.outputs.new-release-version }}
# In ci.yaml
- name: Semantic release dry run to determine version
run: npx semantic-release --dry-run
id: get-next-version
env:
GITHUB_TOKEN: ${{ secrets.PAT_SEMANTIC_RELEASE }}
- Build-Schritt mit Docker erhält die neue Versionsnummer als BUILD_ARG
- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
labels: ${{ steps.meta.outputs.labels }}
push: true
tags: ${{ steps.meta.outputs.tags }}
build-args: |
GITHUB_NPM_TOKEN=${{ secrets.PACKAGE_REGISTRY_TOKEN }}
NODE_VERSION=${{ steps.nvm.outputs.NODE_VERSION }}
SEMANTIC_RELEASE_VERSION=${{ steps.get-next-version.outputs.new-release-version }}
- Im Dockerfile die Platzhalter durch die neue Versionsnummer ersetzen
FROM node:${NODE_VERSION}-alpine AS build
# ensure the build arg is accessible in the build stage
ARG SEMANTIC_RELEASE_VERSION
WORKDIR /app
ENV PATH=/app/node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm install
COPY . ./
# replace SEMANTIC_RELEASE_VERSION placeholder with actual version
RUN echo "SEMANTIC_RELEASE_VERSION: ${SEMANTIC_RELEASE_VERSION}"
RUN sed -i "s/SEMANTIC_RELEASE_VERSION/${SEMANTIC_RELEASE_VERSION}/g" index.html
RUN sed -i "s/SEMANTIC_RELEASE_VERSION/${SEMANTIC_RELEASE_VERSION}/g" src/services/EnvVars.ts
RUN npm run build
Achtung: es ist wichtig, das ARG SEMANTIC_RELEASE_VERSION
nach der Build Stage zu benennen, weil sonst die Variable leer ist → siehe Docker Dokumentation für weitere Details.
Fazit
Mit dem oben beschriebenen Ansatz wird die Versionsnummer Teil des Build-Artefakts und garantiert somit die korrekte Anzeige in der Applikation. Das dafür notwendige Zusammenspiel aus Semantic Versioning und Docker Build in der GitHub-Action bedarf einer Handvoll Konfigurationen, die jedoch universell für jedes Frontend-Projekt einsetzbar sind. D. h. einmal eingerichtet, ist das Problem mit der korrekten Versionsnummer gelöst.
Schreib mich gerne an, wenn du Zugriff auf die komplette GitHub-Action-YAML-Datei, das Dockerfile oder die sonstigen Konfigurationsdateien benötigst.