Zum Inhalt springen

WebImage: JVM zu WebAssembly

Java oder Kotlin mit dem WebImage-Artefakt von Elide zu einem WebAssembly-Modul mit JavaScript-Loader kompilieren: Voraussetzungen, Backends, Hosts und Compiler-Optionen.

Auf dieser Seite

Ein WebImage-Artefakt kompiliert JVM-Bytecode zu einem JavaScript-Loader plus einem WASM-Modul. Wie Sie ein vorhandenes WASM- oder WASI-Binary ausführen, beschreibt WebAssembly.

Voraussetzungen

  • Binaryen 119 oder neuer, mit wasm-as auf dem PATH zur Build-Zeit.
  • Code, der die Anforderungen von Native Image erfüllt: Reachability-Metadaten für Reflection, Ressourcen und Proxys; keine nativen Abhängigkeiten.
  • Ein Host mit WASM-Ausnahmebehandlung (und WASM GC für wasm-gc): Node.js 25+ oder ein aktueller Browser.

Das ausgelieferte Bundle braucht weder Elide noch Binaryen.

Ein vollständiges Projekt bauen

hello-wasm/
  elide.pkl
  src/main/java/Hello.java
public class Hello {
  public static void main(String[] args) {
    System.out.println("Hello from WebImage");
  }
}
amends "elide:project.pkl"
import "elide:Jvm.pkl" as jvm
import "elide:NativeImage.pkl" as nativeImage

name = "hello-wasm"

artifacts {
  ["app-jar"] = new jvm.Jar {
    sources { "main" }
  }
  ["web"] = new nativeImage.WebImage {
    from { "app-jar" }
    name = "hello"
    entrypoint = "Hello"
    backend = "wasm-gc"
    runtime = "generic"
    autoRun = true
    sourceMap = false
    options {
      optimization = "b"
    }
  }
}
elide build

Elide baut app-jar und kompiliert es dann zu web. name ist der Basisname ohne .js oder .wasm; optimization = "b" ist der Schnell-Build-Modus. Die Ausgabe landet in .dev/artifacts/native-image/:

DateiZweck
hello.jsJavaScript-Loader und Einstiegspunkt.
hello.js.wasmWASM-Modul, von hello.js geladen.
hello.js.watWASM-Textform, zur Inspektion.
hello.js.mapSource Map für den Loader, bei sourceMap = true.

Liefern Sie hello.js und hello.js.wasm zusammen aus. Kotlin und andere JVM-Sprachen funktionieren genauso, sobald sie in einem JAR verpackt sind. Ein Cache-Treffer stellt das ganze Bundle wieder her; wird sourceMap abgeschaltet, verschwindet die alte .js.map.

Backend und Host wählen

EigenschaftWertBedeutung
backend"wasm-gc" (Standard)Verwendet den WASM-Garbage-Collector des Hosts.
backend"wasm-lm"Verwendet einen Garbage Collector im linearen Speicher; braucht trotzdem den Loader, kein WASI-Binary.
runtime"generic" (Standard)Der Loader unterstützt Browser und Node.
runtime"browser"Loader speziell für Browser.
runtime"node"Loader speziell für Node-kompatible APIs.
autoRuntrue (Standard)Startet das Programm, sobald der Loader geladen ist; false überlässt den Start der einbettenden Seite.
sourceMapfalse (Standard)true erzeugt hello.js.map.

Ein Einstiegspunkt ist auch mit autoRun = false erforderlich. Kein runtime zielt auf Cloudflare Workers, Fastly Compute oder WASI. Gemeinsame Felder (from, entrypoint, moduleName, options) sind unter Native Image aufgeführt. Ein WebImage kann nicht die Eingabe eines Container-Artefakts sein.

Zielanleitungen: Browser WASM und Edge WASM.

Auf einem Backend-Host ausführen

Mit runtime = "generic" oder "node":

node .dev/artifacts/native-image/hello.js
Hello from WebImage

Im Browser ausführen

Legen Sie bei runtime = "browser" oder "generic" und autoRun = true diese index.html in .dev/artifacts/native-image/ ab:

<!doctype html>
<html lang="en">
  <meta charset="utf-8" />
  <title>Hello WebImage</title>
  <body>
    <p>Open the browser console to see the application output.</p>
    <script src="./hello.js"></script>
  </body>
</html>
elide dev --no-tui --port 8000 .dev/artifacts/native-image

Öffnen Sie http://localhost:8000/; die Ausgabe erscheint in der Browserkonsole. file://-URLs funktionieren nicht.

Compiler-Optionen

Der Block options des Artefakts nimmt die Compiler-Optionen von Native Image an; welche davon greifen, hängt vom Backend ab. Zwei Fälle betreffen nur WebImage:

  • options.driverMode = "external" verwendet native-image aus GRAALVM_HOME oder JAVA_HOME; diese Installation muss die WebAssembly-Backends unterstützen.
  • -H:EntryPointsConfig=config/entrypoints.json in options.flags legt Einstiegspunkte fest; der Pfad ist relativ zum Projektwurzelverzeichnis, und eine Änderung der Datei löst einen neuen Build aus.

Ohne Projektmanifest kompilieren

elide javac -- -d classes src/main/java/Hello.java
elide native-image -- --tool:wasm-gc -Ob -cp classes -o hello Hello
elide native-image -- --tool:wasm-lm -Ob -cp classes -o hello-lm Hello

Die Bundles landen im aktuellen Verzeichnis. Ein NativeImage-Artefakt mit --tool:wasm-gc oder --tool:wasm-lm in options.flags baut weiterhin. Zur Migration ändern Sie die Klasse in WebImage, entfernen das Flag und ein etwaiges type und setzen backend.

Fehlerbehebung

SymptomLösung
wasm-as nicht gefundenInstallieren Sie Binaryen und nehmen Sie es in den PATH des Builds auf.
Der externe Treiber lehnt das WebAssembly-Backend abLassen Sie GRAALVM_HOME oder JAVA_HOME auf eine Installation zeigen, deren native-image es unterstützt, oder verwenden Sie driverMode = "embedded".
Widersprüchliche RohoptionenEntfernen Sie Flags für Backend, Laufzeit, Start und Source Map; verwenden Sie die typisierten Eigenschaften. Überschreiben Sie weder Backend noch die Launcher-Eigenschaft.
Der Host lehnt WASM-Instruktionen abVerwenden Sie einen Host mit Ausnahmebehandlung und, für wasm-gc, WASM GC.
Der Browser kann das Modul nicht ladenLiefern Sie Loader und Modul gemeinsam über HTTP aus; prüfen Sie die angeforderte URL.
elide run hello.js.wasm meldet fehlende ImporteFühren Sie stattdessen hello.js aus; das Modul braucht seinen Loader.

War diese Seite hilfreich?