WebAssembly (mit WASI)
WebAssembly ist eine sichere, isolierte und portable Laufzeitumgebung, die innerhalb und außerhalb von Webbrowsern ausgeführt wird.
In der Praxis:
- Sprachen wie JavaScript werden zu WebAssembly kompiliert (
.wasm-Dateien). - WebAssembly-Laufzeitumgebungen wie
wasmtimeoderjcoermöglichen das Ausführen von WebAssembly-Binärdateien.
Während WebAssembly selbst keinen Zugriff auf das lokale Dateisystem, Sockets oder Ähnliches hat, ermöglicht das WebAssembly System Interface, eine Plattform für WebAssembly-Workloads zu definieren.
Das bedeutet, dass WebAssembly mit WASI mit Dateien, Sockets und vielem mehr arbeiten kann.
Info
Möchtest du dir die WASI-Schnittstelle selbst ansehen? Schau dir wasi:http an.
Die Unterstützung für WebAssembly mit WASI in JavaScript basiert auf StarlingMonkey. Da sowohl StarlingMonkey als auch Hono sich auf Webstandards konzentrieren, funktioniert Hono *ohne zusätzliche Anpassungen in WASI-fähigen WebAssembly-Ökosystemen.
1. Einrichtung
Das JavaScript-Ökosystem von WebAssembly bietet Werkzeuge, mit denen du einfach WASI-fähige WebAssembly-Komponenten erstellen kannst:
- StarlingMonkey ist ein Fork von SpiderMonkey, der zu WebAssembly kompiliert wird und Komponenten ermöglicht.
componentize-jswandelt JavaScript-ES-Module in WebAssembly-Komponenten um.jcoist ein Mehrzweckwerkzeug, das Komponenten baut, Typen generiert und Komponenten in Umgebungen wie Node.js oder dem Browser ausführt.
Info
WebAssembly hat ein offenes Ökosystem und ist quelloffen. Die Kernprojekte werden hauptsächlich von der Bytecode Alliance und ihren Mitgliedern betreut.
Neue Funktionen, Fehlermeldungen, Pull Requests und andere Beiträge sind jederzeit willkommen.
Eine Hono-Projektvorlage für WebAssembly ist noch nicht verfügbar. Du kannst ein WebAssembly-Hono-Projekt aber wie jedes andere Projekt beginnen:
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 rolldownmkdir my-app
cd my-app
npm init
yarn add hono
yarn add -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std
yarn add -D rolldownmkdir 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 rolldownmkdir my-app
cd my-app
npm init
bun add hono
bun add -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-stdInfo
Damit dein Projekt ES-Module verwendet, stelle sicher, dass type in package.json auf "module" gesetzt ist.
Nachdem du in den Ordner my-app gewechselt bist, installiere die Abhängigkeiten und initialisiere TypeScript:
npm i
npx tsc --inityarn
yarn tsc --initpnpm i
pnpm exec tsc --initbun iWenn du eine grundlegende TypeScript-Konfigurationsdatei (tsconfig.json) erstellt hast, stelle sicher, dass sie die folgende Einstellung enthält:
- Setze
compilerOptions.moduleauf"nodenext".
Da componentize-js und jco, das es ebenfalls verwendet, nur einzelne JavaScript-Dateien unterstützen, ist das Bündeln erforderlich. Mit rolldown kannst du ein Bundle aus einer einzelnen Datei erstellen.
Du kannst eine Rolldown-Konfiguration (rolldown.config.mjs) wie diese verwenden:
import { defineConfig } from 'rolldown'
export default defineConfig({
input: 'src/component.ts',
external: /wasi:.*/,
output: {
file: 'dist/component.js',
format: 'esm',
},
})Info
Du kannst auch jeden anderen Bundler verwenden, mit dem du besser vertraut bist (rolldown, esbuild, rollup usw.).
2. WIT-Schnittstelle und Abhängigkeiten einrichten
WebAssembly Interface Types (WIT) ist eine Schnittstellenbeschreibungssprache („IDL“), die festlegt, welche Funktionen eine WebAssembly-Komponente verwendet („Imports“) und welche sie bereitstellt („Exports“).
Unter den standardisierten WIT-Schnittstellen dient wasi:http der Verarbeitung von HTTP-Anfragen, sowohl beim Empfangen als auch beim Senden. Da wir einen Webserver erstellen wollen, muss unsere Komponente die Verwendung von wasi:http/incoming-handler in ihrer WIT-World deklarieren:
Richte zunächst die WIT-World der Komponente in einer Datei namens wit/component.wit ein:
package example:hono;
world component {
export wasi:http/incoming-handler@0.2.6;
}Einfach ausgedrückt bedeutet die obige WIT-Datei, dass unsere Komponente die Funktionalität zum Empfangen und Verarbeiten eingehender HTTP-Anfragen „bereitstellt“.
Die Schnittstelle wasi:http/incoming-handler hängt von vorgelagerten standardisierten WIT-Schnittstellen ab, etwa Spezifikationen zur Struktur von Anfragen.
Um diese von der Bytecode Alliance gepflegten WIT-Schnittstellen von Drittanbietern herunterzuladen, können wir das Werkzeug wkg verwenden:
wkg wit fetchSobald wkg fertig ist, sollte dein Ordner wit neben component.wit auch einen neuen Ordner deps enthalten:
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.wit3. Hello Wasm
Um einen HTTP-Server in WebAssembly zu erstellen, können wir das Projekt [jco-std][jco-std] verwenden. Es enthält Helfer, durch die sich die Entwicklung sehr ähnlich wie mit gewöhnlichem Hono anfühlt.
Implementieren wir unsere World component mit einer einfachen Hono-Anwendung als WebAssembly-Komponente in einer Datei namens src/component.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. Build
Da wir Rolldown verwenden und es für die TypeScript-Kompilierung eingerichtet haben, können wir damit bauen und bündeln:
npx rolldown -cyarn rolldown -cpnpm exec rolldown -cbun build --target=bun --outfile=dist/component.js ./src/component.tsInfo
Das Bündeln ist erforderlich, da die Werkzeuge des JavaScript-Ökosystems von WebAssembly momentan nur eine einzelne JavaScript-Datei unterstützen und wir Hono sowie verwandte Bibliotheken einschließen möchten.
Für Komponenten mit einfacheren Anforderungen sind keine Bundler erforderlich.
Um deine WebAssembly-Komponente zu bauen, verwende jco und damit indirekt componentize-js:
npx jco componentize -w wit -o dist/component.wasm dist/component.jsyarn jco componentize -w wit -o dist/component.wasm dist/component.jspnpm exec jco componentize -w wit -o dist/component.wasm dist/component.jsbun run jco componentize -w wit -o dist/component.wasm dist/component.js5. Ausführen
Um deinen Hono-WebAssembly-HTTP-Server auszuführen, kannst du jede WASI-fähige WebAssembly-Laufzeitumgebung verwenden:
wasmtimejco(läuft in Node.js)
In dieser Anleitung verwenden wir jco serve, da es bereits installiert ist.
Achtung
jco serve ist für die Entwicklung gedacht und wird nicht für den Einsatz in der Produktion empfohlen.
npx jco serve dist/component.wasmyarn jco serve dist/component.wasmpnpm exec jco serve dist/component.wasmbun run jco serve dist/component.wasmDu solltest eine Ausgabe wie diese sehen:
$ npx jco serve dist/component.wasm
Server listening @ localhost:8000...Eine Anfrage an localhost:8000/hello erzeugt die JSON-Ausgabe, die du in deiner Hono-Anwendung festgelegt hast.
Du solltest eine Ausgabe wie diese sehen:
{ "message": "Hello from WebAssembly!" }Info
jco serve konvertiert die WebAssembly-Komponente in ein grundlegendes WebAssembly-Kernmodul, damit sie in Laufzeitumgebungen wie Node.js und dem Browser ausgeführt werden kann.
Dieser Vorgang wird normalerweise über jco transpile ausgeführt. Dadurch können wir JavaScript-Umgebungen wie Node.js und den Browser, die V8 oder andere JavaScript-Engines verwenden können, als Laufzeitumgebungen für WebAssembly-Komponenten nutzen.
Die Funktionsweise von jco transpile liegt außerhalb des Umfangs dieser Anleitung. Weitere Informationen findest du im Jco-Handbuch.
Weitere Informationen
Mehr über WASI, WebAssembly-Komponenten und andere Themen erfährst du in den folgenden Ressourcen:
- Handbuch zum Komponentenmodell der Bytecode Alliance
jco-Codebasisjco-Beispielkomponenten (insbesondere das Hono-Beispiel)
- Jco-Handbuch
componentize-js-Codebasis- StarlingMonkey-Codebasis
Für Fragen, Kommentare, Beiträge oder Fehlermeldungen an die WebAssembly-Community:
- Bytecode Alliance Zulip (erwäge einen Beitrag im #jco-Kanal)
- Jco-Repository
- componentize-js-Repository