eQuantic.UIeQuantic.UI
Docs
Playground
GitHub
DocsRuntime
Runtime (TypeScript)
Edit this page
5 min read
Die Runtime von eQuantic.UI ist die Bibliothek, die die Anwendung im Browser zum Leben bringt. Sie hat die Aufgabe, den virtuellen Baum, den der kompilierte Code erzeugt, in echte DOM-Elemente zu verwandeln und auf Zustandsänderungen zu reagieren.
📦 Verteilung der Runtime
Die Runtime wird als eine einzige gebündelte Datei verteilt (runtime.js; ihre Größe wird hier nicht genannt, denn ihre gzip-Größe ist ein Budget, das ServedRuntimeBudgetTests erzwingt, siehe Build-Ablauf), die Folgendes enthält:
•
Die Kern-Runtime: der Reconciler des virtuellen DOM, der Lebenszyklus der Komponenten
•
Zustandsverwaltung: das reaktive Zustandssystem
•
Event-System: die Event-Verfolgung auf WeakMap-Basis
•
Die Server-Actions-Brücke: die RPC-Kommunikation zwischen Client und Server
•
Entwicklungswerkzeuge: Logger und Fehler-Overlay (nur in der Entwicklung)
•
Der Dienstanbieter: der Container für Dependency Injection
Paketierung und Auslieferung
Die Runtime reist in dem Paket, das sie ausliefert, eQuantic.UI.Server: Der Server bettet das Bundle ein und antwortet /_equantic/runtime.js damit, und trägt dieselben Bytes als Datei unter tools/runtime/runtime.js. Das SDK kopiert diese Datei während des Builds in das wwwroot/_equantic/ der Anwendung (das MSBuild-Target CopyEQuanticRuntime), für die Werkzeuge, die die Module einer Anwendung außerhalb eines Servers laden, etwa die Vorschau in VS Code; einer laufenden Anwendung wird immer mit dem eingebetteten Bundle geantwortet.
Build-Ablauf:
1
2
3
4
5
6
7
8
9
TypeScript-Quelle (src/eQuantic.UI.Runtime/src) + boot.ts (src/eQuantic.UI.Sdk/Resources)
↓ Target BundleRuntime von eQuantic.UI.Server (eingebettetes bun), vor jedem Build
src/eQuantic.UI.Server/wwwroot/runtime.js (EIN Bundle, und sein einziger Schreiber)
├─ eingebettet in eQuantic.UI.Server.dll → ausgeliefert auf /_equantic/runtime.js
↓ Target CollectServedRuntime, beim Packen
eQuantic.UI.Server.nupkg/tools/runtime/runtime.js
↓ das SDK löst es über $(PkgeQuantic_UI_Server) auf
↓ MSBuild-Target CopyEQuanticRuntime
wwwroot/_equantic/runtime.js des Konsumenten (dieselben Bytes)
Vorteile der Architektur:
•
✅ Ein Schreiber: Das Bundle wird einmal geschrieben, von dem Paket, das es ausliefert; das SDK referenziert es nur
•
✅ Die Kopie IST die ausgelieferte Runtime: Was eine Anwendung in wwwroot/_equantic/runtime.js findet, ist Byte für Byte, was /_equantic/runtime.js antwortet
•
✅ Keine Duplikation: eine einzige Quelle der Wahrheit für runtime.js
•
✅ Null Abhängigkeiten: Wer sie konsumiert, bekommt die Runtime automatisch, ohne Node.js und ohne npm
🔄 Der Reconciler
Anders als Frameworks, die das ganze DOM neu erzeugen, vergleicht der Reconciler von eQuantic.UI die aktuelle Seite mit der gewünschten neuen Fassung und wendet nur die minimal nötigen Änderungen an.
Diffing-Algorithmus:
1.
Typvergleich: Hat ein Knoten sein Tag gewechselt (etwa von div zu span), wird er vollständig ersetzt.
2.
Attribut-Aktualisierung: Nur geänderte Attribute werden im DOM geändert.
3.
Verwaltung der Kinder: Der Reconciler geht die Liste der Kinder rekursiv ab.
🗝️ Identität per Key
Der Reconciler unterstützt Keyed Diffing über die Eigenschaft key.
•
Haben zwei Knoten an unterschiedlichen Positionen denselben Key, versteht das Framework, dass das Element bewegt wurde, und bewahrt den internen Zustand des Browsers (etwa die Cursorposition in einem Eingabefeld oder den Scrollzustand).
🧠 Verwaltung von Events und Speicher
Um Speicherlecks zu verhindern, nutzt die Runtime ein System zur Event-Verfolgung auf Basis von WeakMap.
Vorteile von WeakMap:
•
Event-Listener werden direkt dem HTMLElement zugeordnet.
•
Wird ein Element aus dem DOM entfernt und gibt es keine Referenzen mehr darauf, kann der Garbage Collector des Browsers die Metadaten des Events automatisch aufräumen, was dafür sorgt, dass der Speicherverbrauch der Anwendung auch in langen Sitzungen stabil bleibt.
🎯 Zwei Event-Kontrakte, die man kennen sollte
Seit 0.2.0-preview.24
Der Spiegel von HtmlElement senkt on*-Eigenschaften zu DOM-Event-Namen ab, mit der eigenen Schreibweise des DOM dort, wo Kleinschreibung allein falsch ist: OnDoubleClick registriert dblclick (die eine Abweichung der EventNameMap in C#: Ein doubleclick-Listener hängt sich bestens an und feuert nie). Und OnSubmit zu setzen übernimmt den BESITZ des Absendens: Die Runtime ruft preventDefault() auf, bevor sie aufruft, das wegnavigierende Absenden des Browsers läuft also nie, und der Handler validiert und ruft stattdessen eine Server Action auf. Ein Formular, das das native Absenden will, setzt einfach keinen Handler. click behält die Browser-Voreinstellungen, die es immer hatte: Ein Klick auf ein Label muss weiterhin seine Checkbox umschalten.
🔒 Verwaltung des modalen Fokus
Seit 0.2.0-preview.24
Modale Overlay-Ebenen kommen von beiden Erzeugern mit role="dialog", aria-modal, tabindex="-1" und einem data-eq-trap-Marker. Der Controller des Clients gleicht die Fallen genau in dem Moment gegen das DOM ab, in dem sich der Shortcut-Satz nach jedem Reconciler-Durchgang festschreibt: Eine Ebene, die auftauchte, notiert, wer sie aufgerufen hat, und nimmt nach dem nächsten Frame den Fokus (eine Ebene, die aus visibility:hidden einblendet, ist nicht fokussierbar, bis der Style landet); Tab und Umschalt+Tab kreisen darin, und eine focusin-Wache holt zurück, was entkommt; eine Ebene, die nicht mehr markiert ist (entfernt, montiert geschlossen, oder für ihre Ausgangsanimation umgehängt) gibt den Fokus an den Aufrufer zurück. Die Entdeckung über den Marker statt über den Pfad ist, was die beiden Erzeuger byte-identisch hält.
💧 Hydration (SSR)
Die Runtime unterstützt den Vorgang der "Hydration", bei dem sie die Kontrolle über HTML übernimmt, das der Server schon gerendert hat (SSR). Statt zu zerstören und neu zu erzeugen, hängt die Runtime nur die nötigen Event-Listener an die bestehenden Elemente, was ein augenblickliches erstes Laden sichert.
🔧 Entwicklungsmodus
Die Runtime erkennt die Umgebung über das Flag window.__EQ_DEV__ (vom Server anhand von IWebHostEnvironment.IsDevelopment() gesetzt).
Funktionen nur für die Entwicklung
Logger-System (utils/logger.ts)
Ein professionelles Logging-System, das nur im Entwicklungsmodus ausgibt:
1
2
3
4
5
6
import { logger } from './utils/logger';
logger.debug('Boot process started'); // Nur in der Entwicklung
logger.info('Component rendered'); // Nur in der Entwicklung
logger.warn('Deprecated API used'); // Loggt immer
logger.error('Failed to load data'); // Loggt immer
Allen Logs wird [eQuantic.UI] vorangestellt, damit sie leicht zu filtern sind.
Fehler-Overlay (dev/error-overlay.ts)
Ein Fehler-Overlay im Stil von Next.js, das Laufzeitfehler in einer bildschirmfüllenden Oberfläche zeigt (nur in der Entwicklung):
•
Automatisches Einfangen: unbehandelte Fehler und abgelehnte Promises
•
Stack Traces: der vollständige Fehlerkontext mit Quellinformation
•
Tastaturunterstützung: Esc drücken zum Schließen
•
Saubere UX: ähnlich dem Fehler-Overlay von Next.js
Das Fehler-Overlay wird automatisch importiert und aktiviert, wenn window.__EQ_DEV__ === true.
Produktionsmodus
In Produktionsbuilds:
•
logger.debug() und logger.info() werden stillgelegt
•
Das Fehler-Overlay wird nie geladen
•
Nur logger.warn() und logger.error() geben auf die Konsole aus
•
Minimaler Runtime-Mehraufwand: ein Bundle, dessen gzip-Größe ein Budget ist, das die Suite erzwingt, statt einer hier genannten Zahl
🎨 Die Theme-Brücke
Das Theme der Anwendung ist typisiertes C# auf dem Server (IAppTheme, über UseTheme gewählt, siehe DesignSystem). Der Server serialisiert das gewählte Theme neben die Boot-Konfiguration in window.__EQ_THEME__, und die Theme-Brücke der Runtime (shared/theme-bridge.ts) übernimmt es beim Boot, sodass die Pixel des SSR und das Lowering des Clients dieselben Tokens auflösen, und ein Hell-/Dunkel-Umschalten zur Laufzeit eine einzige color-scheme-Deklaration umlegt.