Erkenntnisse aus einer schrittweisen Migration mit Web Components
Tobias Kohr
Abkündigungen gehören zum Alltag in der Softwarewelt. Frontend-Technologien entwickeln sich schnell weiter, und Frameworks, die einst den Standard gesetzt haben, erreichen irgendwann ihr End-of-Life. Dann stehen Teams vor den Risiken veralteter Technologie: Der Support verschwindet, die Kompatibilität wird unsicher, und die Wartung wird langsamer und aufwändiger.
AngularJS 1 ist ein gutes Beispiel. Als es 2010 erschien, veränderte es die Arbeitsweise vieler Frontend-Teams. Der offizielle Support endete 2022, doch zahlreiche langlebige Plattformen basieren weiterhin darauf. Die zentrale Frage lautet also: Wie entwickelt man weiter, ohne den Betrieb zu stoppen?
Eine der Plattformen, die vor dieser Herausforderung standen, war das Geoportal Luxemburg, eine fortgeschrittene Anwendung auf Basis von Geomapfish, OpenLayers und AngularJS. Im Laufe der Jahre wurde sie umfangreich, funktionsreich und stark angepasst. Die Entwicklungsumgebung war schwerfällig und langsam, unter anderem wegen der komplexen Docker-Komposition. Eine komplette Neuentwicklung war keine Option, da das produktive System laufend neue Funktionen und Korrekturen erhält. Wir brauchten eine progressive Migration, die Modernisierung Schritt für Schritt ermöglicht, und das bei laufendem Betrieb.
Wir haben den Prozess in mehrere Phasen gegliedert.
Phase 1: Klein anfangen mit LitElement
Unser erster Schritt war die Einführung von LitElement-Webkomponenten direkt in die bestehende Anwendung. Die ursprüngliche Architektur blieb nahezu unverändert. Wir behielten das LESS-basierte CSS und verzichteten auf grössere Eingriffe in den globalen State. Die Integration funktionierte technisch, aber das Ergebnis überzeugte nicht. Die Entwicklung blieb langsam, und das starke Coupling mit Legacy Code machte selbst kleine Änderungen mühsam. Schnell wurde klar: Lit-Komponenten einfach in das alte Framework einzubetten würde nicht die benötigte Verbesserung bringen.
Phase 2: Mehr Freiraum schaffen mit RxJS
In der zweiten Phase ging es darum, Entwicklungsfreiheit zu gewinnen. Wir erstellten eine separate Anwendung und ein eigenes Repository für die neuen Web Components. Ohne die Einschränkungen des Legacy-Systems wurde die Arbeit sofort schneller und angenehmer.
Parallel bauten wir einen neuen Application Core mit einem State Management auf Basis von RxJS und führten Tailwind CSS für das Styling ein. Lit und RxJS funktionierten gut zusammen, aber die Kombination war umständlich und wenig verbreitet. Sie funktionierte, fühlte sich aber nicht zukunftstauglich an.
Phase 3: Wechsel zu Vue und Pinia
In der dritten Phase wechselten wir von Lit und RxJS zu Vue und Pinia. Zusätzlich entwickelten wir einen neuen State Persistor, um den Anwendungszustand sowohl mit der URL als auch mit dem Local Storage zu synchronisieren.
Die Migration verlief reibungsloser als erwartet. Das Reaktivitätssystem von Vue brachte genau das, was Lit fehlte: eingebaute Reaktivität, mit weniger Boilerplate und klareren Mustern. Das machte die Architektur leichter verständlich und besser wartbar. Vitest erleichterte zudem die Tests.
Integration: Ein hybrides Modell, um in Bewegung zu bleiben
Nachdem der neue Core und die Komponenten stabil waren, haben wir sie als Bibliothek verpackt und eine hybride Umgebung aufgebaut, in der sie parallel zur Legacy-Anwendung laufen können. So konnten wir Teile des alten Frontends schrittweise ersetzen, ohne Unterbruch des Produktionsbetriebs.
Der neue Core erleichterte die Integration deutlich. Die Komponenten funktionierten gut zusammen. Legacy-Teile konnten weiterhin auf den neuen State hören, und das OpenLayers-Map-Objekt wurde weiterhin in den alten Code durchgereicht, sodass bestehende Tools einwandfrei weiterliefen.
Natürlich gab es Herausforderungen. Zum Beispiel erlauben Vue-Webkomponenten nicht ohne weiteres, den Shadow DOM zu deaktivieren – das erforderte einige CSS-Anpassungen auf beiden Seiten. Diese Punkte waren jedoch gut beherrschbar und bremsten die Migration nicht wesentlich.
Das hybride Vorgehen erwies sich letztlich als robuste Strategie. Wir konnten die neue Anwendung parallel entwickeln und gleichzeitig Teile davon in das laufende System integrieren, und dies in einem Tempo, das für das Projekt tragbar war.
Fazit
Rückblickend lassen sich einige klare Erkenntnisse festhalten.
Kleine Experimente zu Beginn gaben Sicherheit, aber der echte Fortschritt begann erst, als wir die neue Entwicklung vom Legacy-Umfeld getrennt haben. Eine progressive Migration muss nicht disruptiv sein. Durch sorgfältiges Schichten neuer Technologien und ein kontrolliertes Weiterführen des alten Systems entsteht ein reibungsloser Übergang; für Entwickler wie für Anwender.
Das hybride Modell bedeutete etwas mehr Aufwand, bot aber genau die Flexibilität, die wir brauchten. Es erlaubte uns, die Plattform Schritt für Schritt zu modernisieren, ohne laufende Entwicklungen zu blockieren oder das Risiko eines grossen Bruchs einzugehen. Technisch waren verschiedene Kombinationen möglich. LitElement und RxJS funktionierten, erzeugten aber unnötige Komplexität. Der Wechsel zu Vue und Pinia führte zu einer klareren, produktiveren Entwicklungsumgebung.
Mit diesem Ansatz konnten wir eine komplexe Anwendung modernisieren – im Einklang mit ihrer Geschichte, ihren Nutzern und den Anforderungen des laufenden Betriebs.
Karriere
Sie sind daran interessiert, in einer inspirierenden Umgebung zu arbeiten und sich unseren motivierten und multikulturellen Teams anzuschliessen?