A WebImage artifact compiles JVM bytecode to a JavaScript loader plus a WASM module. To run an existing WASM or
WASI binary, see WebAssembly.
Prerequisites
- Binaryen 119 or later, with
wasm-asonPATHat build time. - Code that meets the Native Image requirements: reachability metadata for reflection, resources and proxies; no native dependencies.
- A host with WASM exception handling (and WASM GC for
wasm-gc): Node.js 25+ or a current browser.
The deployed bundle needs neither Elide nor Binaryen.
Build a complete project
hello-wasm/
elide.pkl
src/main/java/Hello.javapublic 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 buildElide builds app-jar, then compiles it to web. name is the basename without .js or .wasm;
optimization = "b" is quick-build mode. Output goes to .dev/artifacts/native-image/:
| File | Purpose |
|---|---|
hello.js | JavaScript loader and entrypoint. |
hello.js.wasm | WASM module, loaded by hello.js. |
hello.js.wat | WASM text form, for inspection. |
hello.js.map | Source map for the loader, when sourceMap = true. |
Deploy hello.js and hello.js.wasm together. Kotlin and other JVM languages work the same way once packaged in a
JAR. A cache hit restores the whole bundle; turning sourceMap off removes the old .js.map.
Choose a backend and host
| Property | Value | Meaning |
|---|---|---|
backend | "wasm-gc" (default) | Uses the host’s WASM garbage collector. |
backend | "wasm-lm" | Uses a garbage collector in linear memory; still needs the loader, not a WASI binary. |
runtime | "generic" (default) | Loader supports browsers and Node. |
runtime | "browser" | Loader specialized for browsers. |
runtime | "node" | Loader specialized for Node-compatible APIs. |
autoRun | true (default) | Starts the program when the loader loads; false leaves startup to the embedding page. |
sourceMap | false (default) | true emits hello.js.map. |
An entrypoint is required even with autoRun = false. No runtime targets Cloudflare Workers, Fastly Compute or
WASI. Shared fields (from, entrypoint, moduleName, options) are listed under
Native Image. A WebImage cannot be the input to a
container artifact.
Target guides: Browser WASM and Edge WASM.
Run on a backend host
With runtime = "generic" or "node":
node .dev/artifacts/native-image/hello.jsHello from WebImageRun in a browser
With runtime = "browser" or "generic" and autoRun = true, put this index.html in
.dev/artifacts/native-image/:
<!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-imageOpen http://localhost:8000/; the output appears in the browser console. file:// URLs do not work.
Compiler options
The artifact’s options block takes the Native Image compiler options;
which apply depends on the backend. Two cases specific to WebImage:
options.driverMode = "external"usesnative-imagefromGRAALVM_HOMEorJAVA_HOME; that installation must support the WebAssembly backends.-H:EntryPointsConfig=config/entrypoints.jsoninoptions.flagssets entry points; the path is relative to the project root, and editing the file triggers a rebuild.
Compile without a project manifest
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 HelloBundles are written to the current directory. A NativeImage artifact with --tool:wasm-gc or --tool:wasm-lm in
options.flags still builds. To migrate it, change the class to WebImage, drop the flag and any type, and set
backend.
Troubleshooting
| Symptom | Fix |
|---|---|
wasm-as not found | Install Binaryen and put it on the build’s PATH. |
| External driver rejects the WebAssembly backend | Point GRAALVM_HOME or JAVA_HOME at an installation whose native-image supports it, or use driverMode = "embedded". |
| Conflicting raw options | Remove backend, runtime, startup and source-map flags; use the typed properties. Do not override Backend or the launcher property. |
| Host rejects WASM instructions | Use a host with exception handling and, for wasm-gc, WASM GC. |
| Browser cannot load the module | Serve loader and module together over HTTP; check the requested URL. |
elide run hello.js.wasm reports missing imports | Run hello.js instead; the module needs its loader. |