Runtime (TypeScript)El Runtime de eQuantic.UI es la biblioteca que da vida a la aplicación en el navegador. Es responsable de transformar el árbol virtual que genera el código compilado en elementos del DOM reales y de reaccionar a los cambios de estado.
📦 Distribución del runtime
El runtime se distribuye como un único archivo empaquetado (runtime.js; su tamaño no se cita aquí, porque su tamaño gzip es un presupuesto que ServedRuntimeBudgetTests hace cumplir, vea Flujo de build) que incluye: •
Runtime central: el reconciliador de DOM virtual, el ciclo de vida de los componentes
•
Gestión de estado: el sistema de estado reactivo
•
Sistema de eventos: el seguimiento de eventos basado en WeakMap
•
Puente de Server Actions: la comunicación RPC entre cliente y servidor
•
Herramientas de desarrollo: logger y overlay de errores (solo en desarrollo)
•
Proveedor de servicios: el contenedor de inyección de dependencias
El runtime viaja dentro del paquete que lo sirve, eQuantic.UI.Server: el Server incrusta el bundle y responde /_equantic/runtime.js con él, y lleva los mismos bytes como archivo en tools/runtime/runtime.js. El SDK copia ese archivo al wwwroot/_equantic/ de la aplicación durante el build (el target de MSBuild CopyEQuanticRuntime) para las herramientas que cargan los módulos de una aplicación fuera de un servidor, como la vista previa de VS Code; a una aplicación en marcha siempre se le responde con el bundle incrustado.
Flujo de build:
Fuente TypeScript (src/eQuantic.UI.Runtime/src) + boot.ts (src/eQuantic.UI.Sdk/Resources)
↓ target BundleRuntime de eQuantic.UI.Server (bun embebido), antes de cada build
src/eQuantic.UI.Server/wwwroot/runtime.js (UN bundle, y su único escritor)
├─ incrustado en eQuantic.UI.Server.dll → servido en /_equantic/runtime.js
↓ target CollectServedRuntime, al empaquetar
eQuantic.UI.Server.nupkg/tools/runtime/runtime.js
↓ el SDK lo resuelve vía $(PkgeQuantic_UI_Server)
↓ target de MSBuild CopyEQuanticRuntime
wwwroot/_equantic/runtime.js del consumidor (los mismos bytes)
Beneficios de la arquitectura:
•
✅ Un solo escritor: el bundle se escribe una vez, por el paquete que lo sirve; el SDK solo lo referencia
•
✅ La copia ES el runtime servido: lo que una aplicación encuentra en wwwroot/_equantic/runtime.js es byte por byte lo que responde /_equantic/runtime.js
•
✅ Sin duplicación: una única fuente de verdad para runtime.js
•
✅ Cero dependencias: quien lo consume recibe el runtime automáticamente, sin Node.js ni npm
A diferencia de los frameworks que recrean el DOM entero, el Reconciler de eQuantic.UI compara la página actual con la nueva versión deseada y aplica solo los cambios mínimos necesarios.
1.
Comparación de tipo: si un nodo cambió de etiqueta (por ejemplo, de div a span), se reemplaza por completo.
2.
Actualización de atributos: solo los atributos modificados se cambian en el DOM.
3.
Gestión de hijos: el reconciliador recorre recursivamente la lista de hijos.
El reconciliador soporta el Keyed Diffing a través de la propiedad key.
•
Si dos nodos en posiciones distintas tienen la misma clave, el framework entiende que el elemento se movió, y preserva el estado interno del navegador (como la posición del cursor en un campo o el estado del scroll).
🧠 Gestión de eventos y de memoria
Para prevenir fugas de memoria, el runtime usa un sistema de seguimiento de eventos basado en WeakMap.
•
Los listeners de eventos se mapean directamente al HTMLElement.
•
Cuando un elemento se retira del DOM y no quedan más referencias a él, el recolector de basura del navegador puede limpiar automáticamente los metadatos del evento, lo que asegura que el consumo de memoria de la aplicación se mantenga estable incluso en sesiones largas.
🎯 Dos contratos de eventos que vale conocer
Desde 0.2.0-preview.24
El espejo de HtmlElement baja las propiedades on* a nombres de eventos del DOM, con la grafía propia del DOM allí donde pasarlo a minúsculas no basta: OnDoubleClick registra dblclick (la única divergencia del EventNameMap de C#: un listener de doubleclick se engancha bien y no se dispara nunca). Y fijar OnSubmit toma la PROPIEDAD del envío: el runtime llama a preventDefault() antes de invocar, así que el envío con navegación propio del navegador nunca corre, y el manejador valida y llama a una server action en su lugar. Un formulario que quiere el envío nativo simplemente no fija ningún manejador. click conserva los valores por defecto del navegador que siempre tuvo: un clic en una etiqueta debe seguir alternando su casilla.
Desde 0.2.0-preview.24
Las capas de overlay modales llegan de los dos productores llevando role="dialog", aria-modal, tabindex="-1" y un marcador data-eq-trap. El controlador del cliente reconcilia las trampas contra el DOM en el mismo momento en que el conjunto de Shortcuts se confirma después de cada pasada del reconciliador: una capa que apareció registra a quien la invocó y toma el foco después del siguiente frame (una capa que se desvanece desde visibility:hidden no es enfocable hasta que el estilo aterriza); Tab y Shift+Tab circulan dentro, y una guarda de focusin recupera lo que se escapa; una capa que dejó de estar marcada (retirada, cerrada manteniéndose montada, o reparentada para su animación de salida) devuelve el foco a quien la invocó. Descubrir por marcador en lugar de por ruta es lo que mantiene a los dos productores idénticos byte a byte.
El runtime soporta el proceso de "hidratación", en el que toma el control del HTML que el servidor ya renderizó (SSR). En lugar de destruir y recrear, el runtime solo engancha los listeners de eventos necesarios a los elementos existentes, lo que asegura una carga inicial instantánea.
El runtime detecta el entorno vía el flag window.__EQ_DEV__ (que fija el servidor a partir de IWebHostEnvironment.IsDevelopment()).
Funcionalidades solo de desarrollo
Sistema de logger (utils/logger.ts)
Sistema de logging profesional que solo emite en modo de desarrollo:
import { logger } from './utils/logger';
logger.debug('Boot process started'); // Solo en desarrollo
logger.info('Component rendered'); // Solo en desarrollo
logger.warn('Deprecated API used'); // Siempre registra
logger.error('Failed to load data'); // Siempre registra
Todos los logs llevan el prefijo [eQuantic.UI] para filtrarlos con facilidad.
Overlay de errores (dev/error-overlay.ts)
Overlay de errores al estilo de Next.js que muestra los errores de runtime en una interfaz a pantalla completa (solo en desarrollo):
•
Captura automática: errores no manejados y rechazos de promesas
•
Stack traces: el contexto completo del error con información de la fuente
•
Soporte de teclado: pulsa Esc para cerrar
•
UX limpia: similar al overlay de errores de Next.js
El overlay de errores se importa y se activa automáticamente cuando window.__EQ_DEV__ === true.
En los builds de producción:
•
logger.debug() y logger.info() quedan silenciados
•
El overlay de errores nunca se carga
•
Solo logger.warn() y logger.error() emiten a la consola
•
Coste mínimo de runtime: un bundle, cuyo tamaño gzip es un presupuesto que la suite hace cumplir, en lugar de un número citado aquí
El tema de la aplicación es C# tipado en el servidor (IAppTheme, seleccionado vía UseTheme, vea DesignSystem). El servidor serializa el tema seleccionado en window.__EQ_THEME__ al lado de la configuración de boot, y el puente de tema del runtime (shared/theme-bridge.ts) lo adopta en el boot, así que los píxeles del SSR y el lowering del cliente resuelven los mismos tokens, y un cambio claro/oscuro en tiempo de ejecución voltea una sola declaración color-scheme.