WebAssembly-Primer: Beginnen Sie mit WebAssembly

WebAssembly verspricht eine völlig neue Art von Web - eine schnellere Leistung für Benutzer und mehr Flexibilität für Entwickler. Anstatt JavaScript als einzige Sprache für die clientseitige Webinteraktion zu verwenden, kann ein Entwickler aus einer Vielzahl anderer Sprachen auswählen - C, TypeScript, Rust, Ruby, Python - und in der Sprache arbeiten, in der er sich am wohlsten fühlt mit.

Ursprünglich bestand die einzige Möglichkeit, WebAssembly (oder kurz WASM) zu erstellen, darin, C / C ++ - Code mithilfe der Emscripten-Toolchain in WebAssembly zu kompilieren. Heutzutage haben Entwickler nicht nur mehr Sprachoptionen, sondern es ist auch einfacher geworden, diese anderen Sprachen mit weniger Schritten direkt in WebAssembly zu kompilieren.

In diesem Artikel werden die Schritte untersucht, die zum Implementieren von WebAssembly-Komponenten in einer Web-App erforderlich sind. Da WebAssembly noch in Arbeit ist, hängen die Schritte stark von der verwendeten Sprache ab, und die Toolchain wird sich wahrscheinlich noch einige Zeit ändern. Derzeit ist es jedoch möglich, nützliche, wenn auch minimale WebAssembly-Anwendungen in mehreren Sprachen zu schreiben und bereitzustellen.

Wählen Sie eine von WebAssembly unterstützte Sprache

Der erste Schritt zum Bereitstellen einer WebAssembly-Anwendung besteht darin, eine Sprache auszuwählen, die mit WebAssembly als Ziel kompiliert werden kann. Es besteht eine gute Chance, dass mindestens eine der wichtigsten Sprachen, die Sie in der Produktion verwenden, in WebAssembly konvertiert werden kann oder über einen Compiler verfügt, der WebAssembly ausgeben kann.

Hier sind die Spitzenreiter:

  • C. Offensichtlich. Die typische Möglichkeit, C-Code in WebAssembly umzuwandeln, ist Emscripten, da C-zu-Emscripten-zu-WebAssembly die erste WebAssembly-Toolchain war, die auf den Markt kam. Es entstehen jedoch auch andere Tools. Ein ganzer Compiler, Cheerp, wurde speziell für die Generierung von WebAssembly-Anwendungen aus C / C ++ - Code entwickelt. Cheerp kann auch auf JavaScript, asm.js oder eine beliebige Kombination der oben genannten Ziele abzielen. Es ist auch möglich, die Clang-Toolchain zum Erstellen von WebAssembly-Nutzdaten zu verwenden, obwohl der Prozess immer noch viel manuelles Heben erfordert. (Hier ist ein Beispiel.)
  • Rost. Die sichere und schnelle Systemprogrammiersprache von Mozilla ist einer der Hauptkandidaten für die native Unterstützung von WebAssembly. Mit Erweiterungen der Rust-Toolchain können Sie direkt von Rust-Code zu WebAssembly kompilieren. Sie müssen die nightlyToolchain von Rust verwenden , um die WebAssembly-Kompilierung durchzuführen. Daher sollte diese Funktion vorerst als experimentell betrachtet werden.
  • TypeScript . Standardmäßig wird TypeScript in JavaScript kompiliert, was bedeutet, dass es wiederum in WebAssembly kompiliert werden kann. Das AssemblyScript-Projekt reduziert die Anzahl der erforderlichen Schritte, sodass streng typisiertes TypeScript in WebAssembly kompiliert werden kann.

Einige andere Sprachen zielen auf WebAssembly ab, befinden sich jedoch noch in einem sehr frühen Stadium. Die folgenden Sprachen können zum Erstellen von WebAssembly-Komponenten verwendet werden, jedoch nur in eingeschränkterer Weise als C, Rust und TypeScript:

  • D . Die Sprache D hat kürzlich Unterstützung für das Kompilieren und Verknüpfen direkt mit WebAssembly hinzugefügt.
  • Java . Java-Bytecode kann vorab über das TeaVM-Projekt in WebAssembly kompiliert werden. Dies bedeutet, dass jede Sprache, die Java-Bytecode ausgibt, in WebAssembly kompiliert werden kann, z. B. Kotlin, Scala oder Clojure. Viele der Java-APIs, die in WebAssembly nicht effizient implementiert werden können, sind jedoch eingeschränkt, z. B. die Reflection- und Ressourcen-APIs. Daher ist TeaVM - und damit WebAssembly - nur für eine Teilmenge von JVM-basierten Apps von Nutzen. 
  • Lua . Die Lua-Skriptsprache wird wie JavaScript seit langem als eingebettete Sprache verwendet. Die einzigen Projekte, die Lua in WebAssembly verwandeln, umfassen die Verwendung einer In-Browser-Ausführungs-Engine: wasm_lua bettet eine Lua-Laufzeit in den Browser ein, während Luwa JIT Lua in WebAssembly kompiliert.
  • Kotlin / Native . Fans der Kotlin-Sprache, einem Spin-off von Java, haben gespannt auf die vollständige Veröffentlichung von Kotlin / Native gewartet, einem LLVM-Backend für den Kotlin-Compiler, das eigenständige Binärdateien erstellen kann. Kotlin / Native 0.4 führte die Unterstützung für WebAssembly als Kompilierungsziel ein, jedoch nur als Proof of Concept.
  • .Net . Die .Net-Sprachen bieten noch keine vollständige Unterstützung für WebAssembly, aber einige Experimente haben begonnen. Siehe Blazor, mit dem einseitige Webanwendungen in .Net über C # und die Microsoft-Syntax „Razor“ erstellt werden können.
  • Nim . Diese aufstrebende Sprache wird zu C kompiliert, sodass man theoretisch das resultierende C zu WebAssembly kompilieren kann. Ein experimentelles Backend für Nim namens nwasm befindet sich jedoch in der Entwicklung.
  • Andere LLVM-basierte Sprachen . Theoretisch kann jede Sprache, die das LLVM-Compiler-Framework nutzt, zu WebAssembly kompiliert werden, da LLVM WebAssembly als eines von vielen Zielen unterstützt. Dies bedeutet jedoch nicht unbedingt, dass eine mit LLVM kompilierte Sprache in WebAssembly unverändert ausgeführt wird. Dies bedeutet lediglich, dass LLVM das Targeting von WebAssembly erleichtert.

Alle oben genannten Projekte konvertieren das ursprüngliche Programm oder den generierten Bytecode in WebAssembly. Aber für interpretierten Sprachen wie Ruby oder Python, gibt es einen anderen Ansatz: Anstatt die Apps selbst umzuwandeln, ein wandelt die Sprache Laufzeit  in Webassembly. Die Programme werden dann zur konvertierten Laufzeit unverändert ausgeführt. Da viele Sprachlaufzeiten (einschließlich Ruby und Python) in C / C ++ geschrieben sind, ist der Konvertierungsprozess grundsätzlich der gleiche wie bei jeder anderen C / C ++ - Anwendung.

Dies bedeutet natürlich, dass die konvertierte Laufzeit in den Browser heruntergeladen werden muss, bevor Anwendungen damit ausgeführt werden können, was das Laden und die Analysezeiten verlangsamt. Eine „reine“ WebAssembly-Version einer App ist leichter. Daher ist die Laufzeitkonvertierung bestenfalls eine Notlösung, bis mehr Sprachen WebAssembly als Export- oder Kompilierungsziel unterstützen.

Integrieren Sie WebAssembly in JavaScript

Der nächste Schritt besteht darin, Code in der von Ihnen gewählten Sprache zu schreiben und dabei darauf zu achten, wie dieser Code mit der WebAssembly-Umgebung interagiert. Anschließend wird er in ein WebAssembly-Modul (eine WASM-Binärdatei) kompiliert und schließlich in ein vorhandenes Modul integriert JavaScript-Anwendung.

Die genauen Schritte zum Exportieren des Codes in WebAssembly variieren je nach Toolchain erheblich. Sie weichen auch etwas von der Art und Weise ab, wie reguläre native Binärdateien für diese Sprache erstellt werden. In Rust müssen Sie beispielsweise mehrere Schritte ausführen:

  1. Richten Sie den nightly Build für Rust mit der wasm32-unknown-unknownToolchain ein.
  2. Schreiben Sie Ihren Rust-Code mit externen Funktionen, die als deklariert sind #[no-mangle].
  3. Erstellen Sie den Code mit der obigen Toolchain.

(Eine detaillierte Übersicht über die oben genannten Schritte finden Sie im The Rust and WebAssembly Book auf GitHub.)

Es ist erwähnenswert, dass Sie unabhängig von der verwendeten Sprache mindestens ein Mindestmaß an JavaScript-Kenntnissen benötigen, um den Code in ein HTML-Frontend zu integrieren. Wenn Ihnen die In-Page-JavaScript-Schnipsel in diesem Beispiel aus The Rust and WebAssembly Book griechisch erscheinen, nehmen Sie sich etwas Zeit, um mindestens genug JavaScript zu lernen, um zu verstehen, was dort passiert.

Die Integration von WebAssembly und JavaScript erfolgt mithilfe des WebAssemblyObjekts in JavaScript, um eine Brücke zu Ihrem WebAssembly-Code zu erstellen. Mozilla verfügt über eine Dokumentation dazu. Hier ist ein separates WebAssembly-Beispiel für Rust und hier ein WebAssembly-Beispiel für Node.js.

Derzeit ist die Integration zwischen dem WebAssembly-Backend und dem JavaScript / HTML-Frontend immer noch der umständlichste und manuellste Teil des gesamten Prozesses. Beispielsweise müssen mit Rust Brücken zu JavaScript noch manuell über Rohdatenzeiger erstellt werden.

Es werden jedoch immer mehr Teile der Toolchain dieses Problem beheben. Mit dem Cheerp-Framework können C ++ - Programmierer über einen dedizierten Namespace mit den APIs des Browsers kommunizieren. Und Rust bietet wasm-bindgen an, das als wechselseitige Brücke zwischen JavaScript und Rust sowie zwischen JavaScript und WebAssembly dient.

Darüber hinaus wird ein allgemeiner Vorschlag zum Umgang mit Bindungen an den Host geprüft. Nach der Fertigstellung bietet es eine Standardmethode für Sprachen, die in WebAssembly kompiliert werden, um mit Hosts zu interagieren. Die langfristige Strategie mit diesem Vorschlag umfasst auch Bindungen an Hosts, die keine Browser sind, aber Browserbindungen sind der kurzfristige, unmittelbare Anwendungsfall.

Debuggen und Profilieren von WebAssembly-Apps

Ein Bereich, in dem sich das WebAssembly-Tool noch im Anfangsstadium befindet, ist die Unterstützung für das Debuggen und Profiling. 

Bis zur Einführung von JavaScript-Quellkarten waren Sprachen, die mit JavaScript kompiliert wurden, oft schwer zu debuggen, da der ursprüngliche und kompilierte Code nicht einfach korreliert werden konnte. WebAssembly weist einige der gleichen Probleme auf: Wenn Sie Code in C schreiben und in WASM kompilieren, ist es schwierig, Korrelationen zwischen der Quelle und dem kompilierten Code herzustellen.

JavaScript-Quellkarten geben an, welche Zeilen im Quellcode welchen Regionen des kompilierten Codes entsprechen. Einige WebAssembly-Tools wie Emscripten können auch JavaScript-Quellzuordnungen für kompilierten Code ausgeben. Einer der langfristigen Pläne für WebAssembly ist ein Quellkartensystem, das über das hinausgeht, was in JavaScript verfügbar ist, sich jedoch noch in der Angebotsphase befindet.

Derzeit ist der direkteste Weg, WASM-Code in freier Wildbahn zu debuggen, die Verwendung der Debug-Konsole des Webbrowsers. Dieser Artikel bei WebAssemblyCode zeigt, wie Sie WASM-Code mit einer Quellzuordnung generieren, ihn den Debugging-Tools des Browsers zur Verfügung stellen und den Code schrittweise durchgehen. Beachten Sie, dass die beschriebenen Schritte von der Verwendung des emccTools zum Ausgeben des WASM abhängen. Möglicherweise müssen Sie die Schritte abhängig von Ihrer speziellen Toolchain ändern.