Yew, crea webapps al estilo Angular/React en Rust

Hoy os traigo una librería muy potente y muy útil, ahora que Rust compila a WebAssembly de forma nativa. Se trata de Yew, una librería para diseñar frontends, single-page-applications y en general, una librería que es una alternativa a Angular, React, Vue y Elm.

En particular, Yew se basa en The Elm Architecture, por lo que los usuarios de Elm serán los que encuentren más familiar a Yew.

Yew significa tejo. He aquí uno de los tejos más famosos de Valladolid, en la plaza del Viejo Coso

Instalar cargo-web y el soporte a WebAssembly

Antes de empezar a programar necesitaremos instalar un plugin para Cargo, llamado cargo-web, que nos ayudará en el desarrollo web con Rust. Por otro lado, hace falta instalar el soporte de Rust a WebAssembly. Existen tres opciones actualmente: asmjs-unknown-emscripten, wasm32-unknown-emscripten y wasm32-unknown-unknown. Para los primeras opciones hace falta tener instalado Emscripten. Para la última, no hace falta nada, por lo que es mi opción recomendada. Por otro lado, wasm32 significa WebAssembly y asmjs es asm.js, que es simplemente JavaScript y será compatible con más navegadores.

The Elm Architecture

Los principios de The Elm Architecture se basan en: modelo, mensajes, actualización y vista.

Para este tutorial vamos a hacer la típica aplicación de una lista donde guardamos notas. Nuestro modelo se va a componer de una lista de tareas, para simplificar, pongamos que una tarea es simplemente un String y un ID. Entonces también nos hará falta almacenar un contador para ir poniendo IDs. También, al tener un campo de texto, nos hará falta una variable para ir almacenando temporalmente lo que escribe el usuario.

Lo siguiente es diseñar los mensajes. Los mensajes interactúan con el modelo y desencadenan una actualización de la vista. En esta aplicación solo nos hacen falta dos mensajes: añadir mensaje y borrar mensaje. Pero como tenemos un campo de texto, tenemos que introducir un mensaje Change y siempre viene bien un mensaje que no haga nada.

Una vez hecho esto pasamos a crear la función update, en la que hacemos distintas cosas según el mensaje que recibamos.

Así pues, si se lanza un mensaje Msg::Add lo que hacemos es copiar el valor de la variable temporal input, crear una nueva tarea con su ID y añadirla a la lista de tareas. Ya está. Yew mágicamente actualizará la página para reflejar que la lista de tareas ha sido modificada. Lo mismo pasa con Remove.

Ahora vamos a las vistas. Una vista es una función que devuelve Html<Msg> y se pueden componer varias funciones así. En nuestro caso, tenemos una vista principal donde se ve un campo de texto y un sitio donde se ejecuta un bucle for con las tareas del modelo. Y a cada tarea se le aplica la vista view_task.

La macro html! nos permite escribir HTML directamente en Rust, con algunas diferencias (¡prestad atención a las comas!). También nos permite introducir código Rust (entre llaves) y closures (observad onclick, oninput y onkeypress).

Finalmente en el método main, inicializamos el modelo y llamamos a program, que empieza a ejecutar Yew.

El código final queda así.

Ejecutando la aplicación web

Usando cargo web, es muy sencillo generar la aplicación web. Simplemente ejecuta:

El resultado, se montará en un mini servidor web. Si accedes a la URL que indica Cargo con tu navegador web, verás algo similar a esto:

Añade items y bórralos. Observa como la aplicación funciona perfectamente.

Distribuyendo la aplicación

Realmente cargo web ha hecho muchas cosas por nosotros. Si nosotros queremos usar Yew en la vida real, no usaremos cargo web. Para ello, compilamos la aplicación web:

Y accedemos a la carpeta target/wasm32-unknown-unknown/release. Allí encontraremos dos archivos que vamos a necesitar. Uno acabado en .js y otro acabado en .wasm. Ambos ficheros deberemos copiarlos donde queramos usarlos. Por último, será necesario un fichero HTML. En el fichero HTML solo hace falta cargar el fichero JS. Yew hará el resto.

Si quieres saber más, puedes descargarte el código de ejemplo que se encuentra en GitHub.

WebAssembly para tontos (usando Rust)

Este post usa Emscripten para generar WebAssembly con Rust. Hoy día Emscripten no es necesario, pero no he podido actualizar el tutorial

Una de las cosas que más me han sorprendido del mundo web en estos años fue el proyecto WebAssembly. Un proyecto que pretendía traer un bytecode unificado para navegadores. Un proyecto que permitiría compilar prácticamente cualquier lenguaje a la web sin necesidad de tocar JavaScript.

El proyecto surgía de iniciativas fracasadas de Google (PNaCl) y de Mozilla (asm.js). Pero a este proyecto se unieron Microsoft y Apple, por lo que la compatibilidad estaba asegurada.

WebAssembly es un bytecode (como el de Java o el de .NET) que puede ser ejecutado por un navegador, cada navegador implementa su máquina virtual. También es posible usarlo en otros entornos relacionados con el mundo JavaScript como Node.js. Sin embargo entre los objetivos de WebAssembly está no estar atado a JavaScript, por lo que la especificación puede ser implementada por cualquier otro tipo de entorno. Actualmente WebAssembly no tiene recolector de basura y no tiene acceso directo a las Web API. No obstante, sigue siendo un proyecto interesante. Vamos a ver como usar WebAssembly con Rust.

Instalando Rust y Emscripten

Instala Rust, la versión estable es compatible con lo que queremos. Recomiendo usar Rustup.

El paso clave es instalar un nuevo target, el target de WASM32 (WebAssembly de 32 bits).

Por supuesto también hace falta instalar Emscripten.

Descarga la versión portable de Emscripten aquí. Descomprime y ejecuta

Emscripten ya estará instalado junto con Clang y las piezas claves de LLVM necesarias.

Escribiendo el programa en Rust

Vamos a escribir un programa simple. Un hola mundo.

 

Compilamos con rustc

 

Esto genera diversos archivos: main.html, main.js, main.wasm y main.asm.js (para compatibilidad con navegadores que no tienen WebAssembly). El fichero .wasm contiene el bytecode, si intentas abrirlo verás que es ilegible. Sin embargo, Chrome, Firefox, Edge, Safari y Node.js entenderán ese archivo. Probamos el fichero main.html en Firefox (cuya última versión soporta WebAssembly por defecto):


Usando este sistema compilamos aplicaciones enteras. Si se ajustan ciertos parámetros de Emscripten y se usa una crate adecuada en Rust puede usarse para generar juegos 3D usando WebGL escritos 100% en Rust.

Cargas librerías en Rust desde JavaScript

En el paso anterior vimos como compilar a WASM aplicaciones enteras. Ahora vamos a compilar el código de Rust a una librería y vamos a cargarlo con JavaScript.

La librería va a ser muy simple:

Ahora compilamos el fichero a WebAssembly

Ahora vamos a cargar el fichero random.wasm. Para ello usaremos la ayuda de random.js, que contiene el código necesario para cargar el fichero WASM así como definir los imports que el código Rust espera (variables de entorno, funciones globales, etc).

 

Usando este sistema, podemos ir añadiendo código WASM poco a poco en nuestras webs.

 

Conclusión

Como vemos, ya es posible hoy día usar WebAssembly en nuestros proyectos. Para crear el código WebAssembly podemos usar Rust. El código WASM puede interactuar con el código JavaScript existente. ¿Qué opináis de WebAssembly? ¿Creéis que puede suponer un antes y un después en el mundo web o se seguirá usando JavaScript de forma masiva?