Things are slowly getting better in wasm world.
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...
Tbh, apart from the demonstrated performance improvement for string marshalling I really fail to see how integrating the WASM Component Model into the browser is a good thing. It's a lot of complexity for a single niche use case (less overhead for string conversion - but passing tons of strings across the boundary is really only needed for one use case: when doing a 1:1 mapping of the DOM API).
I really doubt that web APIs like WebGPU or WebGL would see similar performance improvements, and it's unclear how the much more critical performance problems for accessing WebGPU from WASM would be solved by the WASM Component Model (e.g. WebGPU maps WGPUBuffer content into separate JS ArrayBuffer objects which cannot be accessed directly from WASM without copying the data in and out of the WASM heap).
1. It’s not just one use case. I’m working on a product which makes heavy use of indexeddb from JavaScript for offline access. We’d love to rewrite this code into rust & webassembly, but performance might get worse if we did so because so many ffi calls would be made, marshalling strings from wasm -> js -> c++ (browser). Calling indexeddb from wasm directly would be way more efficient for us, too!
2. It’s horrible needing so much JS glue code to do anything in wasm. I know most people don’t look at it, but JS glue code is a total waste of everyone’s time when you’re using wasm. It’s complex to generate. It can be buggy. It needs to be downloaded and parsed by the browser. And it’s slow. Like, it’s pure overhead. There’s simply no reason that this glue needs to exist at all. Wasm should be able to just talk to the browser directly.
I’d love to be able to have a <script src=foo.wasm> on my page and make websites like that. JS is a great language, but there’s no reason to make developers bridge everything through JS from other languages. Nobody should be required to learn and use JavaScript to make web software using webassembly.
> Wasm should be able to just talk to the browser directly.
Web APIs are designed for JavaScript, though, which makes this hard. For example, APIs that receive or return JS Typed Arrays, or objects with flags, etc. - wasm can't operate on those things.
You can add a complete new set of APIs which are lower-level, but that would be a lot of new surface area and a lot of new security risk. NaCl did this back in the day, and WASI is another option that would have similar concerns.
There might be a middle ground with some automatic conversion between JS objects and wasm. Say that when a Web API returns a Typed Array, it would be copied into wasm's linear memory. But that copy may make this actually slower than JS.
Another option is to give wasm a way to operate on JS objects without copying. Wasm has GC support now so that is possible! But it would not easily help non-GC languages like Rust and C++.
Anyhow, these are the sort of reasons that previous proposals here didn't pan out, like Wasm Interface Types and Wasm WebIDL bindings. But hopefully we can improve things here!
At least the DOM APIs are ostensibly designed to work in multiple languages, and are used by XML parsers in many languages.
Some of the newer Web APIs would be difficult to port. But the majority of APIs have quite straight forward equivalents in any language with a defined struct type (which you admittedly do have to define for WASM, and whether that interface would end up being zero-copy would change depending on the language you are compiling to wasm)
There is no solution without tradeoffs here, but the only reason JS-glue-code is winning out is because the complexity is moved from browsers to each language or framework that wants to work with wasm
> There is no solution without tradeoffs here, but the only reason JS-glue-code is winning out is because the complexity is moved from browsers to each language or framework that wants to work with wasm
Correct, but this is has been one of wasm's guiding principles since the start: move complexity from browsers to toolchains.
Wasm is simple to optimize in browsers, far simpler than JavaScript. It does require a lot more toolchain work! But that avoids browser exploits.
This is the reason we don't support the wasm text format in browsers, or wasm-ld, or wasm-opt. All those things would make toolchains easier to develop.
You are right that this sometimes causes duplicate effort among toolchains, each one needing to do the same thing, and that is annoying. But we could also share that effort, and we already do in things like LLVM, wasm-ld, wasm-opt, etc.
Maybe we could share the effort of making JS bindings as well. In fact there is a JS polyfill for the component model, which does exactly that.
It's not just about string performance, it's about making wasm a first class experience on the web. That includes performance improvements - because you don't need to wake up the js engine - but it's a lot more than that. Including much better dev-ex, which is not great as you can see in the OP.
It would also enable combining different languages with high-level interfaces rather than having to drop down to c-style interfaces for everything.
> Including much better dev-ex, which is not great as you can see in the OP.
IMHO the developer experience should be provided by compiler toolchains like Emscripten or the Rust compiler, and by their (standard) libraries. E.g. keep the complexity out of the browser, the right place for binding-layer complexity is the toolchains and at compile time. The browser is already complex enough as it is and should be radically stripped down instead instead of throwing more stuff onto the pile.
Web APIs are designed from the ground up for Javascript, and no amount of 'hidden magic' can change that. The component model just moves the binding shim to a place inside the browser where it isn't accessible, so it will be even harder to investigate and fix performance problems.
The dev-ex issues largely occur at the boundaries between environments. In the browser, that's often a JS-Rust boundary or a JS-C++ boundary. On embedded runtimes, it could be a Go-Rust boundary, or a Zig-Python boundary. To bridge every possible X-Y boundary for N different environments, you need N^2 different glue systems.
You're probably already thinking "obviously we just need a hub-and-spoke architecture where there's a common intermediate representation for all these types". That kind of architecture means that each environment only has to worry about conversions to and from the common representation, then you can connect any environment to any other environment, and you only need 2N glue systems instead of N^2. Effectively, you'd be formalizing the prior system of bespoke glue code generation into a standardized interface for interoperation.
That's the component model.
> "obviously we just need a hub-and-spoke architecture where there's a common intermediate representation for all these types"
I'm perfectly happy with integers and floats as common interface types (native ABIs also only use integers and floats: pointers are integer-indices into memory, and struct offsets need to be implicitly known and compiled into the caller and callee).
The WASM Component Model looks like a throwback to the 1990s when component object models where all the rage (COM, CORBA, and whatnot).
> I'm perfectly happy with integers and floats as common interface types
Most people at least want strings too. And once you add strings, you need to make sure the format is correct (JS uses UTF-16, C uses NULL-termination, etc). So even if you don't allow a complex object model, you would still need N^2 glue systems just for strings.
Then you might as well add arrays too.
Before you know it, you end up with the component model.
...all way too high level for my taste and those problems are not WASM specific yet still have been solved outside WASM via operating-system/platform ABI conventions which compilers and 'user code' has to adhere to without requiring a 'component model'.
Some operating systems might want their strings as UTF-8 encoded, some as UTF-16. It's the job of the caller to provide the strings in the right format before calling the OS function. In the end it's up to the caller and callee to agree on a format for string data. There is no 'middleman' or canonical standard format needed, just an agreement between a specific caller and callee.
The good and important part of such an agreement is that it is unopinionated. As long as caller and callee agree, it's totally fine to pass zero-terminated bytes, other callers and callees might find a pointer/size pair better. This sort of agreement also needs to happen when calling between native Rust and C code (or calling between any language for that matter). My C code might even prefer to receive string data as pointer/size pairs instead of zero-terminated bytes when all my string-processing code is built on top of strings as pointer/size pairs (e.g. apart from string literals there is not a single feature in the C language which dictates that strings are zero-terminated bags of bytes - it's mostly just of convention of the ancient C stdlib functions).
IMHO the WASM Component Model is solving a problem that just isn't all that relevant in practice. System ABIs / calling conventions don't need a 'component model' and so shouldn't WASM.
Luckily, the CM exists as a well-decoupled layer on top of core modules, which are just basic numeric types. So people can pretty easily just ignore the whole thing if they don't like it.
But for the other 99% of devs who just want to exchange strings across various language boundaries without quadratic glue complexity, we have the CM.
How would a compiler toolchain ship a debugger for webassembly? It’s kind of impossible. The only place for a debugger is inside the browser. Just like we do now with dev tools, JavaScript, typescript and webassembly languages.
> The browser is already complex enough as it is and should be radically stripped down
I’d love this too, but I think this ship has sailed. I think the web’s cardinal sin is trying to be a document platform and an application platform the same time. If I could wave a magic wand, I’d split those two used cases back out. Documents shouldn’t need JavaScript. They definitely don’t need wasm. And applications probably shouldn’t have the URL bar and back and forward buttons. Navigation should be up to the developers themselves. If apps were invented today, they should probably be done in pure wasm.
> Web APIs are designed from the ground up for Javascript
Web APIs are already almost all bridged into rust via websys. The APIs are more awkward than we’d like. But they all work today.
> How would a compiler toolchain ship a debugger for webassembly?
You can integrate external debuggers, like Uno documents here:
https://platform.uno/docs/articles/debugging-wasm.html
I assume that uses some browser extension, but I didn't look into the details.
You can also use an extension to provide additional debugging capability in the browser:
FWIW, it's possible to setup an IDE-like debugging environment with VSCode and a couple of plugins [1]. E.g. I can press F5 in VSCode, this starts the debuggee in Chrome and I can step-debug in VSCode exactly like debugging a native program, and it's even possible to seamlessly step into JS and back. And it's actually starting faster into a debug session than a native macOS UI program via lldb.
Inside the browser hardly matters if it isn't maintained, Google has done almost nothing to their DWARF debugging tooling since it was introduced as beta a few years ago.
> Google has done almost nothing to their DWARF debugging tooling since it was introduced as beta a few years ago
WASM DWARF debugging works perfectly fine though?
The 'debugger half' just moved from Chrome into a VSCode debug adapter extension where debugging is much more comfortable than in the browser:
https://marketplace.visualstudio.com/items?itemName=ms-vscod...
I use that all the time when working on web-platform specific code, with this extension WASM debugging in VSCode feels just like native debugging (it actually feels snappier on macOS than debugging a native macOS exe via LLDB).
More like it mostly works.
...'mostly works' describes pretty much every debugging experience outside Visual Studio. But I really can't complain, I've set up 'F5-debugging' in VSCode, pressing F5 starts a local web server, starts Chrome with the debuggee, and starts a remote debug session in VSCode and stops at the first breakpoint (and interestingly all this happens 'immediately', while debugging a native Cocoa macOS app via LLDB easily takes 5 to 10 seconds until the first breakpoint is reached).
TL;DR: It works just fine (early versions of the DWARF extension had problems catching 'early breakpoints' but that had been fixed towards the end of 2024.
> ... I really fail to see how integrating the WASM Component Model into the browser is a good thing.
One of the common (mis-)understandings about WASM when it was released, was people could write web applications "in any language" that could output WASM. (LLVM based things as an example)
That was clear over-selling of WASM, as in reality people still needed to additionally learn JS/TS to make things work.
So for the many backend devs who completely abhor JS/TS (there are many), trying out WASM and then finding it was bullshit has not been positive.
If WASM is made a first class browser citizen, and the requirement for JS/TS truly goes away, then I'd expect a lot of positive web application development to happen by those experienced devs who abhor JS/TS.
At being said, that viewpoint is from prior to AI becoming reasonably capable. That may change the balance of things somewhat (tbd).
https://moq.dev/blog/to-wasm/ is relevant i think