Aller au contenu

WebAssembly (avec WASI) ​

WebAssembly est un environnement d'exécution sécurisé, isolé et portable qui fonctionne dans les navigateurs web et en dehors de ceux-ci.

En pratique :

  • Les langages (tels que JavaScript) sont compilés vers WebAssembly (fichiers .wasm)
  • Les environnements d'exécution WebAssembly (tels que wasmtime ou jco) permettent d'exécuter des binaires WebAssembly

Même si WebAssembly de base n'a pas accès au système de fichiers local ou aux sockets, WebAssembly System Interface permet de définir une plateforme sous les charges de travail WebAssembly.

Ainsi, avec WASI, WebAssembly peut manipuler des fichiers, des sockets et bien plus encore.

Information

Vous souhaitez examiner vous-même l'interface WASI ? Consultez wasi:http.

La prise en charge de WebAssembly avec WASI en JavaScript repose sur StarlingMonkey. Grâce au respect des standards web par StarlingMonkey et Hono, Hono fonctionne *sans configuration supplémentaire dans les écosystèmes WebAssembly compatibles WASI.

1. Configuration ​

L'écosystème JavaScript de WebAssembly fournit des outils pour commencer facilement à créer des composants WebAssembly compatibles WASI :

  • StarlingMonkey est un fork de SpiderMonkey qui se compile en WebAssembly et permet de créer des composants
  • componentize-js transforme les modules ES JavaScript en composants WebAssembly
  • jco est un outil polyvalent qui compile des composants, génère des types et exécute les composants dans des environnements comme Node.js ou le navigateur

Information

WebAssembly possède un écosystème ouvert et open source, dont les principaux projets sont gérés principalement par la Bytecode Alliance et ses membres.

Les nouvelles fonctionnalités, signalements de problèmes, pull requests et autres contributions sont toujours les bienvenus.

Bien qu'aucun modèle de démarrage Hono pour WebAssembly ne soit encore disponible, vous pouvez créer un projet Hono WebAssembly comme tout autre projet :

sh
mkdir my-app
cd my-app
npm init
npm i hono
npm i -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std
npm i -D rolldown
sh
mkdir my-app
cd my-app
npm init
yarn add hono
yarn add -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std
yarn add -D rolldown
sh
mkdir my-app
cd my-app
pnpm init --init-type module
pnpm add hono
pnpm add -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std
pnpm add -D rolldown
sh
mkdir my-app
cd my-app
npm init
bun add hono
bun add -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std

Information

Pour que votre projet utilise les modules ES, assurez-vous que type vaut "module" dans package.json.

Après avoir ouvert le dossier my-app, installez les dépendances et initialisez TypeScript :

sh
npm i
npx tsc --init
sh
yarn
yarn tsc --init
sh
pnpm i
pnpm exec tsc --init
sh
bun i

Une fois le fichier de configuration TypeScript de base (tsconfig.json) créé, vérifiez le paramètre suivant :

  • compilerOptions.module défini sur "nodenext"

Puisque componentize-js (et jco, qui le réutilise) ne prend en charge qu'un seul fichier JavaScript, il faut regrouper les fichiers ; rolldown peut créer ce fichier unique.

Vous pouvez utiliser une configuration Rolldown (rolldown.config.mjs) comme celle-ci :

js
import { defineConfig } from 'rolldown'

export default defineConfig({
  input: 'src/component.ts',
  external: /wasi:.*/,
  output: {
    file: 'dist/component.js',
    format: 'esm',
  },
})

Information

Vous pouvez utiliser tout autre outil de regroupement avec lequel vous êtes plus à l'aise (rolldown, esbuild, rollup, etc.).

2. Configurer l'interface WIT et les dépendances ​

WebAssembly Interface Types (WIT) est un langage de définition d'interface (« IDL ») qui décrit les fonctionnalités utilisées (« imports ») et fournies (« exports ») par un composant WebAssembly.

Parmi les interfaces WIT standardisées, wasi:http gère les requêtes HTTP, entrantes comme sortantes. Puisque nous voulons créer un serveur web, notre composant doit déclarer l'utilisation de wasi:http/incoming-handler dans son monde WIT :

Configurons d'abord le monde WIT du composant dans un fichier nommé wit/component.wit :

txt
package example:hono;

world component {
    export wasi:http/incoming-handler@0.2.6;
}

En termes simples, le fichier WIT ci-dessus indique que notre composant « fournit » la fonctionnalité de réception et de traitement des requêtes HTTP entrantes.

L'interface wasi:http/incoming-handler dépend d'interfaces WIT standardisées en amont (qui spécifient notamment la structure des requêtes).

Pour récupérer ces interfaces WIT tierces, maintenues par la Bytecode Alliance, nous pouvons utiliser wkg :

sh
wkg wit fetch

Après l'exécution de wkg, vous devriez trouver dans votre dossier wit un nouveau dossier deps à côté de component.wit :

wit
├── component.wit
└── deps
    ├── wasi-cli-0.2.6
    │   └── package.wit
    ├── wasi-clocks-0.2.6
    │   └── package.wit
    ├── wasi-http-0.2.6
    │   └── package.wit
    ├── wasi-io-0.2.6
    │   └── package.wit
    └── wasi-random-0.2.6
        └── package.wit

3. Bonjour Wasm ​

Pour créer un serveur HTTP dans WebAssembly, vous pouvez utiliser le projet [jco-std][jco-std], qui propose des helpers rendant l'expérience très proche de celle de Hono classique.

Implémentons notre monde component avec une application Hono de base sous forme de composant WebAssembly dans un fichier nommé src/component.ts :

ts
import { Hono } from 'hono'
import { fire } from '@bytecodealliance/jco-std/wasi/0.2.6/http/adapters/hono/server'

const app = new Hono()

app.get('/hello', (c) => {
  return c.json({ message: 'Hello from WebAssembly!' })
})

fire(app)

// Although we've called `fire()` with wasi HTTP configured for use above,
// we still need to actually export the `wasi:http/incoming-handler` interface object,
// as jco and componentize-js will be looking for the ES module export that matches the WASI interface.
export { incomingHandler } from '@bytecodealliance/jco-std/wasi/0.2.6/http/adapters/hono/server'

4. Compilation ​

Puisque nous utilisons Rolldown, configuré pour compiler TypeScript, nous pouvons l'utiliser pour compiler et regrouper les fichiers :

sh
npx rolldown -c
sh
yarn rolldown -c
sh
pnpm exec rolldown -c
sh
bun build --target=bun --outfile=dist/component.js ./src/component.ts

Information

L'étape de regroupement est nécessaire, car les outils de l'écosystème JavaScript de WebAssembly ne prennent actuellement en charge qu'un seul fichier JavaScript, et nous voulons inclure Hono ainsi que les bibliothèques associées.

Pour les composants aux besoins plus simples, les outils de regroupement ne sont pas nécessaires.

Pour compiler votre composant WebAssembly, utilisez jco (et indirectement componentize-js) :

sh
npx jco componentize -w wit -o dist/component.wasm dist/component.js
sh
yarn jco componentize -w wit -o dist/component.wasm dist/component.js
sh
pnpm exec jco componentize -w wit -o dist/component.wasm dist/component.js
sh
bun run jco componentize -w wit -o dist/component.wasm dist/component.js

5. Exécution ​

Pour exécuter votre serveur HTTP Hono WebAssembly, vous pouvez utiliser n'importe quel environnement d'exécution WebAssembly compatible WASI :

Dans ce guide, nous utiliserons jco serve, puisqu'il est déjà installé.

Attention

jco serve est destiné au développement et n'est pas recommandé en production.

sh
npx jco serve dist/component.wasm
sh
yarn jco serve dist/component.wasm
sh
pnpm exec jco serve dist/component.wasm
sh
bun run jco serve dist/component.wasm

Vous devriez obtenir un résultat similaire à celui-ci :

$ npx jco serve dist/component.wasm
Server listening @ localhost:8000...

Une requête vers localhost:8000/hello renverra le JSON défini dans votre application Hono.

Vous devriez obtenir un résultat similaire à celui-ci :

json
{ "message": "Hello from WebAssembly!" }

Information

jco serve convertit le composant WebAssembly en un module de base WebAssembly, afin de l'exécuter dans des environnements tels que Node.js et le navigateur.

Ce processus s'effectue normalement avec jco transpile. Il permet d'utiliser des moteurs JavaScript tels que Node.js et le navigateur (qui peuvent utiliser V8 ou d'autres moteurs JavaScript) comme environnements d'exécution de composants WebAssembly.

Le fonctionnement de jco transpile dépasse le cadre de ce guide ; vous pouvez en apprendre davantage dans le livre Jco.

Informations complémentaires ​

Pour en savoir plus sur WASI, les composants WebAssembly et les sujets associés, consultez :

Pour contacter la communauté WebAssembly avec des questions, commentaires, contributions ou signalements de problèmes :

Publié sous licence MIT.