relax.js/core disena sus componentes web pensando en agentes de IA
El autor de la libreria publica la tercera entrega de su serie y explica por que el modelo de componentes es corto, verificable y sin estado reactivo.

El autor de @relax.js/core ha publicado la tercera entrega de su serie sobre como esta libreria de componentes web convive con un agente de programacion. La tesis de fondo: el modelo mental que el agente tiene que sostener en la cabeza debe ser corto y verificable, sin capas que existan solo porque el framework las invento. Todos los bloques de codigo salen de una app de ejemplo que corre bajo vitest, no de bocetos.
Componentes que son elementos nativos
Un componente no hereda de una clase base ni se registra con un decorador. Extiende HTMLElement, usa los ciclos de vida nativos y se define con customElements.define al final del archivo. Para un agente eso tiene una ventaja concreta: el ciclo de vida esta documentado en MDN, que ha leido mucho mas que la documentacion de cualquier framework. Y como el nombre del tag es un string literal, la tabla de rutas, el test y el HTML que usan profile-header se localizan con un grep.
El autor se encontro una trampa mientras escribia el ejemplo. Si un archivo de test importa la clase solo como tipo, el bundler elimina el import, el modulo nunca se ejecuta y el tag nunca queda definido. Hay que importar el modulo por su efecto secundario. defineRoutes falla rapido dando el nombre del tag cuando ocurre, que es como lo detecto.
El ciclo de vida es sincrono
connectedCallback devuelve el control antes de que termine cualquier cosa que se espere dentro. Marcarlo async compila, pero el navegador ignora la promesa. Es el primer vicio que arrastra un agente desde ngOnInit o onMounted. El patron es hacer la parte sincrona, lanzar la asincrona y dejar que esta actualice el DOM cuando llegue. En el ejemplo la pagina carga en loadRoute, que el router si espera.
Nada se re-renderiza solo
No hay estado reactivo. Cuando un dato cambia, el DOM se actualiza en ese punto. El formulario se renderiza una vez y nunca mas, porque cada render volveria a escribir value en los inputs y machacaria lo que el usuario esta tecleando. El formulario nativo es el estado. No hay espejo de los valores en la clase. Es la regla que mas cuesta a quien viene de Vue, y tambien la que hace que el diff diga exactamente lo que pasa.
Los eventos son clases, no CustomEvent con un saco de detalle. La clase lleva propiedades y se registra en el mapa de eventos de lo que escuches, asi addEventListener infiere el tipo y e.displayName queda comprobado. Un grep del nombre devuelve todos los productores y consumidores, que es toda la historia de estado compartido que necesita una app pequena.
Lo que falta es deliberado: sin store, sin propiedades computadas, sin context ni provide/inject. Si un valor se deriva, se calcula donde cambia la fuente y se pasa el resultado. Si dos componentes lejanos necesitan el mismo dato, la pagina que lo posee coloca ambos por slots en vez de ir hilando la dependencia hacia abajo.
La apuesta va al contrario de la tendencia. Cuanto menos tenga que recordar el agente, menos superficie tiene para equivocarse, y el precio es que el desarrollador escribe a mano cosas que otros frameworks regalan.

