Introducción a WebAssembly: Introducción a WebAssembly

WebAssembly promete un tipo de web completamente nuevo: un rendimiento más ágil para los usuarios y más flexibilidad para los desarrolladores. En lugar de limitarse al uso de JavaScript como único lenguaje para la interacción web del lado del cliente, un desarrollador puede elegir entre una amplia gama de otros lenguajes (C, TypeScript, Rust, Ruby, Python) y trabajar en el que le resulte más cómodo. con.

Originalmente, la única forma de crear WebAssembly (o WASM para abreviar) era compilar código C / C ++ en WebAssembly utilizando la cadena de herramientas Emscripten. Hoy en día, los desarrolladores no solo tienen más opciones de idioma, sino que se ha vuelto más fácil compilar estos otros lenguajes directamente en WebAssembly, con menos pasos intermedios.

En este artículo, examinaremos los pasos necesarios para implementar componentes WebAssembly en una aplicación web. Debido a que WebAssembly es un trabajo en progreso, los pasos dependen en gran medida del idioma que use, y es probable que la cadena de herramientas siga cambiando durante algún tiempo. Pero en este momento, es posible escribir e implementar aplicaciones WebAssembly útiles, aunque mínimas, en varios idiomas.

Elija un idioma compatible con WebAssembly

El primer paso para implementar una aplicación WebAssembly es elegir un idioma que se pueda compilar en WebAssembly como destino. Existe una buena posibilidad de que al menos uno de los lenguajes principales que está utilizando en producción se pueda convertir a WebAssembly o tenga un compilador que pueda emitir WebAssembly.

Aquí están los favoritos:

  • C. Obviamente. La forma típica de convertir el código C en WebAssembly es a través de Emscripten, ya que C-to-Emscripten-to-WebAssembly fue la primera cadena de herramientas de WebAssembly que apareció. Pero están surgiendo otras herramientas. Un compilador completo, Cheerp, ha sido diseñado específicamente para generar aplicaciones WebAssembly a partir de código C / C ++. Cheerp también puede apuntar a JavaScript, asm.js o cualquier combinación de los anteriores. También es posible utilizar la cadena de herramientas de Clang para crear cargas útiles de WebAssembly, aunque el proceso todavía requiere una gran cantidad de elevación manual. (Aquí hay un ejemplo).
  • Oxido. El lenguaje de programación de sistemas de Mozilla, diseñado para ser seguro y rápido, es uno de los principales candidatos para el soporte nativo de WebAssembly. Las extensiones de la cadena de herramientas de Rust le permiten compilar directamente desde el código de Rust en WebAssembly. Necesita usar la nightlycadena de herramientas de Rust para realizar la compilación de WebAssembly, por lo que esta función debe considerarse experimental por ahora.
  • TypeScript . De forma predeterminada, TypeScript se compila en JavaScript, lo que significa que a su vez podría compilarse en WebAssembly. El proyecto de AssemblyScript reduce el número de pasos necesarios, lo que permite compilar TypeScript estrictamente escrito en WebAssembly.

Varios otros lenguajes están empezando a apuntar a WebAssembly, pero se encuentran en las primeras etapas. Los siguientes lenguajes se pueden utilizar para crear componentes WebAssembly, pero solo de formas más limitadas que C, Rust y TypeScript:

  • D . El lenguaje D agregó recientemente soporte para compilar y vincular directamente a WebAssembly.
  • Java . El código de bytes de Java se puede compilar con anticipación en WebAssembly a través del proyecto TeaVM. Esto significa que cualquier lenguaje que emita código de bytes de Java se puede compilar en WebAssembly, por ejemplo, Kotlin, Scala o Clojure. Sin embargo, muchas de las API de Java que no se pueden implementar de manera eficiente en WebAssembly están restringidas, como las API de reflexión y recursos, por lo que TeaVM, y por lo tanto WebAssembly, solo se puede utilizar para un subconjunto de aplicaciones basadas en JVM. 
  • Lua . El lenguaje de secuencias de comandos Lua tiene una larga historia de uso como lenguaje integrado, al igual que JavaScript. Sin embargo, los únicos proyectos para convertir Lua en WebAssembly implican el uso de un motor de ejecución en el navegador: wasm_lua incrusta un tiempo de ejecución de Lua en el navegador, mientras que Luwa JIT compila Lua en WebAssembly.
  • Kotlin / Nativo . Los fanáticos del lenguaje Kotlin, un derivado de Java, han estado esperando ansiosamente el lanzamiento completo de Kotlin / Native, un back-end LLVM para el compilador Kotlin que puede producir binarios independientes. Kotlin / Native 0.4 introdujo soporte para WebAssembly como objetivo de compilación, pero solo como prueba de concepto.
  • .Net . Los lenguajes .Net aún no tienen soporte completo de WebAssembly, pero se han iniciado algunos experimentos. Consulte Blazor, que se puede utilizar para crear aplicaciones web de una sola página en .Net a través de C # y la sintaxis "Razor" de Microsoft.
  • Nim . Este lenguaje emergente se compila en C, por lo que, en teoría, se podría compilar el C resultante en WebAssembly. Sin embargo, se está desarrollando un back-end experimental para Nim llamado nwasm.
  • Otros lenguajes basados ​​en LLVM . En teoría, cualquier lenguaje que aproveche el marco del compilador de LLVM se puede compilar en WebAssembly, ya que LLVM admite WebAssembly como uno de los muchos objetivos. Sin embargo, esto no significa necesariamente que cualquier lenguaje compilado por LLVM se ejecutará como está en WebAssembly. Simplemente significa que LLVM facilita la orientación de WebAssembly.

Todos los proyectos anteriores convierten el programa original o el código de bytes generado en WebAssembly. Pero para lenguajes interpretados como Ruby o Python, hay otro enfoque: en lugar de convertir las aplicaciones en sí, se convierte el tiempo de ejecución del lenguaje  en WebAssembly. A continuación, los programas se ejecutan tal cual en el tiempo de ejecución convertido. Dado que muchos tiempos de ejecución de lenguajes (incluidos Ruby y Python) están escritos en C / C ++, el proceso de conversión es fundamentalmente el mismo que con cualquier otra aplicación C / C ++.

Por supuesto, esto significa que el tiempo de ejecución convertido debe descargarse en el navegador antes de que se puedan ejecutar aplicaciones con él, lo que ralentiza los tiempos de carga y análisis. Una versión “pura” de WebAssembly de una aplicación es más ligera. Por lo tanto, la conversión en tiempo de ejecución es, en el mejor de los casos, una medida provisional hasta que más lenguajes admitan WebAssembly como destino de exportación o compilación.

Integrar WebAssembly con JavaScript

El siguiente paso es escribir código en el lenguaje que ha elegido, prestando atención a cómo ese código interactuará con el entorno WebAssembly, luego compilarlo en un módulo WebAssembly (un binario WASM) y finalmente integrar ese módulo con un Aplicación JavaScript.

Los pasos exactos sobre cómo exportar el código a WebAssembly variarán enormemente según la cadena de herramientas. También se desviarán un poco de la forma en que se construyen los binarios nativos regulares para ese idioma. Por ejemplo, en Rust, deberá seguir varios pasos:

  1. Configura la nightly compilación para Rust, con la wasm32-unknown-unknowncadena de herramientas.
  2. Escriba su código de Rust con funciones externas declaradas como #[no-mangle].
  3. Cree el código utilizando la cadena de herramientas anterior.

(Para obtener un resumen detallado de los pasos anteriores, consulte el libro The Rust and WebAssembly en GitHub).

Vale la pena señalar que, sea cual sea el lenguaje que esté utilizando, deberá tener al menos un nivel mínimo de competencia en JavaScript para poder integrar el código con una interfaz HTML. Si los fragmentos de JavaScript en la página en este ejemplo de The Rust and WebAssembly Book le parecen griegos, reserve algo de tiempo para aprender al menos suficiente JavaScript para comprender lo que está sucediendo allí.

La integración de WebAssembly y JavaScript se realiza mediante el uso del WebAssemblyobjeto en JavaScript para crear un puente a su código WebAssembly. Mozilla tiene documentación sobre cómo hacer esto. Aquí hay un ejemplo de WebAssembly separado para Rust, y aquí hay un ejemplo de WebAssembly para Node.js.

En este momento, la integración entre el back-end de WebAssembly y el front-end de JavaScript / HTML sigue siendo la parte más engorrosa y manual de todo el proceso. Por ejemplo, con Rust, los puentes a JavaScript aún deben crearse manualmente, a través de punteros de datos sin procesar.

Sin embargo, más piezas de la cadena de herramientas están comenzando a abordar este problema. El marco Cheerp permite a los programadores de C ++ comunicarse con las API del navegador a través de un espacio de nombres dedicado. Y Rust ofrece wasm-bindgen, que sirve como puente bidireccional entre JavaScript y Rust, y entre JavaScript y WebAssembly.

Además, se está considerando una propuesta de alto nivel sobre cómo manejar las vinculaciones con el host. Una vez finalizado, proporcionará una forma estándar para que los lenguajes que se compilan en WebAssembly interactúen con los hosts. La estrategia a largo plazo de esta propuesta también incluye enlaces a hosts que no son navegadores, pero los enlaces de navegador son el caso de uso inmediato a corto plazo.

Depurar y crear perfiles de aplicaciones WebAssembly

Un área donde las herramientas de WebAssembly aún se encuentran en las primeras etapas es la compatibilidad con la depuración y la creación de perfiles. 

Hasta que aparecieron los mapas de código fuente de JavaScript, los lenguajes que se compilaban en JavaScript a menudo eran difíciles de depurar porque el código original y compilado no se podían correlacionar fácilmente. WebAssembly tiene algunos de los mismos problemas: si escribe código en C y lo compila en WASM, es difícil establecer correlaciones entre la fuente y el código compilado.

Los mapas de código fuente de JavaScript indican qué líneas del código fuente corresponden a qué regiones del código compilado. Algunas herramientas de WebAssembly, como Emscripten, también pueden emitir mapas fuente JavaScript para código compilado. Uno de los planes a largo plazo para WebAssembly es un sistema de mapas de origen que va más allá de lo que está disponible en JavaScript, pero aún está solo en la etapa de propuesta.

En este momento, la forma más directa de depurar código WASM en la naturaleza es utilizando la consola de depuración del navegador web. Este artículo en WebAssemblyCode muestra cómo generar código WASM con un mapa fuente, ponerlo a disposición de las herramientas de depuración del navegador y recorrer el código. Tenga en cuenta que los pasos descritos dependen del uso de la emccherramienta para emitir el WASM. Es posible que deba modificar los pasos según su cadena de herramientas en particular.