Repo: https://github.com/umarquez/100DaysOfC0D3/tree/master/31-wasm

WebAssembly

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.

WebAssembly (abreviado Wasm) es un formato binario de instrucciones para una máquina virtual de tipo stack. Wasm está diseñado como objetivo portable para la compilación de lenguajes de alto nivel como C/C++/Rust, haciendo posible la implementación web de aplicaciones cliente y servidor.

https://webassembly.org/

Es importante aclarar que WebAssembly no busca sustituir a JS, es más bien cercano a la evolución de tecnologías como los controles ActiveX, ActionScript o Java Applets.

En esta ocasión vamos a explorar esta tecnología utilizando Golang como lenguaje de alto nivel para desarrollar nuestras aplicaciones, aprenderemos a compilar y empaquetar nuestros programas para que puedan ser distribuidos por medio de un servidor web y jugaremos un poco con el DOM para conocer la forma en que WASM interactúa con él bajo este contexto.

Ventajas y desventajas

Es importante mencionar que en este momento de la historia hacer WASM con Golang no es la manera más óptima de desarrollar aplicaciones, esto debido al overhead que se genera por integrar el runtime nativo de Go a cada aplicación; por otro lado, la experiencia de programar este tipo de aplicaciones en este lenguajes es muy fluida debido a que programando de manera habitual con solo tener en cuenta algunas consideraciones es posible generar programas WASM.

Requerimientos previos

Cross-compiling

Para lograr compilar nuestro código y generar un archivo *.wasm será necesario ejecutar el cross-compiling desde un sistema operativo Linux o compatible ya que desde Windows los archivos resultantes no podrán ser ejecutados.

El comando para compilar el proyecto del directorio actual a WASM (app.wasm) sería el siguiente:

GOOS=js GOARCH=wasm go build -o app.wasm .  

Workaround para Windows 10

Podemos aprovechar una característica de este sistema operativo para compilar nuestras aplicaciones, se trata de WSL (Windows Subsystem for Linux) que nos permite instalar un sistema operativo Linux adicional y que puede ser ejecutado de forma simultanea.
En el siguiente enlace podremos encontrar una guía que nos ayudará a habilitar y configurar esta característica además de instalar el sistema operativo que elijamos, en mi caso tengo instalado Ubuntu 18.04:

Windows Subsystem for Linux Installation Guide for Windows 10 (ingles)

Ubuntu WSL

Una vez hayamos instalado el sistema operativo adicional será necesario instalar y configurar Go v1.11 (o superior) dentro de este.

lsb

Ya con esto instalado y configurado, podremos ejecutar comandos directamente en la consola de windows que serán ejecutados dentro del WSL de la siguiente manera:

wsl pwd

wsl pwd

Ahora bien, para compilar nuestra aplicación será necesario realizar un paso adicional, esto debido a que ejecutando comandos de esta manera no implica que las variables establecidas en los archivos ~/.profile y /etc/profile sean procesadas, esto lo podemos probar ejecutando el comando go version:

wsl go version

Como podemos ver, el comando no está disponible, para solucionarlo deberemos cargar de manera manual el perfil (o perfiles) necesarios, en este caso la variable PATH con la ruta de Go se encuentra definida dentro del archivo /etc/profile, por lo que podemos crear un script de la siguiente forma para ejecutar ambos pasos:

#!/bin/bash

source /etc/profile
go version

wsl .sh

Probemos nuestro script compilando un !Hola Mundo! simple, para ello modificaremos la línea 4 de la siguiente manera:

#!/bin/bash

source /etc/profile
GOOS=js GOARCH=wasm go build -o app.wasm .

El código que utilizaremos para nuestro !Hola Mundo! será el siguiente:

package main

import "fmt"

func main() {
	fmt.Println("!Hola Mundo!")
}

Ejecutando script obtendremos el archivo WASM que, como podemos observar en la imagen, tiene un tamaño similar a un ejecutable “nativo”.

Carga y ejecución con HTML

Aparte de contar con nuestra aplicación compilada *.wasm, debemos incluir dentro de nuestro proyecto el código HTML/JS que se encargará de cargar y ejecutar nuestro programa; para ello utilizaremos los archivos incluidos dentro de nuestra instalación de Go, en el direcotio: $GOROOT/misc/wasm, podremos ejecutar la siguiente secuencia de comandos si nos encontramos en un entorno Linux:

cp "$(go env GOROOT)/misc/wasm/wasm_exec.html" .
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

O podemos descargarlos directamente del repositorio oficial:
https://github.com/golang/go/tree/release-branch.go1.13/misc/wasm

Servidor web

Para lograr ejecutar el archivo *.wasm, este debe ser servido con el tipo MIME application/wasm por lo que deberemos recurrir a un servidor web o servicio de hospedaje que cumpla con estas características; para lograr ejecutar nuestro archivo de manera local podemos crear un webserver, también en Go, usando el siguiente código:

package main

import (
	"log"
	"net/http"
)

func main() {
	http.Handle("/", http.FileServer(http.Dir("./www")))
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal(err)
	}
}

Con este código serviremos el contenido del directorio ./www, así que deberemos crearlo y colocar dentro los archivos HTML/JS/WASM, también sería buena idea renombrar el archivo .html para que sea servido como página principal así que el nuevo nombre de este será index.html.

Finalmente, ejecutamos nuestro servidor, abrimos el sitio localhost:8080 en nuestro navegador y comprobamos su funcionamiento.

Una vez que la aplicación ha cargado se activará el botón Run, al presionarlo se ejecutará nuestro código y se mostrará el texto !Hola Mundo! en la consola.

Jugando con el DOM

Comencemos con algo relativamente sencillo, vamos a crear una aplicación que genere texturas como la siguiente, alternando los caracteres / y \ de manera aleatoria:

Slashes

Para conseguir generar texturas similares:

  1. Deberemos dividir el espacio disponible en 4 cuadrantes.
  2. Generaremos un valor aleatorio que determine el caracter a imprimir.
  3. Colocaremos el caracter seleccionado en la posición correspondiente dentro del primer cuadrante y su equivalente en los cuadrantes restantes.
  4. Repetimos esta secuencia hasta haber colocado todos los caracteres.
  5. Imprimimos el texto resultante dentro del espacio seleccionado.

Palabras finales

Hemos desarrollado nuestro primer programa WASM usando Go, en el proceso conocimos la forma de copilar estas aplicaciones y cargarlas en nuestra página, además de como podemos interactuar con el DOM desde ella.

En próximos artículos hablaremos más acerca de esta tecnología y la aprovecharemos para explicar otros conceptos.