
Nutzen Sie die Vorteile eines Mikro-Frontends für ältere Webanwendungen
Kürzlich haben wir über eine neue Fragment-Architektur für die Erstellung von Webanwendungen berichtet. Die Lösung ist schnell, kostengünstig, skalierbar für die größten Projekte und ermöglicht einen schnellen Iterationszyklus. Dieser Ansatz nutzt mehrere zusammenarbeitende Cloudflare Worker, um Mikro-Frontends zu rendern und in eine Anwendung zu streamen, die schneller interaktiv ist als herkömmliche clientseitige Ansätzen – das bedeutet eine bessere Nutzererfahrung und bessere SEO-Werte.
Dieser Ansatz ist großartig, wenn Sie ein neues Projekt beginnen oder die Kapazität haben, Ihre aktuelle Anwendung von Grund auf neu zu schreiben. Aber in der Realität sind die meisten Projekte für einen kompletten Neuaufbau zu groß und können architektonische Änderungen nur inkrementell übernehmen.
In diesem Beitrag schlagen wir eine Möglichkeit vor, wie Sie nur ausgewählte Teile einer alten clientseitig gerenderten Anwendung durch serverseitig gerenderte Fragmente ersetzen können. Das Ergebnis ist eine Anwendung, bei der die wichtigsten Ansichten schneller interaktiv sind, unabhängig entwickelt werden können und alle Vorteile des Mikro-Frontend-Ansatzes erhalten, ohne dass die veraltete Codebasis in großem Umfang umgeschrieben werden muss. Dieser Ansatz ist frameworkunabhängig; in diesem Beitrag zeigen wir Fragmente, die mit React, Qwik und SolidJS erstellt wurden.
Die Qual großer Frontend-Anwendungen
Viele große Frontend-Anwendungen, die derzeit entwickelt werden, bieten keine gute Nutzererfahrung. Das liegt oft an Architekturen, bei denen große Mengen an JavaScript heruntergeladen, geparst und ausgeführt werden müssen, bevor Nutzer mit der Anwendung interagieren können. Trotz der Bemühungen, unkritischen JavaScript-Code durch Lazy Loading und serverseitiges Rendering zu verzögern, brauchen diese großen Anwendungen immer noch zu lange, um interaktiv zu werden und auf die Eingaben des Nutzers zu reagieren.
Darüber hinaus können große monolithische Anwendungen komplex in der Entwicklung und Bereitstellung sein. Manchmal arbeiten mehrere Teams an einer einzigen Codebasis, und der Aufwand für die Koordinierung von Tests und Bereitstellung des Projekts erschwert die Entwicklung, Bereitstellung und Optimierung einzelner Features.
Wie in unserem vorherigen Beitrag beschrieben, bieten von Cloudflare Workers betriebene Mikro-Frontends eine Lösung für diese Probleme, aber die Umwandlung einer monolithischen Anwendung in eine Mikro-Frontend-Architektur ist oft schwierig und teuer. Es kann Monate oder sogar Jahre von Entwicklungsarbeit erfordern, bis Nutzer oder Entwickler die Vorteile spüren.
Wir brauchen einen Ansatz, bei dem ein Projekt schrittweise Mikro-Frontends in die wichtigsten Teile der Anwendung einführen kann, ohne die gesamte Anwendung auf einmal neu schreiben zu müssen.
Fragmente als Retter in der Not
Das Ziel einer fragmentbasierten Architektur ist eine deutliche Reduzierung der Lade- und Interaktionslatenz für große Webanwendungen (gemessen über die Core Web Vitals). Dafür zerlegen wir die Anwendung in Mikro-Frontends, die schnell in Cloudflare Workers gerendert (und gecacht) werden können. Die Herausforderung dabei: Ein Mikro-Frontend-Fragment in eine veraltete, clientseitig gerenderte Anwendung zu integrieren, und zwar mit minimalen Kosten für das ursprüngliche Projekt.
Wir schlagen eine Technik vor, die es uns ermöglicht, die wertvollsten Teile der Benutzeroberfläche einer veralteten Anwendung zu konvertieren, und zwar isoliert vom Rest der Anwendung.
Tatsächlich sind in vielen Anwendungen die wertvollsten Teile der Benutzeroberfläche eingebettet in eine „Anwendungsschale“, die Header-, Footer- und Navigationselemente enthält. Beispiele hierfür sind das Anmeldeformular, der Bereich mit den Produktdetails in einer E-Commerce-Anwendung oder der Posteingang in einem E-Mail-Client.
Schauen wir uns ein Anmeldeformular genau an. Wenn unsere Anwendung das Anmeldeformular erst nach mehreren Sekunden anzeigt, werden die Nutzer sich nur ungern anmelden, und wir könnten sie verlieren. Wir können das Anmeldeformular jedoch in ein serverseitig gerendertes Fragment umwandeln, das sofort angezeigt wird und interaktiv ist, während der Rest der veralteten Anwendung im Hintergrund hochfährt. Da das Fragment bereits interaktiv ist, kann der Nutzer seine Anmeldedaten sogar übermitteln, bevor die veraltete Anwendung gestartet ist und den Rest der Seite gerendert hat.
Mit diesem Ansatz bieten Entwicklerteams den Nutzern wertvolle Verbesserungen zu einem Bruchteil der Zeit und der Entwicklungskosten, ganz anders als bei herkömmlichen Ansätzen, bei denen entweder Verbesserungen der Nutzererfahrung auf der Strecke bleiben oder die gesamte Anwendung langwierig und risikoreich neu geschrieben werden muss. Teams mit monolithischen Single-Page-Anwendungen können eine Mikro-Frontend-Architektur schrittweise einführen, die Verbesserungen auf die wertvollsten Teile der Anwendung ausrichten und so die Investitionsrendite vorverlagern.
Bei der Extraktion von Teilen der Benutzeroberfläche in serverseitig gerenderte Fragmente ergibt sich eine interessante Herausforderung: Sobald sie im Browser angezeigt werden, sollen sich die veraltete Anwendung und die Fragmente wie eine einzige Anwendung anfühlen. Die Fragmente sollten sauber in die veraltete Anwendungshülle eingebettet werden, so dass die Anwendung durch die korrekte Bildung der DOM-Hierarchie zugänglich bleibt. Wir möchten aber auch, dass die serverseitig gerenderten Fragmente so schnell wie möglich angezeigt werden und interaktiv sind – noch bevor die veraltete clientseitig gerenderte Anwendungshülle entsteht. Wie betten wir also UI-Fragmente in eine Anwendungshülle ein, die es noch gar nicht gibt? Wir haben dieses Problem mit einer von uns entwickelten Technik gelöst, wir nennen sie „Fragment Piercing“.
Fragment Piercing
Fragment Piercing kombiniert HTML/DOM, das von serverseitig gerenderten Mikro-Frontend-Fragmenten erzeugt wird, mit HTML/DOM, das von einer veralteten clientseitig gerenderten Anwendung erzeugt wird.
Die Mikro-Frontend-Fragmente werden direkt in die oberste Ebene der HTML-Antwort gerendert und sind so konzipiert, dass sie sofort interaktiv sind. Im Hintergrund wird die veraltete Anwendung clientseitig als ein Geschwisterteil dieser Fragmente gerendert. Wenn sie bereit ist, werden die Fragmente in die veraltete Anwendung „gepierct“ – das DOM jedes Fragments wird an die entsprechende Stelle im DOM der veralteten Anwendung verschoben – ohne dass es zu visuellen Nebeneffekten oder zum Verlust des clientseitigen Status kommt, z. B. des Fokus, der Formulardaten oder der Textauswahl. Sobald ein Fragment „durchdrungen“ (pierced) ist, kann es mit der veralteten Anwendung kommunizieren und wird so zu einem integrierten Teil der Anwendung.
Hier sehen Sie ein „Login“-Fragment und das leere „Root“-Element der veralteten Anwendung auf dem Top-Level des DOM, bevor es gepierct wird.
<body>
<div id="root"></div>
<piercing-fragment-host fragment-id="login">
<login q:container...>...</login>
</piercing-fragment-host>
</body>
Und hier sehen Sie, dass das Fragment in das „login-page“-Div in der gerenderten veralteten Anwendung eingefügt wurde.
<body>
<div id="root">
<header>...</header>
<main>
<div class="login-page">
<piercing-fragment-outlet fragment-id="login">
<piercing-fragment-host fragment-id="login">
<login q:container...>...</login>
</piercing-fragment-host>
</piercing-fragment-outlet>
</div>
</main>
<footer>...</footer>
</div>
</body>
Um zu verhindern, dass sich das Fragment bewegt und während dieses Übergangs eine sichtbare Layoutverschiebung verursacht, wenden wir CSS-Styles an, die das Fragment vor und nach dem Piercen auf die gleiche Weise positionieren.
Eine Anwendung kann zu jedem Zeitpunkt eine beliebige Anzahl von gepiercten Fragmenten anzeigen, oder auch gar keine. Diese Technik ist nicht nur auf das erste Laden der veralteten Anwendung beschränkt. Fragmente können auch jederzeit zu einer Anwendung hinzugefügt oder aus ihr entfernt werden. Auf diese Weise können Fragmente als Reaktion auf Interaktionen des Nutzers und clientseitiges Routing gerendert werden.
Mit Fragment-Piercing können Sie Mikro-Frontends schrittweise mit einem Fragment nach dem anderen einführen. Sie entscheiden über die Granularität der Fragmente und darüber, welche Teile der Anwendung in Fragmente umgewandelt werden sollen. Die Fragmente müssen nicht alle dasselbe Web-Framework verwenden, was beim Wechsel des Stacks oder bei der Integration mehrerer Anwendungen nach der Übernahme nützlich sein kann.
Die Demo der „Productivity Suite“
Zur Demonstration von Fragment-Piercing und inkrementeller Übernahme haben wir eine „Productivity Suite“-Demoanwendung entwickelt, Mit ihr können Nutzer unter anderem To-Do-Listen verwalten und Hacker-News lesen. Wir haben die Shell dieser Anwendung als clientseitig gerenderte React-Anwendung implementiert – eine übliche technische Wahl bei Unternehmensanwendungen. Dies ist unsere „veraltete Anwendung“. Es gibt drei Routen in der Anwendung, die für die Verwendung von Mikro-Frontend-Fragmenten aktualisiert worden sind:
/login
– ein einfaches Dummy-Anmeldeformular mit clientseitiger Validierung, das angezeigt wird, wenn Nutzer nicht authentifiziert sind (in Qwik implementiert)./todos
– verwaltet eine oder mehrere Todo-Listen, implementiert als zwei zusammenarbeitende Fragmente:/news
– ein Klon der HackerNews-Demo (implementiert in SolidJS).
Diese Demo zeigt, dass sowohl für die veraltete Anwendung als auch für jedes der Fragmente verschiedene unabhängige Technologien verwendet werden können.

Die Anwendung wird bereitgestellt unter https://productivity-suite.web-experiments.workers.dev/.
Um sie auszuprobieren, müssen Sie sich zunächst anmelden – verwenden Sie einfach einen beliebigen Benutzernamen (kein Passwort erforderlich). Die Nutzerdaten werden in einem Cookie gespeichert, so dass Sie sich mit demselben Benutzernamen ab- und wieder anmelden können. Nach der Anmeldung können Sie mit Hilfe der Navigationsleiste oben in der Anwendung durch die verschiedenen Seiten navigieren. Werfen Sie insbesondere einen Blick auf die Seiten „Todo Lists“ und „News“, um das Piercing in Aktion zu sehen.
Sie können jederzeit versuchen, die Seite neu zu laden, um zu sehen, dass die Fragmente sofort gerendert werden, während die veraltete Anwendung langsam im Hintergrund lädt. Interagieren Sie mit den Fragmenten, noch bevor die veraltete Anwendung erschienen ist!
Ganz oben auf der Seite finden Sie Steuerelemente, mit denen Sie die Auswirkungen des Fragment Piercing in Aktion sehen können.

- Verwenden Sie den Schieberegler „Legacy app bootstrap delay“, um die simulierte Verzögerung einzustellen, bevor die veraltete Anwendung startet.
- Schalten Sie „Piercing Enabled“ ein, um zu sehen, wie die Nutzererfahrung ohne Fragmente in der App aussehen würde.
- Schalten Sie „Show Seams“ ein, um zu sehen, wo sich die einzelnen Fragmente auf der aktuellen Seite befinden.
So funktioniert's
Die Anwendung setzt sich aus einer Reihe von Bausteinen zusammen.

Der Host der veralteten Anwendung in unserer Demo stellt die Dateien bereit, die die clientseitige React-Anwendung definieren (HTML, JavaScript und Stylesheets). Anwendungen, die mit anderen Tech-Stacks erstellt wurden, würden genauso gut funktionieren. Die Fragment Worker hosten die Mikro-Frontend-Fragmente, wie in unserem vorherigen Beitrag zur Fragment-Architektur beschrieben. Und der Gateway Worker bearbeitet die Anfragen des Browsers, indem er die Antwortströme der veralteten Anwendung und der Mikro-Frontend-Fragmente auswählt, abruft und kombiniert.
Sobald alle diese Teile implementiert sind, arbeiten sie zusammen, um jede Anfrage des Browsers zu bearbeiten. Schauen wir uns einmal an, was passiert, wenn Sie die Route `/login` aufrufen.

Der Nutzer navigiert zu der Anwendung und der Browser stellt eine Anfrage an den Gateway Worker, um den ursprünglichen HTML-Code zu erhalten. Der Gateway Worker erkennt, dass der Browser die Anmeldeseite anfordert. Er stellt dann zwei parallele Unteranfragen – eine, um die index.html der veralteten Anwendung abzurufen, und eine weitere, um das serverseitig gerenderte Login-Fragment anzufordern. Anschließend kombiniert es diese beiden Antworten zu einem einzigen Antwortstrom, er enthält den HTML-Code, der an den Browser übermittelt wird.
Der Browser zeigt die HTML-Antwort an, die das leere Root-Element für die veraltete Anwendung und das serverseitig gerenderte Login-Fragment enthält, das für den Nutzer sofort interaktiv ist.
Der Browser fordert dann das JavaScript der veralteten Anwendung an. Diese Anfrage wird durch den Gateway Worker an den Host der veralteten Anwendung weitergeleitet. In ähnlicher Weise werden auch alle anderen Assets für die veraltete Anwendung oder Fragmente über den Gateway Worker an den Host der veralteten Anwendung oder den entsprechenden Fragment Worker geroutet.
Sobald das JavaScript der veralteten Anwendung heruntergeladen und ausgeführt und dabei die Shell der Anwendung gerendert wurde, setzt das Fragment Piercing ein und verschiebt das Fragment an die richtige Stelle in der veralteten Anwendung, wobei der gesamte Zustand der Benutzeroberfläche erhalten bleibt.
Wir haben uns bei der Erklärung des Fragment Piercing auf das Login-Fragment konzentriert, aber das gleiche Konzept gilt auch für die anderen Fragmente, die in den Routes /todos
und /news
implementiert sind.
Die Piercing-Bibliothek
Obwohl die Fragmente mit unterschiedlichen Web-Frameworks implementiert wurden, werden sie alle auf die gleiche Weise mit Hilfe einer „Piercing-Bibliothek“ in die veraltete Anwendung integriert. Diese Bibliothek ist eine Sammlung von serverseitigen und clientseitigen Utilities, die wir für die Demo entwickelt haben, um die Integration der veralteten Anwendung mit Mikro-Frontend-Fragmenten zu bewältigen. Die wichtigsten Features der Bibliothek sind die Klasse PiercingGateway
, die benutzerdefinierten Elemente Fragment Host und Fragment Outlet sowie die Klasse MessageBus
.
PiercingGateway
Die Klasse PiercingGateway
kann zur Instanziierung eines Gateway Workers verwendet werden, der alle Anfragen nach den HTML-, JavaScript- und anderen Assets unserer Anwendung bearbeitet. Das `PiercingGateway` routet Anfragen an die entsprechenden Fragment Worker oder an den Host der veralteten Anwendung. Außerdem kombiniert es die HTML-Antwortströme dieser Fragmente mit der Antwort der veralteten Anwendung zu einem einzigen HTML-Stream, der an den Browser zurückgegeben wird.
Die Implementierung eines Gateway Workers ist mit der Piercing-Bibliothek unkompliziert. Erstellen Sie eine neue gateway
-Instanz von PiercingGateway
und übergeben Sie ihr die URL des Hosts der veralteten Anwendung sowie eine Funktion, die feststellt, ob Piercing für die gegebene Anfrage aktiviert ist. Exportieren Sie das gateway
als Standardexport aus dem Worker-Skript, damit die Workers-Laufzeit seinen fetch()
-Handler verknüpfen kann.
const gateway = new PiercingGateway<Env>({
// Configure the origin URL for the legacy application.
getLegacyAppBaseUrl: (env) => env.APP_BASE_URL,
shouldPiercingBeEnabled: (request) => ...,
});
...
export default gateway;
Fragmente können durch den Aufruf der Methode registerFragment()
registriert werden, so dass das gateway
Anfragen nach dem HTML-Code und den Assets eines Fragments automatisch an den Fragment Worker routet. Die Registrierung des Login-Fragments würde zum Beispiel so aussehen:
gateway.registerFragment({
fragmentId: "login",
prePiercingStyles: "...",
shouldBeIncluded: async (request) => !(await isUserAuthenticated(request)),
});
Fragment Host und Outlet
Das Routing von Anfragen und die Kombination von HTML-Antworten im Gateway Worker ist nur eine Hälfte davon, was Piercing ermöglicht. Die andere Hälfte muss im Browser stattfinden, wo die Fragmente mithilfe der zuvor beschriebenen Technik in die veraltete Anwendung gepierct werden müssen.
Das Fragment Piercing im Browser wird durch ein Paar benutzerdefinierter Elemente erleichtert, den Fragment Host (<piercing-fragment-host>
) und das Fragment Outlet (<piercing-fragment-outlet>
).
Der Gateway Worker verpackt den HTML-Code für jedes Fragment in einen Fragment Host. Im Browser verwaltet der Fragment Host die Lebensdauer des Fragments und wird verwendet, wenn das DOM des Fragments in der veralteten Anwendung in Position gebracht wird.
<piercing-fragment-host fragment-id="login">
<login q:container...>...</login>
</piercing-fragment-host>
In der veralteten Anwendung markiert der Entwickler, wo ein Fragment beim Piercen erscheinen soll, indem er ein Fragment Outlet hinzufügt. Die Login-Route unserer Demo-Anwendung sieht wie folgt aus:
export function Login() {
…
return (
<div className="login-page" ref={ref}>
<piercing-fragment-outlet fragment-id="login" />
</div>
);
}
Wenn ein Fragment Outlet dem DOM hinzugefügt wird, sucht es im aktuellen Dokument nach dem zugehörigen Fragment Host. Wird er gefunden, werden der Fragment-Host und sein Inhalt in das Outlet verschoben. Wenn der Fragment Host nicht gefunden wird, stellt das Outlet eine Anfrage an den Gateway-Worker, um das Fragment HTML zu holen, das dann direkt in das Fragment Outlet gestreamt wird. Dabei wird die writable-dom-Bibliothek verwendet (eine kleine, aber leistungsstarke Bibliothek des MarkoJS-Teams).
Dieser Fallback-Mechanismus ermöglicht die clientseitige Navigation zu Routen, die neue Fragmente enthalten. Auf diese Weise können Fragmente im Browser sowohl über die anfängliche (harte) Navigation als auch über die clientseitige (weiche) Navigation gerendert werden.
Message Bus
Sofern die Fragmente in unserer Anwendung nicht vollständig präsentativ oder in sich geschlossen sind, müssen sie auch mit der veralteten Anwendung und anderen Fragmenten kommunizieren. Der MessageBus
ist ein einfacher asynchroner, isomorpher und rahmenunabhängiger Сommunication Bus, auf den die veraltete Anwendung und jedes der Fragmente zugreifen können.
In unserer Demoanwendung muss das Login-Fragment die veraltete Anwendung informieren, wenn sich der Nutzer authentifiziert hat. Dieser Nachrichtenversand ist in der Qwik LoginForm
Komponente wie folgt implementiert:
const dispatchLoginEvent = $(() => {
getBus(ref.value).dispatch("login", {
username: state.username,
password: state.password,
});
state.loading = true;
});
Die veraltete Anwendung kann dann wie folgt auf diese Nachrichten achten:
useEffect(() => {
return getBus().listen<LoginMessage>("login", async (user) => {
setUser(user);
await addUserDataIfMissing(user.username);
await saveCurrentUser(user.username);
getBus().dispatch("authentication", user);
navigate("/", { replace: true, });
});
}, []);
Wir haben uns für diese Message-Bus-Implementierung entschieden, weil wir eine rahmenunabhängige Lösung brauchten, die sowohl auf dem Server als auch auf dem Client gut funktioniert.
Probieren Sie es aus!
Mit Fragmenten, Fragment Piercing und Cloudflare Workers verbessern Sie sowohl die Performance als auch den Entwicklungszyklus veralteter clientseitig gerenderter Anwendungen. Sie können diese Änderungen schrittweise vornehmen und dabei Fragmente sogar mit einem Web-Framework Ihrer Wahl implementieren.
Die Anwendung "Productivity Suite", die diese Möglichkeiten demonstriert, finden Sie unter https://productivity-suite.web-experiments.workers.dev/.
Der gesamte von uns gezeigte Code ist Open-Source und auf Github veröffentlicht: https://github.com/cloudflare/workers-web-experiments/tree/main/productivity-suite.
Sie können das Repository gerne klonen. Sie können es einfach lokal ausführen und sogar Ihre eigene Version (kostenlos) bei Cloudflare bereitstellen. Wir haben versucht, den Code so wiederverwendbar wie möglich zu machen. Der größte Teil der Core-Logik befindet sich in der Piercing-Bibliothek, die Sie in Ihren eigenen Projekten ausprobieren können. Wir freuen uns sehr über Feedback und Vorschläge und hören gerne darüber, für welche Anwendungen Sie es verwenden möchten. Beteiligen Sie sich an unserem Gespräch auf GitHub oder schreiben Sie uns in unserem Discord-Kanal.
Wir sind überzeugt: Die Kombination von Cloudflare Workers mit den neuesten Ideen von Frameworks ermöglicht die nächsten großen Schritte nach vorn, wenn es darum geht, die Erfahrungen von Nutzern und Entwicklern in Webanwendungen zu verbessern. Rechnen Sie also mit weiteren Demos, Blogbeiträgen und Kooperationen, während wir weiterhin die Grenzen des Internets ausreizen. Und wenn Sie uns direkt auf dieser Reise begleiten möchten, dann teilen wir Ihnen gerne mit, dass wir neue Mitarbeiter suchen!