Three frameworks, one workspace. Angular orchestrates. React draws. Svelte diagrams. Native Federation makes it work — without rewriting any of them.
A deliberately small demo of a real enterprise frontend integration pattern: one host application, multiple inherited capabilities from foreign frameworks, one shared business context.
Call it Frankenstein-Driven Architecture.
Remote owns capability. Host owns business context and persistence.
This is not a meeting app. It is not production software. It demonstrates an integration architecture for heterogeneous frontend stacks — the kind of stack you find inside any enterprise after two acquisitions and a framework war.
Spec complete, implementation in progress. This repository currently contains the architecture spec and milestone plan. Runnable code lands milestone by milestone — see Milestones below.
specs/SPEC.mdAngular Host (Frankenstein Meeting Room)
├── Calendar (Schedule-X, native, NOT federated)
├── Event Detail View
│ ├── Whiteboard Slot ← React Remote (Excalidraw, Native Federation)
│ └── Mermaid Editor Slot ← Svelte Remote (Mermaid, Native Federation)
├── Event Bus (host ↔ remotes, framework-agnostic EventTarget)
└── LocalStorage (per meeting)
Each remote is a complete app in its own framework, exposed as a Custom Element. Host and remotes communicate exclusively through a typed event bus — no shared component model, no shared reactivity, no leaky framework abstractions. The host is the single broadcast point for business context.
| Layer | Choice |
|---|---|
| Host framework | Angular 20+ |
| Calendar | Schedule-X (@schedule-x/angular) |
| Whiteboard | Excalidraw (React 18+) |
| Diagram editor | Mermaid + Svelte 5 wrapper |
| Federation runtime | Native Federation v4 + Orchestrator |
| Host build | @angular-architects/native-federation-v4 |
| Remote build | @softarc/native-federation-esbuild |
| Persistence | LocalStorage |
| Workspace | pnpm |
devDependenciesSchedule-X and its transitive runtime (preact, @preact/signals,
temporal-polyfill) are pinned in the shell's devDependencies, not
dependencies. Same goes for @frankenstein/shared. The reason is
Native Federation's share map: shareAll iterates dependencies only,
so anything listed there gets emitted as a separately-loaded shared
chunk and added to the import map for remotes to consume.
For host-only code that no remote will ever import — the calendar, the
internal bus types — sharing buys nothing and costs real correctness.
The Schedule-X Preact tree in particular breaks the moment the runtime
sees two Preact module instances (federated copy + a deep-import path
that slips past the import map), with the canonical __H undefined
crash. Keeping these out of dependencies sidesteps the whole class
of single-instance / version-skew problems and lets vite bundle one
copy inline.
Rule of thumb: if a remote will never import it, it's a
devDependency of the shell.
frankenstein-meeting-room/
├── pnpm-workspace.yaml
├── specs/
│ └── SPEC.md ← full architectural spec
└── packages/
├── shared/ ← bus.ts, types.ts, seed.ts
├── shell/ ← Angular host
├── whiteboard/ ← React remote (Excalidraw)
└── mermaid/ ← Svelte remote (Mermaid)
pnpm install
Run the host and both remotes in three separate terminals:
# terminal 1 — Angular host
pnpm --filter shell start # http://localhost:4200
# terminal 2 — React whiteboard remote
pnpm --filter whiteboard start # http://localhost:3000
# terminal 3 — Svelte mermaid remote
pnpm --filter mermaid start # http://localhost:4000
Each remote is also runnable standalone — open the localhost URL of a remote directly to see it render against a built-in mock host, no shell required. This is how the remotes get developed and debugged in isolation.
Each milestone produces a usable artifact. See specs/SPEC.md for done-criteria per milestone.
Heterogeneity in enterprise frontends is permanent. Acquisitions bring new stacks, teams pick what they know, framework tides shift. The rewrite-first approach treats this as a problem to be eliminated; this repo treats it as a constraint to design with.
This pattern is for:
Old code keeps shipping. New capabilities arrive as islands. No all-or-nothing rewrite gate.
This is a demo of an integration architecture, not a production application. Deliberately out of scope:
If your reaction is "but a real production system would need X": yes, exactly. The architecture is what's being demonstrated, not a production-ready meeting app.
specs/SPEC.md for the technical depth.MIT.