I really hate wasm, not because of the idea or concept but because it gets bloated.
The first idea was computation heavy algorithms to be written in a language like C/C++/Rust and to be compiled to wasm.
Now it gets marketed as something to write sandboxed code/compontents for every language to be consumed by a wasm runtime.
Then there is the problem with the types of wasm. While it was seen to be something run on the web/browser. Its types are way more similar to rusts. For example strings in JS are fundamentally UTF-16 while wasm/rust is utf-8.
We need to constantly convert between them. I always hoped that wasm would simply allow for faster code on the web not here is my program completly sandboxed from the outside world you cant interact with other programs on the same machine.
Well ... that kind of explains why nobody uses wasm.
Initially I fell for the hype too. Now it seems the number
of people using wasm, is mega-low. It's like the tiniest
ever fraction of javascript-knowing folks. And this will
probably never change either.
I guess it is time to conclude:
- wasm will remain a small niche. At the least for the, say,
close future. But probably forever.
For me, wasm is a godsend. I sure hope it doens't go away. I can write a reasonably complex GUI with Rust and egui and OpenGL and put it online without having to deal with browser/Javascript/TS nonsense. The only pain points for me, so far, are (1) network and local file access for which I had to write tiny amounts of wrapper JS (2) having to rewrite shaders for OpenGL ES and (3) executor gymnastics for manual cooperative scheduling of some background computations, apparently multithread support isn't quite there yet. Also it works perfectly fine under Firefox, Chromium and even on my cellular telephone (these things have browsers now!) with Vanadium and Firefox mobile.
Yes wasm is basically a rust thing at this point unfortunately. And if you want to write a wasi preview 0.2 component, you need a bunch of rust tooling to do it properly
This reads like the same problems as using Emscripten's embind for automatically generating C++ <=> JS bindings, and my advice would be "just don't do it".
It adds an incredible amount of complexity and bloat versus writing a proper hybrid C++/JS application where non-trivial work is happening in handwritten JS functions versus hopping across the JS/WASM boundary for every little setter/getter. It needs experience though to find just the right balance between what code should go on either side of the boundary.
Alternatively tunnel through a properly designed C API instead of trying to map C++ or Rust types directly to JS (e.g. don't attempt to pass complex C++/Rust objects across the boundary, there's simply too little overlap between the C++/Rust and JS type systems).
The automatic bindings approach makes much more sense for a C API than for a native API of a language with a huge 'semantic surface' like C++ or Rust.
Tangential: I decided to write a Wasm parser (more precisely, a decoder the the Wasm binary format) from scratch, as a means to learn both Wasm and Rust[0].
It was the first time I was writing this sort of thing, but I found the spec very clear and well-written.
Fun fact: I was surprised when the test from a toy parser surfaced a real regression in version 3 of the spec[1], released roughly 4 months before.
I made a couple 2D browser games a few years ago in various WASM languages. I used C++, Zig, Odin, and Rust.
(Including a game with online multiplayer! Though only the client, I did the server in TS ;)
Now a disclaimer, I experienced most of these languages for the first time during the jams, which biases me towards confusion and suffering. That being said, there was still a big gradient, and it does give us useful data on "how easy is it to get started with the basics and achieve basic tasks" (my games were like, 1970s level complexity).
Spent the last day of the C++ one dealing with a weird Emscripten bug. 12 hours left in the jam and suddenly the whole thing refused to compile, but only with Emscripten.
Spent most of the Zig jam trying to find up to date libraries and documentation. (Stuff changes fast apparently. This was 2024 though so maybe different now).
The Rust one was the most painful because I kept running into "I know what I want to do, and it's correct, and it works in every single other programming language, but rust is an authoritarian nanny state and won't let me."
(That's not WASM specific, I had similar problems when making native games in Rust. But WASM does make that aspect of the Rust experience worse, unless, I'm told, you go for one of the well supported WASM games libraries, in which case it should be relatively smooth.)
I found this too bad because overall Rust should have been the winner, in terms of cool language features. It's just a bad match for "yes I know what I'm doing and this over-cautious compiler case genuinely doesn't apply to me and there's no way to configure that so it actually lets you do your job". Also probably not ideal for game jams where dev speed and flexibility matter more than correctness.
(To beat a dead horse, my favorite part about the Rust jam was going into discord for help, getting even more absurd workarounds than GPT gave me, and then being called a bad person for not prioritizing memory safety on a game jam xD)
Zig was similarly suboptimal for game jams (though I imagine it would be fine for longer projects). Where I had 6 hours left and it was forcing me to think about what kind of division operator I wanted to use xD
Odin, I found surprisingly pleasant, even in the context of a very short jam. Very pleasant syntax. Nicest I've seen by far. (Well, I hear Jai is nice too, being Odin inspired, but no invite from Jon yet ;)
Odin's also very nice for game dev, being batteries included. For wasm there wasn't native support for game libraries at the time, but I found a GitHub repo that let you do it with a C wrapper.
Overall a fun and educational experience (and I definitely want to give Rust another go, in a less time sensitive context — it's the one language you can't just hope to wing it ;).
I did, I must admit, switch back to JS/TS and just use that for the last few games I made, because the truth is you're going to be writing it anyway for web games (unless you're using an engine or heavyweight library / toolchain), and the interop gave me more headaches than the nicer languages solved.
Depending on your scale or timeline, (or deep seated feelings about JavaScript!) WASM may be worth it for you though :)
I think most GC languages that compile to WASM don't use the built-in GC support in WASM, but just compile the GC to WASM also. Languages like Go, Java, C# have support for WASM.
The c-style interface of wasm is pretty limiting when designing higher level interfaces, which is why wasn-bindgen is required in the first place.
Luckily, Firefox is pushing an early proposal to expose all the web apis directly to wasm through a higher level interface based on the wasm component-model proposal.
> FWIW I prefer `futures::lock::Mutex` on std, or `async_lock::Mutex` under no_std.
Async mutexes in Rust have so many footguns that I've started to consider them a code smell. See for example the one the Oxide project ran into [1]. IME there are relatively few cases where it makes sense to want to await a mutex asynchronously, and approximately none where it makes sense to hold a mutex over a yield point, which is why a lot of people turn to async mutexes despite advice to the contrary [2]. They are essentially incompatible with structured concurrency, but Rust async in general really wants to be structured in order to be able to play nicely with the borrow checker.
`shadow-rs` [3] bears mentioning as a prebuilt way to do some of the build info collection mentioned later in the post.
Author of the article here! I've actually come to agree with you since writing that article. I'm actually not a fan of mutexes in general and miss having things like TVars from my Haskell days. Just to shout out a deadlock freedom project that I'm not involved in and haven't put in production, but would like to see more exploration in this direction: https://crates.io/crates/happylock
I will admit to being pretty ignorant. But wasm seems like a pretty big swing and a miss. Far too many edges cases and gotchas. It definitely does not “just work”. :(
It's because every 'programmer category' (game devs, backend devs, traditional web devs, ...) wants something different from WASM, and the early hype also didn't help.
For me WASM is "just another ISA" like x86 or ARM, and the web is "just another platform" like Windows, macOS or Linux.
All my hobby C/C++ projects (and some Zig projects) also automatically run in the browser, and 'distributing' a URL is much less painful than distributing native binaries or asking users to build the code themselves.
26 comments
[ 7.2 ms ] story [ 51.4 ms ] threadThe first idea was computation heavy algorithms to be written in a language like C/C++/Rust and to be compiled to wasm.
Now it gets marketed as something to write sandboxed code/compontents for every language to be consumed by a wasm runtime.
Then there is the problem with the types of wasm. While it was seen to be something run on the web/browser. Its types are way more similar to rusts. For example strings in JS are fundamentally UTF-16 while wasm/rust is utf-8.
We need to constantly convert between them. I always hoped that wasm would simply allow for faster code on the web not here is my program completly sandboxed from the outside world you cant interact with other programs on the same machine.
Initially I fell for the hype too. Now it seems the number of people using wasm, is mega-low. It's like the tiniest ever fraction of javascript-knowing folks. And this will probably never change either.
I guess it is time to conclude:
- wasm will remain a small niche. At the least for the, say, close future. But probably forever.
It adds an incredible amount of complexity and bloat versus writing a proper hybrid C++/JS application where non-trivial work is happening in handwritten JS functions versus hopping across the JS/WASM boundary for every little setter/getter. It needs experience though to find just the right balance between what code should go on either side of the boundary.
Alternatively tunnel through a properly designed C API instead of trying to map C++ or Rust types directly to JS (e.g. don't attempt to pass complex C++/Rust objects across the boundary, there's simply too little overlap between the C++/Rust and JS type systems).
The automatic bindings approach makes much more sense for a C API than for a native API of a language with a huge 'semantic surface' like C++ or Rust.
Very handy to update serde data structure and see all the typescript errors that after recompiling.
[0]: https://github.com/madonoharu/tsify
https://github.com/modelcontextprotocol/modelcontextprotocol...
https://github.com/modelcontextprotocol/rust-sdk/pull/183
It was the first time I was writing this sort of thing, but I found the spec very clear and well-written.
Fun fact: I was surprised when the test from a toy parser surfaced a real regression in version 3 of the spec[1], released roughly 4 months before.
[0] https://github.com/agis/wadec
[1] https://github.com/WebAssembly/spec/issues/2066
(Including a game with online multiplayer! Though only the client, I did the server in TS ;)
Now a disclaimer, I experienced most of these languages for the first time during the jams, which biases me towards confusion and suffering. That being said, there was still a big gradient, and it does give us useful data on "how easy is it to get started with the basics and achieve basic tasks" (my games were like, 1970s level complexity).
Spent the last day of the C++ one dealing with a weird Emscripten bug. 12 hours left in the jam and suddenly the whole thing refused to compile, but only with Emscripten.
Spent most of the Zig jam trying to find up to date libraries and documentation. (Stuff changes fast apparently. This was 2024 though so maybe different now).
The Rust one was the most painful because I kept running into "I know what I want to do, and it's correct, and it works in every single other programming language, but rust is an authoritarian nanny state and won't let me."
(That's not WASM specific, I had similar problems when making native games in Rust. But WASM does make that aspect of the Rust experience worse, unless, I'm told, you go for one of the well supported WASM games libraries, in which case it should be relatively smooth.)
I found this too bad because overall Rust should have been the winner, in terms of cool language features. It's just a bad match for "yes I know what I'm doing and this over-cautious compiler case genuinely doesn't apply to me and there's no way to configure that so it actually lets you do your job". Also probably not ideal for game jams where dev speed and flexibility matter more than correctness.
(To beat a dead horse, my favorite part about the Rust jam was going into discord for help, getting even more absurd workarounds than GPT gave me, and then being called a bad person for not prioritizing memory safety on a game jam xD)
Zig was similarly suboptimal for game jams (though I imagine it would be fine for longer projects). Where I had 6 hours left and it was forcing me to think about what kind of division operator I wanted to use xD
Odin, I found surprisingly pleasant, even in the context of a very short jam. Very pleasant syntax. Nicest I've seen by far. (Well, I hear Jai is nice too, being Odin inspired, but no invite from Jon yet ;)
Odin's also very nice for game dev, being batteries included. For wasm there wasn't native support for game libraries at the time, but I found a GitHub repo that let you do it with a C wrapper.
Overall a fun and educational experience (and I definitely want to give Rust another go, in a less time sensitive context — it's the one language you can't just hope to wing it ;).
I did, I must admit, switch back to JS/TS and just use that for the last few games I made, because the truth is you're going to be writing it anyway for web games (unless you're using an engine or heavyweight library / toolchain), and the interop gave me more headaches than the nicer languages solved.
Depending on your scale or timeline, (or deep seated feelings about JavaScript!) WASM may be worth it for you though :)
The c-style interface of wasm is pretty limiting when designing higher level interfaces, which is why wasn-bindgen is required in the first place.
Luckily, Firefox is pushing an early proposal to expose all the web apis directly to wasm through a higher level interface based on the wasm component-model proposal.
See https://hacks.mozilla.org/2026/02/making-webassembly-a-first...
Async mutexes in Rust have so many footguns that I've started to consider them a code smell. See for example the one the Oxide project ran into [1]. IME there are relatively few cases where it makes sense to want to await a mutex asynchronously, and approximately none where it makes sense to hold a mutex over a yield point, which is why a lot of people turn to async mutexes despite advice to the contrary [2]. They are essentially incompatible with structured concurrency, but Rust async in general really wants to be structured in order to be able to play nicely with the borrow checker.
`shadow-rs` [3] bears mentioning as a prebuilt way to do some of the build info collection mentioned later in the post.
[1]: https://rfd.shared.oxide.computer/rfd/0609 [2]: https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html#wh... [3]: https://docs.rs/shadow-rs/latest/shadow_rs/
This was one of the things that has put me off, and ergonomics are still a subset for Rust Roadmap 2026.
For me WASM is "just another ISA" like x86 or ARM, and the web is "just another platform" like Windows, macOS or Linux.
All my hobby C/C++ projects (and some Zig projects) also automatically run in the browser, and 'distributing' a URL is much less painful than distributing native binaries or asking users to build the code themselves.