Skip to content

Runtime fr

Edgar Mesquita edited this page Oct 13, 2026 · 1 revision

Runtime (TypeScript)

🌐 Cette page en : English · Português · Español · Français · Deutsch

Le Runtime d'eQuantic.UI est la bibliothèque qui donne vie à l'application dans le navigateur. Il a la charge de transformer l'arbre virtuel que génère le code compilé en vrais éléments du DOM et de réagir aux changements d'état.

📦 Distribution du runtime

Le runtime est distribué comme un unique fichier empaqueté (runtime.js ; sa taille n'est pas citée ici, parce que sa taille gzip est un budget que ServedRuntimeBudgetTests fait respecter, voir Flux de build) qui comprend :

  • Le runtime central : le réconciliateur de DOM virtuel, le cycle de vie des composants
  • La gestion d'état : le système d'état réactif
  • Le système d'événements : le suivi d'événements fondé sur WeakMap
  • Le pont des Server Actions : la communication RPC entre client et serveur
  • Les outils de développement : logger et overlay d'erreurs (développement seulement)
  • Le fournisseur de services : le conteneur d'injection de dépendances

Empaquetage et déploiement

Le runtime voyage dans le paquet qui le sert, eQuantic.UI.Server : le Server embarque le bundle et répond /_equantic/runtime.js avec lui, et porte les mêmes octets sous forme de fichier à tools/runtime/runtime.js. Le SDK copie ce fichier dans le wwwroot/_equantic/ de l'application pendant le build (la cible MSBuild CopyEQuanticRuntime) pour les outils qui chargent les modules d'une application hors d'un serveur, comme l'aperçu de VS Code ; à une application en marche on répond toujours avec le bundle embarqué.

Flux de build :

Source TypeScript (src/eQuantic.UI.Runtime/src) + boot.ts (src/eQuantic.UI.Sdk/Resources)
    ↓ cible BundleRuntime d'eQuantic.UI.Server (bun embarqué), avant chaque build
src/eQuantic.UI.Server/wwwroot/runtime.js (UN bundle, et son unique écrivain)
    ├─ embarqué dans eQuantic.UI.Server.dll → servi sur /_equantic/runtime.js
    ↓ cible CollectServedRuntime, au moment du pack
eQuantic.UI.Server.nupkg/tools/runtime/runtime.js
    ↓ le SDK le résout via $(PkgeQuantic_UI_Server)
    ↓ cible MSBuild CopyEQuanticRuntime
wwwroot/_equantic/runtime.js du consommateur (les mêmes octets)

Bénéfices de l'architecture :

  • ✅ Un seul écrivain : le bundle est écrit une fois, par le paquet qui le sert ; le SDK ne fait que le référencer
  • ✅ La copie EST le runtime servi : ce qu'une application trouve dans wwwroot/_equantic/runtime.js est octet pour octet ce que répond /_equantic/runtime.js
  • ✅ Aucune duplication : une seule source de vérité pour runtime.js
  • ✅ Zéro dépendance : qui le consomme reçoit le runtime automatiquement, sans Node.js ni npm

🔄 Le réconciliateur

À la différence des frameworks qui recréent tout le DOM, le Reconciler d'eQuantic.UI compare la page actuelle avec la nouvelle version voulue et n'applique que les changements minimaux nécessaires.

Algorithme de diffing :

  1. Comparaison de type : si un nœud a changé de balise (par exemple de div à span), il est remplacé entièrement.
  2. Mise à jour des attributs : seuls les attributs modifiés sont changés dans le DOM.
  3. Gestion des enfants : le réconciliateur parcourt récursivement la liste des enfants.

🗝️ Identité par clé

Le réconciliateur prend en charge le Keyed Diffing par la propriété key.

  • Si deux nœuds à des positions différentes ont la même clé, le framework comprend que l'élément a été déplacé, et préserve l'état interne du navigateur (comme la position du curseur dans un champ ou l'état du défilement).

🧠 Gestion des événements et de la mémoire

Pour prévenir les fuites de mémoire, le runtime utilise un système de suivi d'événements fondé sur WeakMap.

Avantages de WeakMap :

  • Les listeners d'événements sont mappés directement sur l'HTMLElement.
  • Quand un élément est retiré du DOM et qu'il n'y a plus de références vers lui, le ramasse-miettes du navigateur peut nettoyer automatiquement les métadonnées de l'événement, ce qui garantit que la consommation mémoire de l'application reste stable même sur de longues sessions.

🎯 Deux contrats d'événements à connaître

Depuis 0.2.0-preview.24

Le miroir d'HtmlElement abaisse les propriétés on* vers des noms d'événements du DOM, avec l'orthographe propre au DOM là où la seule mise en minuscules se trompe : OnDoubleClick enregistre dblclick (l'unique divergence de l'EventNameMap du C# : un listener doubleclick s'attache très bien et ne se déclenche jamais). Et poser OnSubmit prend la PROPRIÉTÉ de la soumission : le runtime appelle preventDefault() avant d'invoquer, donc la soumission avec navigation propre au navigateur ne tourne jamais, et le gestionnaire valide puis appelle une server action à la place. Un formulaire qui veut la soumission native ne pose simplement aucun gestionnaire. click garde les comportements par défaut du navigateur qu'il a toujours eus : un clic sur un libellé doit encore basculer sa case.

🔒 Gestion du focus modal

Depuis 0.2.0-preview.24

Les couches d'overlay modales arrivent des deux producteurs en portant role="dialog", aria-modal, tabindex="-1" et un marqueur data-eq-trap. Le contrôleur du client réconcilie les pièges contre le DOM au moment même où l'ensemble des Shortcuts se valide après chaque passe du réconciliateur : une couche qui est apparue enregistre qui l'a invoquée et prend le focus après la frame suivante (une couche qui s'estompe depuis visibility:hidden n'est pas focalisable avant que le style ne soit posé) ; Tab et Maj+Tab tournent à l'intérieur, et une garde focusin rattrape ce qui s'échappe ; une couche qui a cessé d'être marquée (retirée, fermée en restant montée, ou reparentée pour son animation de sortie) rend le focus à qui l'a invoquée. La découverte par marqueur plutôt que par chemin est ce qui garde les deux producteurs identiques octet pour octet.

💧 Hydratation (SSR)

Le runtime prend en charge le processus d'"hydratation", où il prend le contrôle du HTML que le serveur a déjà rendu (SSR). Au lieu de détruire et de recréer, le runtime n'attache que les listeners d'événements nécessaires aux éléments existants, ce qui garantit un chargement initial instantané.

🔧 Mode développement

Le runtime détecte l'environnement via le drapeau window.__EQ_DEV__ (posé par le serveur d'après IWebHostEnvironment.IsDevelopment()).

Fonctionnalités réservées au développement

Système de logger (utils/logger.ts)

Système de journalisation professionnel qui n'émet qu'en mode développement :

import { logger } from './utils/logger';

logger.debug('Boot process started');  // Développement seulement
logger.info('Component rendered');     // Développement seulement
logger.warn('Deprecated API used');    // Journalise toujours
logger.error('Failed to load data');   // Journalise toujours

Tous les logs sont préfixés de [eQuantic.UI] pour les filtrer facilement.

Overlay d'erreurs (dev/error-overlay.ts)

Overlay d'erreurs à la manière de Next.js qui affiche les erreurs de runtime dans une interface plein écran (développement seulement) :

  • Capture automatique : erreurs non gérées et rejets de promesses
  • Stack traces : le contexte complet de l'erreur avec l'information de source
  • Prise en charge du clavier : appuyez sur Esc pour fermer
  • UX propre : semblable à l'overlay d'erreurs de Next.js

L'overlay d'erreurs est importé et activé automatiquement quand window.__EQ_DEV__ === true.

Mode production

Dans les builds de production :

  • logger.debug() et logger.info() sont réduits au silence
  • L'overlay d'erreurs n'est jamais chargé
  • Seuls logger.warn() et logger.error() émettent dans la console
  • Surcoût de runtime minimal : un bundle, dont la taille gzip est un budget que la suite fait respecter plutôt qu'un nombre cité ici

🎨 Le pont du thème

Le thème de l'application est du C# typé sur le serveur (IAppTheme, choisi via UseTheme, voir DesignSystem). Le serveur sérialise le thème choisi dans window.__EQ_THEME__ à côté de la configuration de boot, et le pont de thème du runtime (shared/theme-bridge.ts) l'adopte au boot, si bien que les pixels du SSR et le lowering du client résolvent les mêmes tokens, et qu'une bascule clair/sombre à l'exécution retourne une seule déclaration color-scheme.

Clone this wiki locally