- Seit der ersten Veröffentlichung im Jahr 2017 hat sich WebAssembly weiterentwickelt und unterstützt die Ausführung von Low-Level-Sprachen wie C/C++, wird auf der Web-Plattform aber weiterhin als Sprache zweiter Klasse behandelt
- Nur JavaScript kann direkt mit Web-APIs interagieren, während WebAssembly dafür komplexen JS-Bindungscode (Glue Code) schreiben muss
- Diese Struktur führt zu komplizierten Ladeabläufen, Performance-Overhead und unterbrochenen sprachspezifischen Toolchains, was die Developer Experience verschlechtert
- Um das zu lösen, schlägt Mozilla das WebAssembly Component Model vor, das standardisierte Web-API-Aufrufe und Modul-Laden auch ohne JS ermöglicht
- Wenn sich dieses Modell etabliert, könnte WebAssembly zu einer Laufzeitumgebung erster Klasse im Browser werden und damit die Grundlage schaffen, dass auch allgemeine Entwickler es leicht nutzen können
Warum WebAssembly als Sprache zweiter Klasse behandelt wird
- WebAssembly kann nur über JavaScript auf die Web-Plattform zugreifen und hat keine Berechtigung für direkte Web-API-Aufrufe
- JavaScript lässt sich einfach per
<script>-Tag laden, WebAssembly benötigt dagegen einen manuellen Ladevorgang über die JS-API
- Dafür sind komplexe API-Aufrufe wie
WebAssembly.instantiateStreaming() nötig, die Entwickler auswendig kennen oder per Tool automatisieren müssen
- Der Vorschlag esm-integration vereinfacht den Ladevorgang, indem
.wasm-Dateien direkt über das JS-Modulsystem importiert werden können
- Direktes Laden in der Form
<script type="module" src="/module.wasm"></script> ist möglich
Einschränkungen beim Zugriff auf Web-APIs
- Was in JavaScript mit einer Zeile
console.log("hello, world") möglich ist, erfordert in WebAssembly komplizierte Abläufe wie JS-Speicherzugriff, String-Decodierung und Function Wrapping
- WebAssembly kann weder auf das
console-Objekt noch auf das DOM zugreifen und muss daher aus JS heraus über gemeinsam genutzten Speicher sowie Function Import/Export indirekt aufrufen
- Der dabei erzeugte Bindungscode (Glue Code) unterscheidet sich je nach Sprache und wird mit Tools wie
embind oder wasm-bindgen automatisch generiert
- Das erhöht jedoch die Build-Komplexität und verursacht Runtime-Overhead sowie sprachspezifische Inkompatibilitäten
Technische Gründe, warum WebAssembly keine Sprache erster Klasse wurde
- Schwierige Compiler-Integration: Die Compiler jeder Sprache müssen separaten Integrationscode für JS und die Web-Plattform erzeugen; dieser ist nicht wiederverwendbar
- Inkompatibilität von Standard-Compilern: Mit
rustc --target=wasm erzeugte Dateien lassen sich im Browser nicht direkt ausführen
- Dafür muss zusätzlich eine inoffizielle Toolchain installiert werden, die die Plattform-Integration implementiert
- Verzerrtes Dokumentations-Ökosystem: Web-Dokumentationen wie MDN sind überwiegend auf JavaScript ausgerichtet, was die Einstiegshürde für Nutzer anderer Sprachen erhöht
- Performance-Probleme: DOM-Aufrufe über JS-Bindings sind 45 % langsamer als direkte Aufrufe
- In Experimenten mit dem Dodrio-Framework halbierte sich die Zeit zum Anwenden von DOM-Änderungen, nachdem der JS-Glue-Code entfernt wurde
- JavaScript-Abhängigkeit: Wer WebAssembly praktisch einsetzen will, muss letztlich doch JS verstehen; das führt zum Problem der leaky abstraction
Das WebAssembly Component Model erscheint
- Das WebAssembly Component Model definiert eine standardisierte Ausführungseinheit, die sprach- und runtime-übergreifend gemeinsam genutzt werden kann
- Web-API-Zugriff, Modul-Laden und Linking können direkt ohne JS erfolgen
- Komponenten können in verschiedenen Sprachen erzeugt und in Browsern oder in mehreren Runtimes wie Wasmtime ausgeführt werden
- Über WIT (Interface Description Language) lassen sich benötigte APIs deklarieren, die innerhalb der Komponente direkt aufgerufen werden können
- Browser können Komponenten direkt mit
<script type="module" src="component.wasm"></script> laden und die Web-API-Bindings automatisch ohne JS verarbeiten
Interoperabilität mit JavaScript
- Das Component Model unterstützt auch hybride App-Architekturen
- Beispiel: Ein Bilddecoder wird in WebAssembly geschrieben und kann aus JS in der Form
import { Image } from "image-lib.wasm"; aufgerufen werden
- JS nutzt WebAssembly-Komponenten per Import/Export wie gewöhnliche Module
Ausblick und Beteiligung
- Mozilla arbeitet gemeinsam mit der WebAssembly CG an der Standardisierung des Component Models, auch Google befindet sich in der Prüfungsphase
- Entwickler können mit Jco oder Wasmtime im Browser oder über die CLI experimentieren
- Wenn sich dieses Modell etabliert, könnte sich WebAssembly von einer „Funktion für Power User“ zu einer Web-Technologie entwickeln, die auch allgemeine Entwickler nutzen können
4 Kommentare
Das ist eher bloß ein typischer Wunschtraum von Mozilla. Das Frontend kann sich strukturell nicht aus dem limbischen System der Marktreaktionen lösen. Mit dem Auftauchen von WebAssembly wurde sofort Doom 3 portiert. Das DOM ist in modernen Browsern schon seit Langem zu leichtgewichtigen Proxy-Objekten geworden, und wenn man die JavaScript-spezifischen Instruction Sets moderner CPUs sowie die quantenhaften Grenzen von Single-Core-Systemen berücksichtigt, wird dieser Ansatz niemals einen marktwertbezogenen Vorteil erlangen.
Welche Bedeutung hat überhaupt ein WebAssembly-Binary, das innerhalb von Electron läuft? Das wirkt einfach wie ein weiterer GitKraken-CLI oder wie Ruhmesjagd durch Rust-Portierungen.
Auch wenn ich den Rest nicht beurteilen kann: Die Art, ein wasm-Modul als Datei einzubinden, etwa wie
<script type="module" src="/module.wasm"></script>, klingt schon ziemlich verlockend.Und ich muss unbedingt sagen, dass die Behauptungen, WebAssembly habe eine hohe Einstiegshürde, absurd sind. Es ist nur so, dass die Notwendigkeit dafür geringer ist als die Bereitschaft, dafür zu bezahlen. Ihr wollt Geschwindigkeit und einen kleinen Footprint und gleichzeitig DOM und CSS nutzen? Was ist das für eine schwarze Komödie.
Hacker-News-Kommentare
Es ist schade, dass man das ursprüngliche Ziel aufgegeben hat, WebIDL in WebAssembly zu unterstützen, und stattdessen eine weitere IDL bauen wollte, ohne den fehlenden DOM-Zugriff als Problem zu sehen
Natürlich verstehe ich die Realität des Marktes, aber ich kann das Gefühl nicht loswerden, dass viel Zeit verloren ging
Weiterführende Links: Commit-Verlauf, stringref-Rückblick, ACM-Artikel
Später kamen zwei weitere Ziele hinzu: Unterstützung für Nicht-Web-APIs und Interoperabilität zwischen Sprachen
WebIDL ist die Vereinigungsmenge aus JS und Web API und daher sehr ausdrucksstark, enthält aber viele Konzepte, die mit diesen Zielen kollidieren
Deshalb hat das Component Interface einen weniger ausdrucksstarken, aber deutlich portableren Schnittmengen-Ansatz gewählt
Ich persönlich halte den DOM-Zugriff für wichtig, aber die Wasm CG war mit höher priorisierten Aufgaben beschäftigt
Ich habe diesen Beitrag geschrieben, weil ich zeigen wollte, dass dieses Problem noch nicht vergessen ist und wir weiter daran arbeiten wollen
Toolchain und Build-Prozess sind so komplex, dass ihre Nutzung jedes Mal kognitiven Aufwand erzeugt
Die Performance ist ohne Glue deutlich besser, aber entsprechend gibt es auch mehr Risikofaktoren
Ich hoffe, dass das Component Model keine neue Komplexität einführt, aber wenn man sich die Beispiele in verschiedenen Sprachen anschaut, wirkt es schon jetzt ziemlich verwirrend
Besonders beim Go-Beispiel gibt es zu viele generierte Dateien, und aus Entwicklersicht ist einfacheres Tooling dringend nötig
Im Moment wirkt es nicht so, als würde Komplexität beseitigt, sondern nur verschoben
Da sich die wasm-component-Spezifikation ständig verändert hat, gab es viel Churn
Das Ziel ist, dass Webentwickler WIT nicht selbst schreiben müssen, sondern Web APIs wie eine Bibliothek verwenden können
Aber bis dahin ist es noch ein weiter Weg
Wenn man zum Beispiel Textfreigabe, Medienfreigabe und Anwendungsfreigabe trennt, verbessert das auch die Sicherheit, und kleine Teams könnten Browser-Alternativen bauen
Aber der riesige Umfang der Web APIs und von CSS stützt das Browser-Monopol, daher dürften solche Versuche schwierig sein
Es wäre gut, die WebAssembly-Registry zu standardisieren, damit sich Komponenten leichter kombinieren lassen
Letztlich ist das Web ein Prozess zur Definition eines verteilten Betriebssystems
Dort sind Konzepte und Codebeispiele gut aufbereitet
Im JS-Ökosystem sind StarlingMonkey, ComponentizeJS und jco die drei zentralen Projekte
Die reifste Toolchain ist derzeit Rust, aber auch die Unterstützung für LLVM-basierte Sprachen (C/C++, Go, Python usw.) wird immer besser
Das Ziel von WebAssembly ist es, ein Compile-Target zu werden, das sich natürlich in lokale Toolchains einfügt
Wenn man weiterhin sprachspezifischen Glue-Code oder zwei Laufzeitmodelle verstehen muss, bleibt WebAssembly ein „Werkzeug nur für Extremfälle“
Wenn man wirklich etwas verändern will, muss man den üblichen Build-Pfad vereinfachen
Es ist unklar, wie das im Component Model behandelt wird
Das DOM unterscheidet sich je nach Browser, und die verfügbaren Funktionen ändern sich von Seitenaufruf zu Seitenaufruf
In einer JS-Bridge-Schicht lassen sich Polyfills leicht anwenden, aber in WIT-Schnittstellen sind Methodenerkennung zur Laufzeit oder Polyfills schwierig
Nicht nur Performance, sondern auch die Flexibilität des Ökosystems ist wichtig
JS-Glue-Code selbst zu verwalten oder sich auf Codegenerierungswerkzeuge zu verlassen, fühlt sich wie ein großer Rückschritt an
Dass im Dodrio-Experiment durch Weglassen des Glue 45 % weniger Overhead erreicht wurden, ist beeindruckend
Ich frage mich allerdings, wie beim WebAssembly Component Model das Speichermanagement funktioniert, wenn es direkt mit Web APIs interagiert
Ich würde gern wissen, ob der Wasm-GC-Vorschlag zum Halten von DOM-Referenzen verwendet wird oder ob man weiterhin auf den JS-GC angewiesen ist
Ich hoffe, dass Wasm wirklich ein Bürger erster Klasse wird
Aber derzeit ist IPC immer noch ineffizient, und ich denke, man braucht etwas wie Übertragung auf Speicherseiten-Ebene
Beliebigen Leuten zu erlauben, komplexe Programme auf meinem Computer auszuführen, war aus Sicherheitssicht eine verrückte Idee, aber genau das haben wir getan
Dank JS hatten wir 20 Jahre lang unzählige Browser-Sicherheitslücken, aber inzwischen haben sich Designprinzipien und Gegenmaßnahmen etabliert
Und nun ist es ironisch und zugleich schön, dass man das durch ein weiteres gefährliches Ausführungsparadigma ersetzen will
Mobile Betriebssysteme machen das viel besser als Desktop-Systeme
Sie sind stark aus Ingenieurssicht entworfen und bieten keinen autorenfreundlichen Standard-Workflow
Trotzdem ist es gut zu sehen, dass es noch Leute gibt, denen solche Probleme wichtig sind
Es wirkt wie übertriebene Ingenieursarbeit, nur um für ein 1:1-Mapping der DOM-API eine doppelt so schnelle Stringverarbeitung zu bekommen
Bei APIs wie WebGL2, WebGPU und WebAudio sind die Kosten eines JS-Shims bereits minimal
Das eigentliche Problem sind Dinge wie GPU-Pufferkopien, und dabei hilft das Component Model nicht
Ich würde gern Benchmarks sehen, die zehntausende Draw Calls in WebGL2 oder WebGPU testen
Neben der Performance ist auch eine bessere Developer Experience (DX) wichtig
Der Einstieg ist derzeit zu schwer, und man muss fast Experte sein, um überhaupt Vorteile daraus zu ziehen
Wenn es mit nativer App-Effizienz konkurrieren kann, wäre das eine visionäre Veränderung für die Zukunft des Webs
Im Zeitalter der Coding Agents ist die von ihnen betonte DX-Verbesserung nicht mehr so wichtig