[ANN] (Experimental) WasmTarget.jl & Therapy.jl: Julia-to-WebAssembly compiler, with a full-stack signals framework built on it

[ANN] (Experimental) WasmTarget.jl & Therapy.jl: Julia-to-WebAssembly compiler, with a full-stack signals framework built on it

I’m “announcing” two new packages, both registered in General. They might be usable, might not. The main goal is feedback from actual subject-matter experts, and to put these in front of anyone who wants to play around with them, like I do.

WasmTarget.jl: compiles real Julia functions to WebAssembly. It reads Julia’s fully-inferred IR (Base.code_typed()) and emits WasmGC bytecode directly. Targets modern WasmGC types (struct, array, externref) so Vector{T} and user structs map naturally instead of fighting linear memory.

  • Current scope: 176 Julia functions compile and produce correct E2E results across Int32 / Int64 / UInt32 / UInt64 / Float32 / Float64. 127 are native paths (real Base IR), and 48 are overlay reimplementations for IR tangled with GC internals or libm foreigncalls. This is the same pattern CUDA.jl / GPUCompiler.jl uses. 2409 tests passing. Optional wasm-opt pass yields ~85% size reduction with no behavioral regressions.
using WasmTarget: compile_multi

square(x::Float64)::Float64 = x * x
cube(x::Float64)::Float64   = x * square(x)

# Both functions in one WASM module. `cube` calls `square` inside the binary.
bytes = compile_multi([(square, (Float64,)), (cube, (Float64,))])
write("cubic.wasm", bytes)

Therapy.jl: a full-stack web framework with fine-grained signals (in the SolidJS / Leptos sense) and Astro-inspired islands architecture. Components are written in a JSX-style call syntax like Div(Button(...), Span(...)), but it’s plain Julia function composition, no macro or template DSL.

  • Islands: most of the page is static HTML, and only the parts that actually need reactivity ship JS / WASM. With Therapy each @island function compiles to its own per-island WASM module via WasmTarget. You write SSR layouts and reactive components in plain Julia; the build emits static HTML plus tiny WASM modules (1 to 12 KB per island) that hydrate on demand.
using Therapy: Div, Button, Span
using Therapy: @island, create_signal, create_memo, create_effect, js

@island function InteractiveCounter(; initial::Int = 0)
    count, set_count = create_signal(initial)
    doubled = create_memo(() -> count() * 2)
    create_effect(() -> js("console.log('count:', $1, 'doubled:', $2)", count(), doubled()))

    return Div(
        Div(
            Button(:on_click => () -> set_count(count() - 1), "-"),
            Span(count),
            Button(:on_click => () -> set_count(count() + 1), "+")
        ),
        Span("doubled ", Span(doubled))
    )
end

Both docs sites dogfood Therapy itself:

Both repos were built iteratively with LLM coding agents, so if you’ve shipped real compilers or built real web frameworks and have any interest in a real Julia to Wasm story, I’d love any and all feedback from those of you with much more domain knowledge than me.

Repos:

Neat!

Is this related to the previous (I think abandoned?) work some people did on WebAssemblyCompiler ? The ability to show DiffEq and (modified) Makie running in the browser always made for impressive demo material for Julia presentations.

Not really. That project was before WasmGC and didn’t take advantage of any of the garbage collection features now native to Wasm

It looks great as it clearly works , but it might feel more comfortable if it is (more) hand-written with carefully crafted details.
Some compiler tasks nowadays might work well with the generative AI, especially for some X-to-Y transpiler when there is at least one existing de facto approach to execute X and collect results. However, if a human cannot control details, should we use some mechanisms to make AI-powered compiler work more reliably, like domain modeling-based tests (split things into orthogonal and complete bases/cases and test against every basis so any composition works)?

A lot of projects only exist because it is a lot of work to do it by hand, and nobody is willing to spend the time and effort do so. I think if nobody wants to do it by hand, then AI is the second best thing.

edit: removed poorly worded comment

Lol, besides being just a generally weak argument against someone giving constructive feedback, it’s particularly funny that you should say that to @thautwarm of all people. You should take a look at Taine’s history before saying that.

It wasn’t a personal comment, it was a comment about putting in the work to bring julia → webassembly. I mean that others could have done it, but it never happened. Because it is a lot of work

I absolutely agree with you which is why I am seeking feedback from people who actually know a bit about Wasm or the Julia compiler. I am hoping that I can help in various ways but I genuinely don’t have enough compiler knowledge to do much on my own without agents

@thautwarm Also, if you have any libraries in the Julia world or adjacent to it, that you could point me to which demonstrate the testing design you are talking about, I would love to look more into this!