惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
爱范儿
爱范儿
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 叶小钗
Last Week in AI
Last Week in AI
博客园 - 三生石上(FineUI控件)
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - Franky
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 司徒正美
罗磊的独立博客
博客园 - 聂微东
T
Troy Hunt's Blog
美团技术团队
IT之家
IT之家
A
Arctic Wolf
腾讯CDC
雷峰网
雷峰网
SecWiki News
SecWiki News
博客园_首页
L
LINUX DO - 最新话题
Cloudbric
Cloudbric
量子位
N
News and Events Feed by Topic
小众软件
小众软件
C
CXSECURITY Database RSS Feed - CXSecurity.com
Cyberwarzone
Cyberwarzone
J
Java Code Geeks
V
V2EX
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Latest news
Latest news
Webroot Blog
Webroot Blog
F
Fortinet All Blogs
P
Privacy International News Feed
NISL@THU
NISL@THU
Google Online Security Blog
Google Online Security Blog
WordPress大学
WordPress大学
PCI Perspectives
PCI Perspectives
GbyAI
GbyAI
宝玉的分享
宝玉的分享
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts
Simon Willison's Weblog
Simon Willison's Weblog
P
Palo Alto Networks Blog
V
Visual Studio Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Frankenstein Meeting Room: Drei Apps in einem Browser-Tab
Lutz Leonhar · 2026-05-13 · via DEV Community

1. Einstieg - Warum Frankenstein?

Die 2010er Jahre waren der große Frontendkrieg. Viele neue UI-Frameworks entstanden in dieser Zeit und verschwanden wieder. Das sieht man heutigen Enterprises an ihren Legacy-Anwendungen an. Viele haben Angular, React, Vue oder Svelte für verschiedene Use Cases im Einsatz. Wenn man diese Anwendungen nicht als Inseln, sondern in ihrer Gesamtheit nutzen möchte, bleibt normalerweise nur die Möglichkeit, auf ein gemeinsames Framework zu migrieren. Ein langfristiger und fehleranfälliger Prozess. Eine bessere Möglichkeit kann es sein, die Apps über eine gemeinsame Orchestrator-Plattform miteinander kommunizieren zu lassen. Das ist die Ausgangslage für unseren Frankenstein Meeting Room auf Basis von Native Federation.

2. Was die App macht

Der Aufbau soll zeigen, wie man eine heterogene Web-App-Landschaft (Angular, React, Svelte) über Native Federation integrieren kann. Das Projekt simuliert im Kleinen eine Legacy-Enterprise-Landschaft. Konkret: In einem Angular-Kalender (Shell) können Meetings ausgewählt werden. Die verknüpften Informationen werden in einem Svelte-Mermaid-Diagramm (Remote 1) sowie einem React-Excalidraw-Whiteboard (Remote 2) dargestellt. Beim Wechsel des Meetings werden die Daten gespeichert und geladen (LocalStorage).

Die Demo läuft unter lutzleonhardt.de/frankenstein-meeting-room, der Code liegt auf GitHub.

3. Ausgangslage und Workflow

Im vorherigen Artikel habe ich bereits die Spezifikation der Umsetzung und das UI-Mockup (Claude Design) vorgestellt.

Das ursprüngliche UI-Mockup aus Teil 1, generiert mit Claude Design. Der Lab-Notebook-Look hat es bis in die fertige App geschafft.

Zur Umsetzung habe ich mein Skill-Kit für agentische Workflows zusammen mit den Code-Agenten Claude Code und Codex im Tandem genutzt. Die Agenten haben die Spezifikation in einzelne Meilensteinpläne überführt. Jeder Meilensteinplan wurde in Tasks zerlegt. Der Vorteil dieses Vorgehens: jeder Meilenstein bringt ein prüfbares Artefakt hervor, das der Entwickler isoliert validieren und reviewen kann. Das Ergebnis dient dann als Basis für den nächsten Schritt. Pro Task entsteht dabei nicht nur der Code, sondern auch ein Task-Log: was probiert wurde, was verworfen wurde, welche Hypothesen unterwegs starben. Diese Negativ-Information geht in normalen Commit-Bodies fast immer verloren — beim Schreiben dieses Posts musste ich genau dort am häufigsten nachlesen.

Ein kleines Problem dabei: der NF-Builder gibt nach Abschluss seiner Arbeit den Prozess nicht frei. Am eigenen Terminal merkt man es nicht. Man drückt Ctrl-C und macht weiter. Im agentischen Workflow wird das zum Problem: der Agent weiß nicht, dass die Arbeit fertig ist, und wartet weiter. Der Ausweg war ein kleines Wrapper-Script: Artefakt vorher löschen, ng build starten, auf Artefakt pollen, dann der gesamten Prozessgruppe SIGKILL schicken.

4. Native Federation: Shell, Remotes, Bus

Im Zentrum von Native Federation steht die Shell (auch Host genannt), welche die anderen Web-Apps oder exportierten UI-Komponenten als Remotes von entfernten Endpunkten lädt. In unserem Fall sind die Remotes eigenständige Web-Apps (Svelte, React), welche je ein Custom Element für die Shell exportieren.

Da für die Kommunikation zwischen den heterogenen Frameworks kein internes Binding genutzt werden kann, muss ein agnostisches Nachrichten-Pattern etabliert werden. Im Fall von Frankenstein Meeting Room habe ich mich für einen simplen, selbst implementierten Pub-Sub-Bus entschieden. Die Topologie ist sternförmig: die Remotes können nicht untereinander kommunizieren.

Die Bus-Implementierung liegt im Shared-Bereich des Monorepos, Shell und Remotes importieren die Funktionalität jeweils selbst. Der eigentliche Bus wird als Singleton an globalThis (window) gehängt. Die BusEvents wurden als DeepReadonly<T> typisiert, um eine versehentliche Mutation über die Framework-Grenze zur Kompilierzeit zu verhindern. Ein Deep-Clone wäre zu kostspielig: die gesamte Excalidraw-Datenstruktur hätte geklont werden müssen.

// packages/shared/src/bus.ts
type BusEvents = {
  'context:request': {};
  'event:selected':  { meetingId: string; initialData: Meeting };
  'drawing:changed': { meetingId: string; excalidrawData: ExcalidrawDemoData };
  'diagram:changed': { meetingId: string; mermaidSource: string };
};

const bus = (globalThis.frankensteinBus ??= new EventTarget()) as EventTarget;

export function emit<K extends keyof BusEvents>(
  name: K, payload: DeepReadonly<BusEvents[K]>,
) {
  bus.dispatchEvent(new CustomEvent(name, { detail: payload }));
}

Enter fullscreen mode Exit fullscreen mode

Sternförmige Topologie: alle Bus-Kommunikation läuft durchs Zentrum, Persistenz liegt beim Host. Live gerendert im Svelte-Mermaid-Editor der Demo selbst.

5. M1 — Monorepo, Shared-Package, Shell-Skeleton

Im ersten Meilenstein habe ich das pnpm-Monorepo aufgesetzt und im Shared-Package die Typen sowie den Bus implementiert. Über ein Native-Federation-Schematic wird das Angular-Projekt anschließend in eine Native-Federation-Shell überführt. Im Kern bekommt das Projekt dabei einen angepassten Build, einen leicht abgewandelten Bootstrap-Prozess und eine Federation-Konfiguration. Der Bootstrap läuft zweistufig: die Shell lädt zuerst das Federation-Manifest, injiziert die Import-Map und startet erst dann die eigentliche Angular-App. Die Konfiguration legt fest, welche Abhängigkeiten zwischen Shell und Remotes geteilt werden.

Das ist ein weiterer Vorteil von Native Federation: je nach Konfiguration werden Libraries nur einmal geladen, auch wenn mehrere Remotes und die Shell sie nutzen.

6. M2 — Host komplett: Kalender, Meeting-Service, Panels

Im Meilenstein 2 habe ich die Shell komplettiert, indem ich den Kalender (Schedule-X) hinzugefügt habe. Außerdem gibt es einen Meeting-Service, der auf Basis von Signals die aktuellen Meetings managt, über den Event-Bus Nachrichten empfängt und Daten sendet, zum Beispiel um die Remotes mit dem aktiven Meeting zu initialisieren. Initial werden die Meetings durch ein Seed befüllt. Bei Änderungen werden sie im LocalStorage gespeichert und beim Start wieder von dort geladen. In der Shell gibt es noch zwei weitere Angular-Komponenten: die Detailanzeige für das aktive Meeting sowie eine Übersicht der Bus-Nachrichten. Das Layout ist dreispaltig: Kalender links, Remotes in der Mitte, Detailanzeige und Bus-Log rechts.

Ein kleines Detail im Meeting-Service: die Remotes debouncen ihre Updates (500 ms), und ohne Guard würde ein Meeting-Wechsel mitten im Debounce dazu führen, dass der alte Draft das neue Meeting überschreibt. Der Fix: jede applyDrawingChange/applyDiagramChange im Service prüft die meetingId gegen currentMeeting und droppt stale Updates. Eine Zeile Code, ohne die der Bus eine subtile Daten-Korruption hätte.

private applyDrawingChange(p: DrawingChangedPayload): void {
  if (p.meetingId !== this.currentMeeting()?.id) return;  // stale-update guard
  // ... persist
}

Enter fullscreen mode Exit fullscreen mode

Im mittleren Bereich der Shell müssen jetzt noch die React- und Svelte-Anwendungen integriert werden.

7. M3 & M4 — Whiteboard und Mermaid als Remotes

Im Meilenstein 3 und 4 habe ich das React-Whiteboard (Excalidraw) und das Svelte-Mermaid-Diagramm jeweils als Remote implementiert. Bei beiden bin ich gleich vorgegangen: zuerst die Standalone-App, dann die Federation-Konfiguration darauf gesetzt. So konnte ich Excalidraw beziehungsweise das Mermaid-Diagramm in Isolation entwickeln und testen, bevor das Remote in die Shell eingebunden wurde. Dasselbe UI Projekt (react, svelte) läuft weiterhin unter eigenem Port als eigenständige App und kann zugleich vom Host als Remote geladen werden — fürs Federation-Loading reichen aber die gebauten JavaScript-Chunks plus remoteEntry.json als statische Assets, ein laufender Dev-Server ist nicht nötig (nur für den Standalone Test).
Konzeptionell war der wichtigste Build-Mode-Entscheid: @frankenstein/shared bleibt devDependency, damit shareAll das Package übergeht und der globalThis-Singleton aus Abschnitt 4 intakt bleibt.

Die erste Komplikation im Whiteboard: Excalidraws onChange feuert auch ohne echte Änderungen. Beim Resizen des Fensters bekam ich ~8 drawing:changed-Events in 11 Sekunden, ohne dass jemand etwas gezeichnet hatte. Den 500-ms-Debounce am Sender hatte ich schon eingebaut — der fasst die Events aber nur zusammen, er erkennt nicht, ob sich überhaupt etwas geändert hat. Der eigentliche Fix war ein Fingerprint über ${element.id}:${element.version}: Excalidraw bumpt version nur bei echten Änderungen, nicht bei kosmetischen Reflows. Damit fallen die leeren Events vor dem Debounce raus, und der kümmert sich danach nur noch um die Frequenz echter Edits.

const fp = elements.map(e => `${e.id}:${e.version ?? 0}`).join('|');
if (fp === prevFingerprintRef.current) return;  // skip cosmetic re-renders
prevFingerprintRef.current = fp;
// → 500ms debounce → emit('drawing:changed', …)

Enter fullscreen mode Exit fullscreen mode

Dazu noch ein Firefox-Detail: Firefox kappt <canvas> bei ~11180 px Kantenlänge. Da Excalidraws Stylesheet erst nach dem React-Mount geladen wurde, war der Container kurz groß; Excalidraw rechnete eine Canvas-Größe jenseits des Limits aus, und der erste setTransform-Call warf eine Exception mit Stacktrace in der Konsole — Excalidraw bootete gar nicht erst. Chromium hat das Limit nicht: klassischer „funktioniert bei mir"-Bug. Gelöst, indem das Stylesheet schon beim Modul-Init in den Head injiziert wird und der erste Render auf dessen load-Event wartet.

Die Federation-Konfiguration ist bei beiden Remotes gleich aufgebaut: eine federation.config.mjs, in der spezifiziert ist, was das Remote exportiert und welche Bibliotheken geteilt werden. Geteilte Bibliotheken werden in der Regel als Singleton geladen — genau eine Instanz für Shell und alle Remotes, auch wenn jedes Projekt sie selbst als Dependency mitbringt. Versionskonflikte werden zur Build-Zeit aufgelöst, transitive Sub-Dependencies explizit geteilt oder ausgeschlossen. Damit bestimmt die Federation-Konfiguration am Ende auch, wie viele JavaScript-Chunks pro Anwendung entstehen.

Im Whiteboard musste ich einmal nachhelfen: React liefert einige Module noch als CommonJS, die Native Federation beim Build in ESM überführt. Bei einem bestimmten Muster — react/jsx-runtime — klappt diese Übersetzung nicht sauber: die jsx-Funktion war zur Laufzeit undefined und Excalidraw flog beim ersten Render. Behebbar per Pfad-Mapping in der Federation-Konfiguration, das den problematischen Zwischenschritt überspringt und direkt auf Reacts fertig kompilierte CJS-Datei zeigt.

Im Mermaid-Remote war es umgekehrt: Svelte ließ sich gar nicht sauber teilen. Sein interner Code referenziert sich über relative Pfade, an die der Federation-Mechanismus nicht herankommt — am Ende landeten zwei Svelte-Runtimes parallel im Tab, und Mermaid warf zur Laufzeit effect_orphan. Pragmatisch gelöst: Svelte aus der Share-Map raus und direkt ins Mermaid-Bundle gebündelt. Bei nur einer Svelte-App ist das größenmäßig egal — die ~160 kB landen so oder so beim Client, ob als geteilter Chunk neben dem Bundle oder als Bestandteil davon. Erst ab zwei Svelte-Remotes käme die Duplikation zum Tragen.

8. Inseln statt Komponenten

In einer homogenen Landschaft — also wenn alle Apps dasselbe UI-Framework nutzen — würde man Komponenten direkt exportieren und in der Shell verwenden. In einer heterogenen Landschaft funktioniert das nicht: würde ich aus dem React-Projekt nur die React-Komponente exportieren, könnte die Angular-Shell sie nicht laden, weil die React-Runtime im Tab schlicht fehlt. Eine reine Komponente hat keine Plattform unter sich.

Die Lösung sind Inseln: jedes Remote exportiert nicht nur die Komponente, sondern die komplette App inklusive ihres Frameworks. Im Tab läuft dann pro Insel ein eigenes UI-Framework, vollständig gekapselt. Technisch passiert das über native Custom Elements: das Remote definiert ein <whiteboard-remote> (bzw. <mermaid-remote>), die Shell rendert das Tag wie jedes andere DOM-Element, und im connectedCallback bootet das eingebettete Framework. Genau so sind Whiteboard und Mermaid in Meilenstein 3 und 4 umgesetzt.

class WhiteboardRemote extends HTMLElement {
  connectedCallback() {
    this.root = createRoot(this);
    this.unsubs.push(on('event:selected', ({ initialData }) => {
      this.render(initialData);
    }));
    emit('context:request', {});
  }

  disconnectedCallback() {
    this.unsubs.forEach(u => u());
    this.root?.unmount();
  }
}

customElements.define('whiteboard-remote', WhiteboardRemote);

Enter fullscreen mode Exit fullscreen mode

React DevTools sehen den vollständigen Komponentenbaum (links). Wappalyzer findet kein React (rechts). Die Insel funktioniert.

9. Bus-Zugriff und Events

Shell und Remotes importieren den Bus jeweils direkt aus dem Shared-Package (siehe Abschnitt 4). Konkret läuft das so: nach seiner Initialisierung schickt jedes Remote ein context:request über den Bus und bekommt vom Host ein event:selected mit dem aktuellen Meeting zurück. Erst damit weiß das Remote, welche Whiteboard- oder Mermaid-Daten es laden soll.

Es gibt vier Events:

  • context:request — Remote → Host: „bitte aktuelles Meeting schicken"
  • event:selected — Host → Remotes: aktuelles Meeting mit Whiteboard- und Mermaid-Daten
  • drawing:changed — React-Remote → Host: das Whiteboard wurde geändert
  • diagram:changed — Svelte-Remote → Host: das Mermaid-Diagramm wurde geändert

Der Event-Bus-Log live: context:request beim Mount eines Remotes, event:selected als Host-Antwort, dann drawing:changed für eine echte Whiteboard-Änderung.

Bewusst nicht im Setup: das Anlegen oder Editieren von Meetings über den Bus. Das hätte CRUD-Wiring durch alle drei Frameworks gezogen, ohne am Integrationspattern selbst etwas hinzuzufügen. Was mit Native Federation möglich ist, lässt sich auch mit diesem minimalen Event-Set übersichtlich zeigen.

10. M5 & M6 — Polish und Deployment

In den letzten beiden Meilensteinen ging es um Polish und Deployment. M5 war Feinschliff: das CSS verbessert, Cleanups gemacht, einen repräsentativen Seed angelegt. Der Seed hat eine kleine Pointe: statt Lorem-Ipsum-Meetings ist das Demo-Meeting ein „Architecture Review" der Demo selbst. Das Whiteboard zeichnet drei Boxen plus Bus, Mermaid zeigt das Sequenzdiagramm des Bus-Flows. Das Hero-Bild des Posts ergibt sich daraus von allein.

M6 war das Deployment auf https://lutzleonhardt.de/frankenstein-meeting-room/ — alles statisch unter einem Subpath, kein Backend, plus die beiden Remotes separat unter /whiteboard/ und /mermaid/ als eigenständige Apps. Während der Entwicklung lief jedes Remote über seinen eigenen Standalone-Dev-Server, das Federation-Manifest verwies entsprechend auf localhost-URLs. Nach dem Build wandern die Remotes als statische Assets in die Unterpfade des Hosts, und das Manifest wird passend dazu angepasst.

11. Take-away

Das ganze Setup stand in 10 bis 12 Stunden Nettoaufwand, mit Hilfe des agentischen Prozesses und konsequenter Kuratierung. Erweitern lässt es sich leicht: weitere React-Anwendungen lassen sich genauso einbinden wie ein zusätzliches Framework, zum Beispiel Vue. Damit eignet sich Native Federation gut, um eine gewachsene heterogene Legacy-Landschaft auf einer Plattform zusammenzuführen, ohne eine große Migration durchziehen zu müssen.

Besondere Fallstricke gibt es vor allem dann, wenn mehrere Versionen desselben Frameworks parallel laufen — etwa Angular 15 und Angular 17 in derselben Plattform. Dann muss man genau auf geteilte Dependencies, Sub-Dependencies und transitive Dependencies achten. Das Laden der Abhängigkeiten läuft aber zentral über die native Import-Map, was es überschaubar hält. Im Gegensatz zu Webpack Module Federation, wo die Remote-Map tief im Code vergraben war.

Fazit: die Reibung zwischen drei Frameworks in einem Tab befindet sich nicht da, wo man sie erwarten würde. Bus und Loading liefen problemlos. Komplikationen gab es beim Firefox-CSS, dem React-CJS-Wrapper und einem Svelte-Compiler, der zweimal in derselben Seite lief. Der Code liegt unter github.com/lutzleonhardt/FrankensteinMeetingRoom.


Lutz Leonhardt ist Mitglied im Native Federation Advisory Board. Mehr unter lutzleonhardt.de.