BookinglyTech News
Software

Fitz convierte una función del servidor en una llamada local desde un componente WASM

El compilador genera las dos mitades, el endpoint POST y el stub con fetch, a partir de una sola declaración @rpc, con el mismo tipo compartido entre cliente y servidor.

3 min de lecturaDev.to0 vistas

Fitz, el lenguaje que compila componentes .fitzv por dos vías —HTML renderizado en servidor vía WebSocket, o SPA autónoma en WebAssembly— ha cerrado el bucle. Ahora basta marcar una función asíncrona con @rpc para invocarla desde el componente como si estuviera en local: let u = get_user(42).await?. El compilador escribe las dos mitades a partir de esa única declaración.

Antes de esto, un componente en el navegador era una isla. Leer la base de datos o validar un token obliga a pasar por el servidor, y el puente clásico es fontanería: escribir el endpoint, escribir el fetch, serializar el JSON en ambos sentidos y mantener los tipos sincronizados a mano. Aquí eso desaparece.

Qué emite el compilador

En el lado servidor, la función @rpc se monta como POST /__rpc/get_user. El cuerpo es un objeto JSON con un campo por parámetro, en este caso {"id": 42}. Cada parámetro se deserializa de su campo, la función se ejecuta y su Result<T> se traduce a un 200 con el JSON de T si es Ok, o a un 500 con {"error": ...} si es Err. Todo esto reutiliza el pipeline de @post, con observabilidad y captura de panics incluidos.

En el cliente, el import de la función @rpc se emite como un stub asíncrono basado en fetch; el cuerpo original no se transpila a WASM. El stub serializa los argumentos, hace POST al mismo origen —así la cookie de sesión viaja con la petición— y mapea la respuesta de vuelta a Result<T>. Como el manejador de eventos ahora hace await, el compilador lo parte en un envoltorio síncrono y un worker asíncrono mediante spawn_local, de modo que la actualización de estado y el re-render se disparan cuando llega la respuesta.

El ejemplo del repositorio es una SPA de dos botones más un binario de servidor, verificado en Chrome real: el botón de saludo devuelve el texto desde el servidor y el de carga trae el usuario, lo deserializa y lo pinta, sin errores de página. El crate cliente compila a .wasm de verdad con wasm-pack. Los comandos son fitz build --bin server, que monta las rutas /__rpc/* en el puerto 3838, y fitz build --bin web, que genera target/wasm/web/web_bg.wasm. La SPA tiene que servirse desde el mismo origen que el servidor, o poner ambos detrás de un proxy inverso, para que el fetch relativo llegue.

No es el patrón, es lo que falta alrededor

Las funciones de servidor no son nuevas: Next.js tiene Server Actions, Remix sus loaders y actions, SvelteKit su +page.server, y existen tRPC y Phoenix. La diferencia que Fitz reclama es que no hay paso de infraestructura: ni directiva use server, ni router de tRPC, ni generador de código. El tipo User se define una vez y se compila a un struct nativo y a un struct WASM, así que el desajuste entre ambos es imposible por construcción. El servidor reaprovecha su pila HTTP integrada y el cliente solo arrastra fetch y serde cuando algún crate usa @rpc.

Los límites que el propio autor reconoce: un tipo nominal que cruza la red hay que importarlo también en el .fitzv, la autenticación apilada sobre el endpoint generado (@authenticated, @admin) queda para después —ahora la cookie de sesión viaja y el token se comprueba dentro del cuerpo de la función— y el componente re-renderiza una sola vez al llegar la respuesta, sin estado intermedio de carga. Lo siguiente en la serie es la hidratación SSR.

La propuesta es interesante por dónde quita trabajo, no por inventar el patrón. Quien haya mantenido a mano la sincronización entre un tipo del backend y su copia en el frontend sabe cuántas horas se van ahí. Queda por ver si Fitz aguanta ese modelo cuando la aplicación crece y las llamadas @rpc dejan de ser un puñado.