Guía
Errores y depuración
onError para que un fallo no se lleve la aplicación, source maps que señalan tu archivo y los mensajes del compilador.
Cuando una vista falla
Un error dentro de un efecto se lleva por delante lo que lo rodea, a menos que
alguien se haga cargo. onError registra quién:
import { onError, signal } from "ascua";
function Seccion() {
const fallo = signal<string | null>(null);
onError((error) => fallo.set(String(error)));
return view`
<section>
<Show when=${() => fallo() === null}>
<Contenido/>
<Else><p class="error">${() => fallo()}</p></Else>
</Show>
</section>`;
}El error sube por los dueños —el efecto que falló, el componente que lo creó,
el que contiene a ese— hasta el primero que tenga un onError. El manejador
corre en su scope, no en el que falló, así que lo que escriba sobrevive a
lo que se está derrumbando. Sin ninguno registrado, el error se propaga como
siempre: nada se traga en silencio.
Source maps
El compilador emite un source map, así que un error del navegador señala el
archivo que escribiste y no el que salió del compilador. Lo que se copia sin
tocar —casi todo— apunta a su línea exacta; lo que genera una plantilla apunta
a la línea del view que lo produjo, que es donde hay que mirar.
El mapa lleva dentro el TypeScript original, de modo que las herramientas del navegador lo enseñan aunque el archivo no esté servido. Con el plugin de Vite no hay que hacer nada.
Errores de compilación
Salen por la vía de siempre —la consola de Vite, el overlay del navegador— con la línea de la plantilla que los causó:
ascuac: línea 42: <For> necesita `render`: <For each=${() => items()} …/>Lo que suele fallar
Un texto que no se actualiza. Falta la closure: ${cuenta()} se evalúa
una vez; ${() => cuenta()} sigue al signal. Lo mismo con un prop:
${props.valor} pinta la función, ${() => props.valor()} la llama.
Un input que no se vacía desde el código. Está escrito value= y tiene
que ser prop:value=. El atributo es solo el valor inicial.
Un array que cambió y nadie se enteró. Se mutó por dentro (push,
splice, lista[i] = …). Un signal avisa cuando recibe otro valor:
tareas.update((l) => [...l, nueva]).
Una fila de <For> que no refleja un cambio. El nodo de cada clave se
construye una vez. Lo que cambie dentro de un item tiene que leerse de un
signal del propio item.
Efectos que siguen vivos en los tests. Falta afterEach(limpiar).
Tras un await, un efecto que no se libera. El scope se perdió en el
salto. Se captura con currentScope() antes y se restaura con withScope.
Está en Reactividad.
creados no es cero al hidratar. El servidor y el cliente construyeron
cosas distintas: props diferentes, una fecha o un número aleatorio calculado
en los dos lados, o algo que depende de window.