[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. Optionalwasm-optpass 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
@islandfunction 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:
- WasmTarget: https://grouptherapyorg.github.io/WasmTarget.jl/
- Therapy: https://grouptherapyorg.github.io/Therapy.jl/
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: