JavaScript a Wasi Habilitado Wasm: Composición Portátil de JavaScript

Rate this content
Bookmark

JavaScript ya no es un lenguaje limitado a los navegadores. Nuevos estándares están permitiendo entornos de ejecución totalmente portátiles y livianos, para hacer de JavaScript el lenguaje definitivo para aplicaciones isomórficas.

Exploraremos casos de uso, algunos experimentales, otros consolidados, para llevar nuestro juego de Wasm con JavaScript al siguiente nivel.

Natalia Venditto
Natalia Venditto
21 min
15 Feb, 2024

Video Summary and Transcription

El código JavaScript se convierte en binarios de bajo nivel mediante motores de JavaScript como MV8, Chakra y SpiderMonkey. WebAssembly permite escribir código en otros lenguajes y compilarlo para ejecutarlo en un motor de JavaScript. Las funciones externas se pueden importar en WebAssembly utilizando la declaración de importación. WebAssembly puede ejecutarse en escenarios no relacionados con el navegador con interfaces adicionales como WASI y proporciona aislamiento de memoria. La herramienta Jco es una herramienta experimental para componentizar el código JavaScript en módulos WASM.

Available in English

1. Introduction to JavaScript and WebAssembly

Short description:

Soy una líder principal de experiencia de desarrollo de JavaScript en Azure, que abarca integraciones, servicios de alojamiento y cómputo. El código JavaScript pasa por un flujo de ejecución en el navegador, desde el análisis hasta la generación de código. Los motores de JavaScript como MV8, Chakra y SpiderMonkey convierten el código en binarios de bajo nivel. WebAssembly es un formato de instrucciones binarias que nos permite escribir código en otros lenguajes y compilarlo para que se ejecute en un motor de JavaScript. Funciona en base a importaciones y exportaciones.

Hola a todos. Mi nombre es Natalia Bendito y soy una líder principal de experiencia de desarrollo de JavaScript de extremo a extremo en los muchos servicios y herramientas que pueden ser utilizados por los desarrolladores de JavaScript para construir aplicaciones en Azure. Eso incluye integraciones como GitHub Actions o extensiones de VS Code, servicios de alojamiento como Azure Static Web Apps, o cómputo como Azure Container Apps o Azure Functions. Cuando construimos aplicaciones de JavaScript, sabemos que nuestro código o scripts pasan básicamente por este flujo de ejecución en el navegador. Cada instrucción pasa por este viaje justo a tiempo. El analizador o motor de JavaScript genera una estructura jerárquica llamada árbol de sintaxis abstracta o AST. Por ejemplo, una declaración de variable es un constructo de nodo de declaración de variable en AST, que el intérprete lee y genera código binario de alto nivel a partir de él. Finalmente, el compilador genera código binario de bajo nivel que se comunica con la CPU de una manera que puede ser entendida según la arquitectura del procesador o CPU. Todo esto ocurre nuevamente justo a tiempo. Este flujo es principalmente el trabajo del motor de JavaScript. MV8 es uno de los más populares, pero también existen Chakra, SpiderMonkey y otros. El código de máquina generado puede estar optimizado para un conjunto específico de instrucciones que son, nuevamente, óptimas para una arquitectura específica, como mencionamos antes. Esto significa que estamos convirtiendo nuestro código de JavaScript de alto nivel en binarios de bajo nivel. Los motores de JavaScript pueden encargarse de la inicialización del entorno o encargarse de la inicialización del entorno. Añaden funciones integradas y también ejecutan nuestro código de aplicación. El motor también proporciona el tiempo de ejecución en el que se ejecutará la aplicación. Los scripts de JavaScript se ejecutan en un motor de JavaScript, obviamente, pero ¿qué más se ejecuta en un motor de JavaScript, si lo piensas a ese nivel bajo? Eso es, por supuesto, WebAssembly.

¿Qué es WebAssembly más concretamente, o Wasm, como algunos lo llaman? No es realmente un lenguaje. Es un formato de instrucciones binarias. El objetivo de compilación significa que escribimos nuestro código en el lenguaje que preferimos siempre y cuando tenga una cadena de herramientas o compilador de Wasm que nos permita hacerlo y lo compilamos a binario como Wasm para ejecutarlo en ese nivel bajo que describimos antes. ¿Cómo funciona realmente WebAssembly? Imaginemos que tenemos un programa escrito en C, C++, Rust o cualquier otro lenguaje que sea compatible, y queremos compilarlo a Wasm. Usamos su correspondiente cadena de herramientas o conjunto de herramientas de desarrollo, y eso es a lo que me refería antes con que sea compatible. Tiene este conjunto de herramientas de desarrollo y compiladores, que emitirán ese código como un módulo, que importa y exporta. Luego podemos importarlo en nuestro JavaScript para que se ejecute con un motor de JavaScript utilizando las uniones de WebAssembly JavaScript o la API de JavaScript. Wasm no define realmente ninguna API. Funciona como mencionamos sobre la base de importaciones y exportaciones. Este es un ejemplo de un módulo escrito en texto de WebAssembly. Recorramos este ciclo.

2. Using External Functions in WebAssembly

Short description:

La declaración de importación se utiliza para importar una función externa, como println del módulo de entorno. La sección de funciones exporta la función hello world. La sección de memoria declara el tamaño de la memoria y la sección de datos inicializa la memoria con una cadena. Al importar el módulo en JavaScript, obtenemos el módulo, procesamos la respuesta, compilamos los datos binarios y creamos una instancia del módulo. Podemos redirigir la salida de la función print line a console.log. WebAssembly nos permite ejecutar operaciones intensivas en CPU a un nivel más bajo y componer interfaces de usuario. Page find es un ejemplo de uso de WebAssembly para la ingestión de documentos, indexación y búsqueda de texto completo en el lado del cliente. Podemos lograr esto en un sitio web estático utilizando WebAssembly.

Creo que es importante comenzar con la declaración de importación que se utiliza para importar una función externa porque no tenemos nada en las API nativas de Wasm. Estamos importando esta función externa llamada println desde un módulo llamado environment. Esta función toma un solo parámetro de tipo I32 o entero de 32 bits. La función importada se le da el nombre de dollar println. Ahora, en la siguiente sección, tenemos la sección de funciones. La función se exporta con el nombre hello world. Luego tenemos otra sección, la sección de memoria, que básicamente declara el tamaño de la memoria. En este caso, una página. Finalmente, tenemos la sección de datos que inicializa la memoria, en este caso en el desplazamiento cero con una cadena UTF-8, hello world de JavaScript. Ahora, lo que creo que es realmente interesante es lo que sucede en JavaScript que importa este módulo o busca este módulo. Obtenemos el módulo que exportamos a un archivo llamado hello world.wasm. Luego, la respuesta se procesa utilizando response.arrive buffer para obtener los datos binarios del módulo. Luego usamos la función WebAssembly.compile para compilar los datos binarios que obtuvimos del paso anterior en un módulo de WebAssembly. Usamos el constructor WebAssembly.instance para crear una instancia del módulo de WebAssembly compilado. Como puedes ver, hay un objeto de entorno proporcionado en el segundo parámetro del constructor, que incluye una función importante llamada print line. ¿Recuerdas el archivo anterior? Esta función importante se asigna a console log. El propósito de esta asignación es redirigir cualquier salida de la función print line del módulo de WebAssembly, como se define en el código de texto de WebAssembly que proporcionamos antes, a la función console.log de JavaScript. Y finalmente, la función exportada hello world se invoca desde el módulo de WebAssembly utilizando instance.exports.hello world o hello world.

Dado que tenemos la capacidad de buscar y ejecutar Wasm, como acabamos de ver, como parte de nuestros programas de JavaScript, podemos componer interfaces de usuario donde ejecutamos operaciones intensivas en CPU a un nivel mucho más bajo o inferior que nuestros programas de JavaScript típicos se ejecutan de una manera más eficiente. Exploraremos un caso de uso específico de este tipo de composición. Propongamos que tenemos un sitio web estático, como uno creado con cualquier metaframework hoy en día, como Astro, y así sucesivamente, utilizando la obtención de datos estáticos. Y queremos ejecutar una funcionalidad de búsqueda para ese contenido estático. Bueno, podemos hacerlo con JavaScript en el lado del cliente, pero también podemos usar WebAssembly. Así que lo usaremos. Y page find es un gran ejemplo de una característica de Wasm que hace, en este caso, la ingestión de documentos, la indexación y ejecuta la búsqueda de texto completo, filtrado, ordenación, etc., todo en el lado del cliente a un nivel muy bajo en WebAssembly. Permíteme mostrarte ahora exactamente cómo funciona page find. Estamos en el sitio de documentación, pero iremos a Starlight, un marco para construir sitios de documentación con Astro. Si prestamos atención a la parte superior izquierda, veremos que tenemos una barra de búsqueda. Aunque este es un sitio generado estáticamente, ¿cómo funciona esto? Ejecutemos una búsqueda de algo como div. Notaremos que obtenemos resultados inmediatos.

3. WebAssembly en Escenarios No Navegadores

Short description:

La funcionalidad de búsqueda en el sitio web estático se implementa de manera transparente utilizando JavaScript y WebAssembly. WebAssembly puede ejecutarse en escenarios no navegadores con interfaces adicionales como WASI. WebAssembly con WASI habilitado se ejecuta en un tiempo de ejecución especial que incluso puede ejecutarse en metal desnudo. WebAssembly es seguro y aislado. Se muestra una demostración de código JavaScript que se ejecuta en el navegador y en el tiempo de ejecución de WASM utilizando la cadena de herramientas Javi y el tiempo de ejecución de WASM.

resultados. Tomó unos pocos milisegundos para mostrar los resultados. Ahora, busquemos algo más. Busquemos 'bottom', por ejemplo. Y obtenemos aún más resultados a la misma velocidad exacta.

Ahora, al hacer clic en los resultados, somos redirigidos de inmediato a la página correspondiente de la que proviene la cita del resultado. Ahora, examinemos qué sucede detrás de escena en este ejemplo. ¿Es esta una funcionalidad del lado del cliente en JavaScript que se inicia en las páginas estáticas y se ejecuta en la base de datos en algún lugar? Si vamos a las fuentes ahora mismo con el inspector, déjame mostrarlo y enfocar la barra de búsqueda, veremos de inmediato algo que sucede aquí. Aquí. Vemos esta fuente wasm y el contenido del módulo. Hemos demostrado que podemos ejecutar y operar sin problemas entre programas de JavaScript y módulos de WebAssembly. Hay API de plataforma que facilitan la transferencia de memoria, la activación de eventos o la actualización del estado entre el código que se ejecuta en el objeto de ventana y el que se ejecuta en un worker. Y puedes decir, bueno, eso está muy bien, Natalia, pero eso no es JavaScript. Lo sé, es Rust. Y tienes razón. Entonces, ¿qué pasa si queremos usar JavaScript de principio a fin, incluso en escenarios no navegadores donde los flujos de tiempo de ejecución justo a tiempo pueden no ser la mejor opción o pueden no ser compatibles? ¿Tenemos las herramientas para hacerlo? ¿Podemos hacer que JavaScript sea portátil desde el navegador hasta entornos no navegadores y viceversa de verdad? ¿Podemos hacer esto? Comencemos respondiendo esta pregunta. Si WebAssembly necesita un motor de JavaScript y estos suelen ser parte de un navegador, ¿podemos ejecutar WebAssembly en escenarios no navegadores? Podemos, siempre y cuando proporcionemos interfaces adicionales. Por ejemplo, las de WASI o la interfaz del sistema WebAssembly. La interfaz del sistema WebAssembly es solo otro estándar. Es una interfaz de sistema modular construida para WebAssembly fuera del navegador. Y es totalmente compatible con los sistemas POSIX. Al igual que WebAssembly utiliza la máquina virtual de JavaScript para ejecutarse en el navegador, WebAssembly con WASI habilitado se ejecuta en un tiempo de ejecución especial que incluso puede ejecutarse en metal desnudo. Recuerda que WebAssembly no tiene acceso a ninguna API y que no importamos explícitamente. Es decir, son entornos completamente seguros desde ese punto de vista. Están aislados. Hablaremos más sobre estas características de seguridad en un momento. Veamos ahora una demostración de código JavaScript que se escribió una vez y se ejecuta en el navegador y en el tiempo de ejecución de WASM utilizando una cadena de herramientas llamada Javi. Bienvenido a mi traductor binario. Ahora, para esta demostración, necesito algunas dependencias. Necesito Javi, una cadena de herramientas de JavaScript y WebAssembly, y como no voy a ejecutar esto solo en el navegador, necesitaré un entorno independiente.

4. Portabilidad de JavaScript a WASM

Short description:

El código JavaScript convierte caracteres en números ASCII y binarios. El código utiliza la cadena de herramientas Javi para operaciones de lectura y escritura. Puede compilarse en un módulo WASM y ejecutarse con tiempo WASM. El mismo código se ejecuta en el navegador y fuera del navegador con cambios mínimos, demostrando portabilidad, reducción de mantenimiento y mejora de rendimiento.

runtime para WASM, en este caso, tiempo WASM. Ahora, yendo al código, podemos verificar que esto es JavaScript. Tenemos algunas funciones en el archivo bittranslate.js. El script básicamente toma una palabra y convierte cada carácter en su número ASCII y luego en binario. Entonces, lo que obtenemos después de leerlo es su representación en formato binario. Como mencionamos antes, es solo JavaScript puro, excepto por algunas líneas donde estamos usando esta biblioteca, esta cadena de herramientas, Javi, para algunas operaciones de lectura y escritura. Cuando se ejecuta en el navegador, utilizaremos las API estándar de JavaScript, y cuando no estamos en el navegador, realizaremos exactamente las mismas operaciones con Javi.

Ahora compilaremos nuestro código en un módulo WASM utilizando esta cadena de herramientas. Ejecutaremos Javi compile, pasando el archivo de entrada y el nombre del archivo de salida, y cuando tengamos nuestro código como un módulo WASM, podemos volver a la terminal y usar tiempo WASM para ejecutarlo. Para eso, le pasaremos una cadena, en este caso, hello world devops.js, y boom, obtenemos su representación binaria. Ahora hemos demostrado que este código JavaScript se ejecuta fuera del navegador como WASM, pero ¿sigue funcionando en el navegador como JavaScript? Iniciamos un servidor de alimentación simple y pasamos exactamente la misma cadena al formulario HTML que luego la pasa al script, y obtenemos exactamente el mismo resultado. Se ejecuta el mismo código en dos entornos diferentes con mínimas refactorizaciones o código adicional mínimo, y podemos ver de inmediato los beneficios de la portabilidad en

5. Seguridad de WebAssembly y Modelo de Componentes

Short description:

WebAssembly es seguro y proporciona aislamiento de memoria. WASM habilitado para WASI tiene capas adicionales para la depuración y definiciones de API inestables. No todas las interfaces están disponibles para todos los lenguajes. WASI Preview 2 se basa en el modelo de componentes, proporcionando oportunidades para aplicaciones portátiles. Jco es una cadena de herramientas para JavaScript a WASM habilitado para WASI, implementando el modelo de componentes.

En términos de reducción de mantenimiento y rendimiento. Antes de probar una herramienta diferente para demostrar la portabilidad y composición, permítanme destacar algunos aspectos de seguridad. Debido a que WebAssembly se ejecuta en un entorno completamente encapsulado, es seguro en cuanto a la memoria y mucho más seguro que cualquier otro contexto de ejecución dentro de la máquina virtual de JavaScript. Cuando se compone dentro de una página en el navegador, WebAssembly implementará las mismas políticas de seguridad y contenido que el origen que lo ejecuta. Y ese entorno controlado proporcionado por el host se asegura de que el código deWebAssembly no pueda acceder ni modificar la memoria fuera de sus límites designados, lo que resulta en un aislamiento de memoria y una interacción directa limitada con otros procesos y componentes en el host.

Las interacciones suelen estar limitadas a través de interfaces bien definidas, lo que reduce el riesgo de actividades maliciosas, reduce el riesgo de ataques a la cadena de suministro y reduce el vector de ataque o la superficie de vector. Todo parece increíble, pero todo tiene un compromiso en la ingeniería y desarrollo de software. Si alguien te dice que no es así, desconfía. ¿Cuál es el inconveniente con WASM habilitado para WASI? Hay más capas para depurar para comprender el origen de un problema cuando se tiene uno. Estas nuevas tecnologías están en versión preliminar y, por lo tanto, son inestables y propensas a cambios en las definiciones de API. Y, por supuesto, no todas las interfaces están disponibles para todos los lenguajes, ya que cada lenguaje tiene su propia cadena de herramientas y progresan en diferentes momentos en la integración de nuevosestándares. Por lo tanto, WASI Preview 2 se lanzó recientemente. Estamos a mediados de febrero. Eso sucedió a finales de enero de 2024. Y se basó completamente en el modelo de componentes en lugar demódulos. Una arquitectura de amplio alcance para construir aplicaciones y entornos interoperables con WebAssembly. ¿Cómo nos brinda el modelo de componentes más oportunidades para ejecutar aplicaciones portátiles? Bueno, hay grandes ventajas para la composición en lanube. Y recuerda, estábamos hablando de componer JavaScript en WebAssembly. Y esto amplía nuestras oportunidades con JavaScript isomórfico compilado a WASM habilitado para WASI que puede ejecutarse en el navegador y en los workers. Esto ya está disponible o es posible con algunos proveedores. Y permítanme mostrarles otra cadena de herramientas, Jco. Esta es una cadena de herramientas para JavaScript a WASM habilitado para WASI que implementa el modelo de componente. Y lo mostraré en el siguiente ejemplo de demostración. Ahora, en esta última demostración, usaremos la cadena de herramientas Jco, como se mencionó, una cadena de herramientas de JavaScript a WASM específicamente construida para el modelo de componentes. También ejecutaremos WASM con WASM time. Pero en este caso, lo compilaremos con cargo con ese propósito. Compilaremos WASM con cargo. Y en primer lugar, tengo todas mis dependencias en su lugar. Tengo la cadena de herramientas Jco. Tengo el shim Preview 2. También usaré

6. Usando la cadena de herramientas Jco para la componentización

Short description:

La cadena de herramientas Jco es experimental y no estable. Escribir con archivos como contratos de interfaz no es sencillo. Jco puede evolucionar para ofrecer una forma más intuitiva para los desarrolladores de JavaScript. El archivo fuente es la función hello. Después de componentizar a WASM, podemos ejecutarlo con node o usar cargo y REST para construir una versión. La cadena de herramientas Jco puede transpilar el contenido del componente WASM para ejecutarlo con node. Únete a microfrontend.dev para obtener más información sobre frontend, estándares web y composibilidad. ¡Gracias por sintonizar!

componentize.js. La trampa con esta biblioteca es que es experimental y no estable. Y la otra trampa está en la cadena de herramientas, porque necesitarás escribir con archivos como contratos de interfaz, lo cual no es una tarea muy sencilla en términos de experiencia del desarrollador. Estoy seguro de que Jco evolucionará para ofrecer una forma más intuitiva paraJavaScript desarrolladores de generar binarios de componentes WASM a partir de una fuenteJavaScript. Pero por ahora, mi archivo fuente es la función hello, que es así. Y tiene su correspondiente con world.

Ahora, esos dos archivos se utilizan para componentizar a WASM. En este caso, la salida será un componente llamado hello.component.wasm. Y después de generarla, podremos ejecutarla con node. Como mencioné, podemos ejecutarla con node, pero también podemos usar cargo y REST para construir una versión y ejecutar el mismo código con WASM time. Y después de obtener ese componente, o ese WASM como componente, podemos usar la cadena de herramientas Jco para transpilar el contenido de ese componente WASM para poder ejecutarlo con node. Esto creará una carpeta con los componentes necesarios para ejecutar este código en un Node.js worker. Ahora, en la demostración, lo estoy ejecutando con el REPL de Node.js, pero esta misma salida se puede ejecutar en la nube en un worker siempre que admita la cadena de herramientas de vista previa. Ahora, muchas gracias. Y únete a microfrontend.dev para obtener más información sobre frontend, estándares web y composibilidad. Gracias por sintonizar. Adiós.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Modern Web Debugging
JSNation 2023JSNation 2023
29 min
Modern Web Debugging
Top Content
Few developers enjoy debugging, and debugging can be complex for modern web apps because of the multiple frameworks, languages, and libraries used. But, developer tools have come a long way in making the process easier. In this talk, Jecelyn will dig into the modern state of debugging, improvements in DevTools, and how you can use them to reliably debug your apps.
Utilising Rust from Vue with WebAssembly
Vue.js London Live 2021Vue.js London Live 2021
8 min
Utilising Rust from Vue with WebAssembly
Top Content
Rust is a new language for writing high-performance code, that can be compiled to WebAssembly, and run within the browser. In this talk you will be taken through how you can integrate Rust, within a Vue application, in a way that's painless and easy. With examples on how to interact with Rust from JavaScript, and some of the gotchas to be aware of.
The Future of Performance Tooling
JSNation 2022JSNation 2022
21 min
The Future of Performance Tooling
Top Content
Our understanding of performance & user-experience has heavily evolved over the years. Web Developer Tooling needs to similarly evolve to make sure it is user-centric, actionable and contextual where modern experiences are concerned. In this talk, Addy will walk you through Chrome and others have been thinking about this problem and what updates they've been making to performance tools to lower the friction for building great experiences on the web.
Making JavaScript on WebAssembly Fast
JSNation Live 2021JSNation Live 2021
29 min
Making JavaScript on WebAssembly Fast
Top Content
JavaScript in the browser runs many times faster than it did two decades ago. And that happened because the browser vendors spent that time working on intensive performance optimizations in their JavaScript engines.Because of this optimization work, JavaScript is now running in many places besides the browser. But there are still some environments where the JS engines can’t apply those optimizations in the right way to make things fast.We’re working to solve this, beginning a whole new wave of JavaScript optimization work. We’re improving JavaScript performance for entirely different environments, where different rules apply. And this is possible because of WebAssembly. In this talk, I'll explain how this all works and what's coming next.
Crafting the Impossible: X86 Virtualization in the Browser with WebAssembly
JSNation 2022JSNation 2022
21 min
Crafting the Impossible: X86 Virtualization in the Browser with WebAssembly
WebAssembly is a browser feature designed to bring predictable high performance to web applications, but its capabilities are often misunderstood.
This talk will explore how WebAssembly is different from JavaScript, from the point of view of both the developer and the browser engine, with a particular focus on the V8/Chrome implementation.
WebVM is our solution to efficiently run unmodified x86 binaries in the browser and showcases what can be done with WebAssembly today. A high level overview of the project components, including the JIT engine, the Linux emulation layer and the storage backend will be discussed, followed by live demos.
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
DevOps.js Conf 2022DevOps.js Conf 2022
31 min
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
You will learn about one of the most popular package managers for JavaScript and its advantages over npm and Yarn.A brief history of JavaScript package managersThe isolated node_modules structure created pnpmWhat makes pnpm so fastWhat makes pnpm disk space efficientMonorepo supportManaging Node.js versions with pnpm

Workshops on related topic

React, TypeScript, and TDD
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
Paul Everitt
Paul Everitt
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.