Adrianistán

WebAssembly para tontos (usando Rust)

02/06/2017
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.
curl https://sh.rustup.rs -sSf | sh

El paso clave es instalar un nuevo target, el target de WASM32 (WebAssembly de 32 bits).
rustup target add wasm32-unknown-emscripten

Por supuesto también hace falta instalar Emscripten.

Descarga la versión portable de Emscripten aquí. Descomprime y ejecuta
source ./emsdk_env.sh
emsdk update
emsdk install latest
emsdk activate latest
source ./emsdk_env.sh
emcc -v (para comprobar)

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.

 
fn main(){
println!("Hola mundo - WebAssembly + Rust");
}

Compilamos con rustc

 
rustc --target=wasm32-unknown-emscripten main.rs -o main.html

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:
#[no_mangle]
pub fn random_number() -> i32 {
42
}

fn main() {

}


Ahora compilamos el fichero a WebAssembly
rustc --target=wasm32-unknown-emscripten random.rs

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).

 
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<script>
var Module = {
wasmBinaryFile: "random.wasm",
onRuntimeInitialized: main,
};
function main() {
var random_number = Module.cwrap("random_number","number",[]);
alert(random_number());
}
</script>
<script src="random.js"></script>
</body>
</html>

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?

 
Tags: programacion javascript webassembly rust tutorial bytecode emscripten