Show HN: Bringing Guava, Commons CSV, and GEXF4J to the Browser via WASM

4 hours ago 2

Live demo: https://java-wasm-graphs-demo.vercel.app

Proof of concept for client-side graph processing using Java libraries (Guava, Commons CSV) compiled to WebAssembly via GraalVM.
Query geographical hierarchies (e.g., "Is Collo in Algeria?") entirely in the browser—no backend required.

Once the graph is built, the user can query it, asking questions like: Is Collo in Algeria?
The Java/Wasm runtime traverses the graph using Guava's graph APIs to determine relationships and returns the result to JavaScript.

var reachable = Graphs.reachableNodes(graph, "Collo").contains("Algeria");


Note: JS library graphology is decent. We did not really need to use Guava. Still, it has much needed data structures like RangeSet.

The following build both the frontend and .wasm/wasm.js files.

cd app npm run build:all npx -y serve dist/spa/

For just graph queries, JS libraries suffice. But for bringing Gephi, PDFBox, or complex solvers to the browser? That's where this shines.

Wasm allows us to use cool and battle-tested libraries (originally written for C++, Rust, or Java) in the browser/Node.

Imagine, constraint solvers like OptaPlanner/Timefold or Choco solver.

Imagine the possibilities.

Many libraries and frameworks support GraalVM Native Image.

The Java ecosystem has mature projects. Some cool examples:

Core libraries

Graph & visualization

Or any of Apache or Eclipse projects:

Component diagram

We use a worker to decouple UI rendering from computation, allowing the Java/Wasm runtime to operate independently and keep the UI interactive.

Workflow (notice languages used):

  • Web: Edit data using a data grid.

  • JS/Web page: Generate a CSV text describing geographical or group hierarchies: what subregion is part of what region. For example:

Skikda, Algeria Collo, Skikda
  • JS: Submit the query and CSV data to the Worker.

  • JS/Wasm/Java: Listen to messages/queries.

  • Java: Parse the CSV.

  • Java: Build the graph.

  • Java: Traverse the graph to answer the query.

  • Java: Serialize the graph to GEXF.

  • Java/Wasm/JS: Reply with the graph and answer.

  • JS: Update the UI to draw the graph and answer.

Tested with:

  • Kubuntu 24.04 x64

  • Node 22 / npm 11

  • GraalVM 26 Early Access (sdk install java 26.ea.13-graal)

  • GraalVM 25 (sdk install java 25.0.1-graal)

  • Binaryen version 124

  • Chrome version 141

  • Bundle size (non-debug): 10 MB raw / 4.3 MB gzip / 3.4 MB Brotli.
gzip -k -9 GeoHierarchy.js.wasm brotli -q 11 GeoHierarchy.js.wasm
  • The wasm module is loaded asynchronously, which means it's a bit involved to know when the worker is ready. You can't just start calling postMessage as soon as you create it.
    However, you can simply listen to a "READY" even that the worker emits once it's ready.
    That's what I did here.

  • DataCloneError when trying to post a JSObject to BroadcastChannel since it violates structure clone algorithm's rules: apparently, GraalVM wraps objects with proxies/functions.
    Tried JSON.parse(JSON.stringify(theObject)) but the result was just {}.
    Ended up using Gson to convert it to a string before posting to self (Web Worker) or BroadcastChannel.

Stuff I tried but failed to compile as Wasm even if they compile as native binaries just fine:

  • Quarkus and Timefold AI

  • PlantUML ELK (which uses Eclipse Layout Kernel)

    <dependency> <groupId>net.sourceforge.plantuml</groupId> <artifactId>plantuml-epl</artifactId> <version>1.2025.9</version> </dependency>"><!-- https://mvnrepository.com/artifact/net.sourceforge.plantuml/plantuml-epl --> <dependency> <groupId>net.sourceforge.plantuml</groupId> <artifactId>plantuml-epl</artifactId> <version>1.2025.9</version> </dependency>

WTFPL - Abdeldjalil Hebal

Read Entire Article