11 ms·
When Is WebAssembly Going to Get DOM Support?
- baudaux 1y agoI am adding a WASI runtime (0.1 and 0.2) in https://exaequos.com https://exaequos.com, an OS running in the web browser. What would be a good DOM api ?
- jauntywundrkind 1y agoLaw of question marks on headlines holds here: no / never seems to be the answer. Article l also discussed ref types, which do exist and do provide... Something. Some ability to at least refer to host objects. It's not clear what that enables or what it's limitstions are. Definitely some feeling of being rug-pulled in the shift here. It felt like there was a plan for good integration, but fast forward half a decade+ and there's been so so much progress and integration but it's still so unclear how WebAssembly is going to alloy the web, seems like we have reams of generated glue code doing so much work to bridge systems. Very happy that Dan at least checked in here, with a state of the wasm for web people type post. It's been years of waiting and wondering, and I've been keeping my own tabs somewhat through twists and turns but having some historical artifact, some point in time recap to go look at like this: it's really crucial for the health of a community to have some check-ins with the world, to let people know what to expect. Particularly for the web, wasm has really needed an update State of the Web WebAssmebly. I wish I felt a little better though! Jco is amazing but running a js engine in wasm to be able to use wasm-components is gnarly as hell. Maybe by 2030 wasm & wasm-components will be doing well enough that browsers will finally rejoin the party & start implementing new.
- weinzierl 1y ago"Definitely some feeling of being rug-pulled in the shift here." Definitely feeling rug-pulled. What I think all the people that hark on the "Don't worry, going through JS is good enough for you." are missing is the subtext of their message. They might objectively be right, but in the end what they are saying is that they are content with WASM being a second class citizen in the web world. This might be fine for everyone needing a quick and dirty solution now, but it is not the kind of narrative that draws in smart people to support an ecosystem in the long run. When you bet, you bet on the rider and not the domestique.
- flohofwoe 1y ago> that they are content with WASM being a second class citizen in the web world Tbh, most of the ideas so far to enable more direct access of Javascript APIs from WASM have a good chance of ruining WASM with pointless complexity. Keeping those two worlds separate, but making sure that 'raw' calls between WASM and JS are as fast as they can be (which they are) is really the best longterm solution. I think what people need to understand is that the idea of having 'pure' WASM browser applications which don't involve a single line of Javascript is a pipe dream. There will always be some sort of JS glue code, it might be generated and you don't need to directly deal with it, but it will still be there, and that's simply because web APIs are first and foremost designed for usage from Javascript. Some web APIs have started to 'appease' WASM more by adding 'garbage free' function overloads, which IMHO is a good thing because it may help to reduce overhead on the JS side, but this takes time and effort to be implemented in all browser (and most importantly, a will by mostly "JS-centric" web people to add such helper functions which mostly only benefit WASM).
- Spivak 1y agoWouldn't the path forward be that the browser acts more like a kernel with a syscall interface which both V8 and WASM use? You wouldn't access "Web APIs" from WASM because those would be written in JS but you get access to the same primitives used to implement the JS API. Sure, probably equally a pipedream but if there was any serious effort to make WASM a first class citizen in the browser it would probably be something like this rather than a crappy FFI to JS which has to obey JS semantics and deal with JS types.
- hoodchatham 1y agoReference types makes wasm/js interoperability way cleaner and easier. wasm-gc added a way to test a function pointer for whether it will trap or not. And JSPI is a standard since April and available in Chrome >= 137. I think JSPI is the greatest step forward for webassembly in the browser ever. Just need Firefox and Safari to implement it...
- jauntywundrkind 1y agoI'd really love a deep dive on what reference types enable and what limitations they have. Why are reference types not an end-all be-all "When is WebAssembly Going to Get DOM Support?" 'we have them now' answer?
- dfabulich 1y agoI think the easiest way to explain reference types is to contrast it with how we used to do it. WASM strings aren't JS strings; they're byte arrays. (WASM only knows about bytes, numbers (integers/floats), arrays, functions, and modules.) In the old days, to pass a JS string to WASM, you'd first have to serialize the JS string to a byte array (with the JS TextEncoder API, usually), and then copy the byte array into WASM, byte by byte. That took two O(n) steps, one to serialize to a byte array, and another to copy the byte array. Well, now, you can serialize the JS string to a byte array and then transmit it by reference to WASM, saving you a copy step. You still have one O(n) step to serialize the string to a byte array, but at least you only have to do it once, amirite? If you want your WASM to call `document.createElement("div")`, you can pass `document` and `createElement` by reference from JS to WASM, then have WASM create an array `['d', 'i', 'v']`, and send all of those back to JS, where the JS will convert the array back into a JS string and then call `createElement.call(document, "div")`. It's better, certainly, but it's never going to be as fast as just calling `document.createElement("div")` in JS, not as long as `createElement` requires a JS string instead of a byte array. The proper fix would be to define a whole new "low-level DOM API", which would work exclusively with byte arrays. That's what we're probably never going to get, because it would require all of the browser vendors (Apple, Google, Microsoft, and Mozilla) to standardize on a new thing, in the hopes that it was fast enough to be worth their trouble. Today, they don't even want to discuss it; they think their time is better spent making existing web apps faster than making a new thing from scratch that ought to be faster, if only a multi-year (decade??) effort comes to fruition.
- sfvisser 1y agoWe use WASM quite a bit for embedding a ton of Rust code with very company specific domain code into our web frontend. Pretty cool, because now your backend and frontend can share all kinds of logic without endless network calls. But it’s safe to say that the interaction layer between the two is extremely painful. We have nicely modeled type-safe code in both the Rust and TypeScript world and an extremely janky layer in between. You need a lot of inherently slow and unsafe glue code to make anything work. Part is WASM related, part of it wasm-bindgen. What were they thinking? I’ve read that WASM isn’t designed with this purpose in mind to go back and forth over the boundary often. That it fits the purpose more of heaving longer running compute in the background and bring over some chunk of data in the end. Why create a generic bytecode execution platform and limit the use case so much? Not everyone is building an in-browser crypto miner. The whole WASM story is confusing to me.
- BlackFly 1y agoMy reading of it is that the people furthering WASM aren't really associated with just browsers anymore and they are building a whole new VM ecosystem that the browser people aren't interested in. This is just my take since I am not internal to those organizations. But you have the whole web assembly component model and browsers just do not seem interested in picking that up at all. So on the one side you have organizations that definitely don't want to easily give network/filesystem/etc. access to code and on the other side you have people wanting it to be easier to get this access. The browser is the main driving force for WASM, as I see it, because outside of the browser the need for sandboxing is limited to plugins (where LUA often gets used) since otherwise you can run a binary or a docker container. So WASM doesn't really have much impetus to improve beyond compute.
- boomskats 1y ago> So on the one side you have organizations that definitely don't want to easily give network/filesystem/etc. access to code and on the other side you have people wanting it to be easier to get this access I don't think this is entirely fair or accurate. This isn't how Wasm runtimes work. Making it possible for the sandbox to explicitly request specific resource access is not quite the same thing as what you're implying here. > The browser is the main driving force for WASM, as I see it This hasn't been the case for a while. In your first paragraph you yourself say that 'the people furthering WASM are [...] building a whole new VM ecosystem that the browser people aren't interested in' - if that's the case, how can the browser be the main driving force for Wasm? It's true, though, that there's verey little revenue in browser-based Wasm. There is revenue in enterprise compute. > because outside of the browser the need for sandboxing is limited to plugins (where LUA often gets used) since otherwise you can run a binary or a docker container Not exactly true when you consider that docker containers are orders of magnitude bigger, slower to mirror and start up, require architecture specific binaries, are not great at actually 'containing' fallout from insecure code, supply chain vulns, etc.. The potential benefits to enterprise orgs that ship thousands of multi-gig docker containers a week with microservices architectures that just run simple business logic, are very substantial. They just rarely make it to the hn frontpage, because they really are boring. However, the Wasm push in enterprise compute is real, and the value is real. But you're right that the ecosystem and its sponsorship is still struggling - in some part due to lack of support for the component model by the browser people. The component model support introduced in go 1.25 has been huge though, at least for the (imho bigger) enterprise compute use case, and the upcoming update to the component model (wasi p3) should make a ton of this stuff way more usable. So it's a really interesting time for Wasm.
- sublinear 1y ago[flagged]
- edg5000 1y agoHas anybody written a nice DOM wrapper for C++/Rust? So you can do everything from the comforts of the C++/Rust application? The API whould match JavaScript APIs as much as possible.
- the_duke 1y agoSure, in Rust the web-sys [1] crate provides auto-generated bindings for pretty much all the browser APIs. Has been used by most of the Rust web frontend frameworks for years. It all has to go through JS shims though, limiting the performance potential. [1] https://docs.rs/web-sys/latest/web_sys/ https://docs.rs/web-sys/latest/web_sys/
- theSherwood 1y agoI want DOM access from WASM, but I don't want WASM to have to rely on UTF-16 to do it (DOMString is a 16-bit encoding). We already have the js-string-builtins proposal which ties WASM a little closer to 16-bit string encodings and I'd rather not see any more moves in that direction. So I'd prefer to see an additional DOM interface of DOMString8 (8-bit encoding) before providing WASM access to DOM apis. But I suspect the interest in that development is low.
- flohofwoe 1y agoTbh I would be surprised if converting between UTF-8 and JS strings is the performance bottleneck when calling into JS code snippets which manipulate the DOM. In any case, I would probably define a system which doesn't simply map the DOM API (objects and properties) into a granular set of functions on the WASM side (e.g. granular setters and getters for each DOM object property). Instead I'd move one level up and build a UI framework where the DOM is abstracted away (quite similar to all those JS frameworks), and where most of the actual DOM work happens in sufficiently "juicy" JS functions (e.g. not just one line of code to set a property).
- zeratax 1y agoidk looking at what the creator of leptos talks about it seems to be very significant: https://youtu.be/4KtotxNAwME?si=e_xwqo5gopKDlOtK https://youtu.be/4KtotxNAwME?si=e_xwqo5gopKDlOtK
- criticalfault 1y agoI've been reading about this for a while. Will it. Won't it. Does anybody know why is it such a big problem to add dom access to wasm? In worst case, we should have a second option to Js (which is not typescript - typescript is just a lipstick on a pig). If wasm is not it, why not something different? Having dart in would be great.
- flohofwoe 1y ago> Does anybody know why is it such a big problem to add dom access to wasm? Well, the article does a pretty good job of answering this specific question ;)
- wongarsu 1y agoDoes it? It gives good reasons why we can't have specific parts. Having the JavaScript Standard library in WebAssembly would be hard (was anyone actually asking for that?), and some of the modern APIs using promises or iterators wouldn't have a clear mapping. Also not everything could be zero-copy for every language But the article doesn't do a very good job explaining why we can't have some dom access, at least for the 90% of DOM APIs not using JavaScript-specific features. Most of the argument boils down to "you shouldn't want direct DOM access, because doing that would be work for these people, and we can instead have those other people do lots of work making the JavaScript bridge less painful. And anyways it's not clear if having these people make proper APIs would actually result in faster code than having those people do a separate sophisticated toolchain for each language" It reads very much like a people and resource allocation problem rather than a technical challenge
- flohofwoe 1y ago> at least for the 90% of DOM APIs not using JavaScript-specific features The DOM is a Javascript API, so it uses 100% Javascript-specific features (every DOM manipulation requires accessing JS objects and their properties and lots of those properties and function args are Javascript strings) - none of those map trivially to WASM concepts. It's a bit like like asking why x86 assembly code doesn't allow "C++ stdlib access", the question doesn't even make much sense ;)
- CaptainFever 1y agoI'm worried that wide use of WASM is going to reduce the amount of abilities extensions have. Currently a lot of websites are basically source-available by default due to JS.
- IshKebab 1y ago> Currently a lot of websites are basically source-available by default due to JS. By default maybe, but JS obfuscators exist so not really. Many websites have totally incomprehensible JS even without obfuscators due to extensive use of bundlers and compile-to-JS frameworks. I expect if WASM gets really popular for the frontend we'll start seeing better tooling - decompilers etc.
- Fluorescence 1y agoWith minimisers and obfuscators I don't see wasm adding to the problem. I felt something was really lost once css classes became randomised garbage on major sites. I used to be able to fix/tune a website layout to my needs but now it's pretty much a one-time effort before the ids all change.
- hinkley 1y agoI’ve been trying to fix UI bugs in Grafana and “randomized garbage” is real. Is that a general React thing or just something the crazy people do? Jesus fucking Christ.
- Fluorescence 1y agoI assume it was first as anti-scraping / anti-adblock measures but then frameworks with styled components spread it even further. Remember when the trend was "semantic class names" and folk would bikeshed the most meaningful easy to understand naming schemes? How we have fallen.
- hinkley 1y agoI was doing my most intense period of frontend work during that era. I went to work on backend for a long while and came out of my cave into this bullshit. This is worse than Struts, which was a bad trip we all eventually woke up from.
- Havoc 1y ago> Wasm includes various JavaScript APIs that allow compiler-generated glue code One of the reasons I’m interested in wasm is to get away from the haphazardly evolved JS ecosystem…
- nikeee 1y agoI wouldn't be that sure if we'd want to exchange that for an ecosystem that consists of many different languages that all have their own ecosystem wich may not be compatible with WASM. Imagine needing nuget, maven and cargo -- all in their specific version -- to build a project.
- Muromec 1y agoYou get more of that with wasm actually. You get the rust zoo, elixir zoo, gleam, three toolchains for c or what not. And for each of them you need a bunch of fine autogenerated javascript glue to sniff, because those people can't agree on what the string looks like in memory.
- hardwaresofton 1y agoDisclaimer: I work on Jco, one of the user-facing Bytecode Alliance WASM JS ecosystem projects Just a note, but there is burgeoning support for this in "modern" WebAssembly: https://github.com/bytecodealliance/jco/tree/main/examples/components/webidl-book-library https://github.com/bytecodealliance/jco/tree/main/examples/c... If raw WebIDL binding generation support isn't interesting enough: https://github.com/bytecodealliance/jco/blob/main/packages/jco/test/fixtures/idl/dom.test.js https://github.com/bytecodealliance/jco/blob/main/packages/j... https://github.com/bytecodealliance/jco/blob/main/packages/jco/test/fixtures/idl/dom.wit https://github.com/bytecodealliance/jco/blob/main/packages/j... https://github.com/bytecodealliance/jco/blob/main/packages/jco/test/fixtures/idl/console.test.js https://github.com/bytecodealliance/jco/blob/main/packages/j... Support is far from perfect, but we're moving towards a much more extensible and generic way to support interacting with the DOM from WebAssembly -- and we're doing it via the Component Model and WebAssembly Interface Types (WIT) (the "modern" in "modern" WebAssembly). What's stopping us the most from being very effective in browsers is the still-experimental browser shim for components in Jco specifically. This honestly shouldn't be blocking us at this point but... It's just that no one has gotten around to improving and refactoring the bindings. That said, the support for DOM stuff is ready now (you could use those WIT interfaces and build DOM manipulating programs in Rust or TinyGo or C/C++, for example). P.S. If you're confused about what a "component" is or what "modern" WebAssembly means, start here: https://component-model.bytecodealliance.org/design/why-component-model.html https://component-model.bytecodealliance.org/design/why-comp... If you want to dive deeper: https://github.com/WebAssembly/component-model https://github.com/WebAssembly/component-model
- valorzard 1y agoYou should write an article about this stuff and post it here since this is the first time I’m hearing about all of this
- landonxjames 1y agoI have used Jco quite a bit (and contributed a few times) to build out simple utilities binding Rust code to JS [1][2]. I think it is great and the Component Model is the most exciting step towards real useful polyglot libraries I have seen in years. I wish it were better publicized, but I understand keeping things lowkey until it is more fleshed out (the async and stream support coming in Preview 3 are the real missing pieces for my usecases). [1] https://github.com/awslabs/aws-wasm-checksums https://github.com/awslabs/aws-wasm-checksums [2] https://github.com/landonxjames/aws-sdk-wasi-example https://github.com/landonxjames/aws-sdk-wasi-example
- jagged-chisel 1y agoInterop with JS APIs is a requirement. Therefore, glue code is a requirement. If we’re not going to get direct access to the DOM, can we at least get the ability to just list the JS functions that our wasm will call? Of course the list will be bundled with (compiled into) the wasm blob, and whether it’s literally a text list or something like a registration call naming those JS functions, I am agnostic about. Everyone having to write all their own glue[*] is just nuts at this point. [*]Yeah, the toolchains help solve this a bit, but it still makes me ship JS and wasm side-by-side.
- xscott 1y ago> If we’re not going to get direct access to the DOM, can we at least get the ability to just list the JS functions that our wasm will call? You mean like a list of JS functions that are imported into the Wasm binary? This has been there since day one: (module ... (import "env" "foo" (func (;0;) (type 1))) (import "env" "bar" (func (;1;) (type 2))) ... ) > Everyone having to write all their own glue[*] is just nuts at this point. Did you mean for the specific programming language you use? If so then that seems like a problem for the language implementor, not a problem with Wasm. Rust has wasm bindgen, Emscripten has their thing, and so on.
- lucideer 1y agoI don't think I want WebAssembly to have DOM support. Would it be nice? Yes. But. Every added feature is a trade-off between need -vs- outlay, overhead, complexity & other drawbacks. In order to justify the latter things, that "need" must be significant enough. I'd like to have DOM, but I don't feel the need is significant. Some thoughts on use-cases: 1. "Inactive" or "in-instance" DOM APIs for string parsing, document creation, in-memory node manipulation, serialisation: this is all possible today in WASM with libraries. Having it native might be cool but it's not going to be a significantly different experience. The benefits are marginal here. 2. "Live / active" or "in-main-thread" direct access APIs to manipulate rendered web documents from a WASM instance - this is where the implementation details get extremely complex & the security surface area starts to really widen. While the use-cases here might be a bit more magical than in (1), the trade-offs are much more severe. Even outside of security, the prospect of WASM code "accidently" triggering paints, or slow / blocking main thread code hooked on DOMMutation events is a potential nightmare. Trade-offs definitely not worth it here. Besides, if you really want to achieve (2), writing an abstraction to link main-thread DOM APIs to WASM postMessage calls isn't a big lift & serves every reasonable use-case I can think of.
- Surac 1y agoi miss the times where computers where used to solve problem. Nowerdays people MAKE there problems themself by layering thousands of apis over each other and calling back and forth milions of times. no wonder computer are not getting faster.
- apatheticonion 1y agoThe web is a platform that has so much unrealized potential that is absolutely wasted. Wasm is the perfect example of this - it has the potential to revolutionize web (and desktop GUI) development but it hasn't progressed beyond niche single threaded use cases in basically 10 years.
- adastra22 1y agoIt should never have been web assembly. WASM is the fulfillment of the dream that started with Java VM in the 90’s but never got realized. A performant, truly universal virtual machine for write-once, run anywhere deployment. The web part is a distraction IMHO.
- secondcoming 1y agoWhy did Java fail though, and why would wasm succeed when the underlying philosophy is the same?
- dijit 1y agoabundance of the runtime, ease of distribution of programs, the permission model which was bolted on, appropriate sandboxing mechanism leading to authorisation problems and performance when people were not ready to sacrifice a very significant amount for no reason. Oh, and breaking changes between versions meaning you needed multiple runtimes and still got weird issues in some cases.
- thaumasiotes 1y agoI asked a number of times on HN why wasm was good when java applets, exactly the same thing, were bad. There was a vague feeling that java applets were insecure and that this would somehow not be an issue for wasm. It's not just applets; we also had Flash, which was a huge success until it was suddenly killed. As far as I can tell, the difference between java applets and Flash is that you, the user, have to install java onto your system to use applets, whereas to use Flash you have to install Flash into your browser. I guess that might explain why one became more popular than the other.
- gchamonlive 1y agoI have zero experience with anything wasm, just regular old DOM with typescript, but I wonder if this is the kind of problem that could be addressed the same way that phoenix liveview addesses frontend updates, by message passing only with diff changes, and delegate the Dom manipulation to what works, effective modelling the wasm runtime as an actor.
- Muromec 1y agoIt's one of the ways one can write the glue between WASM and JS. The actual problem is, like everything in javascript, there is no standard glue, no ABI, no expectation of what memory representation of a list or even a string looks like. You can even compile elixir into wasm-fx and run actor model, it's super fun and mad, but what you can't do is not deal with the technicalities. So either you buy into one of the frameworks that are (not) built on top of wasm and lock into their paradigm or roll your own, because wasm proper doesn't even have any abstractions above numbers on a stack.
- austin-cheney 1y agoThis is one of those self-taught versus college educated subjects. See this for some background https://news.ycombinator.com/item?id=44599228 https://news.ycombinator.com/item?id=44599228 This subject is interesting because your typical college educated developer HATES the DOM with extreme passion, because it’s entirely outside their area of comfort. The typical college educated developer is typically educated to program in something like Java, C#, or C++ and is how the world is supposed to work. The DOM doesn’t work like that. It’s a graph of nodes in the form of a tree model, and many developers find that to be scary shit. That’s why we have things like jQuery, Angular, and React. These college educated developers also hate JavaScript for the same reasons. It doesn’t behave like Java. So for many developers the only value of WASM is as JavaScript replacement. WASM was never intended or positioned to be a JavaScript replacement so it doesn’t get used very often. Think about how bloated and slow the web could become if WASM were a JavaScript replacement. Users would have to wait on all the run time and dependencies to download into the WASM sandbox and then open like a desktop application, but then all that would get wrapped in something like Angular or React because the DOM is still scary.
- JambalayaJimbo 1y agoWhy would college educated developers hate node or tree structures? That’s half of our degrees!
- austin-cheney 1y agoI have 20 years of experience writing software with hundreds and hundreds of other developers for mega dot coms that indicates many, possibly most, developers do everything possible to hide from tree structures. I don’t know why that is because it’s neither scary nor challenging. It’s also strange that my prior comment here is maximally downvoted when the similar comment it linked to was upvoted to triple digits. This further reaffirms my assumption that WASM primarily appeals to insecure developers.
- JambalayaJimbo 1y agoI can understand how developers would be scared of tree structures. This doesn't make sense when you specifically call out people with degrees however, as we worked with trees to a fault in my Computer Science degree. But maybe I'm reading too much into this - there are different "college eduction" paths people may take that are not Computer Science.
- 3cats-in-a-coat 1y agoDOM is so dynamic, any integration with DOM will look no different than the way we do it now through JS. JS is built to work naturally with DOM. Maybe we should stop overdesigning things and keep it simple. WASM needs more tooling around primitive types, threading, and possibly a more flexible memory layout than what we have now.
- evrimoztamur 1y agoIt's not just the DOM, it's also all other APIs like WebGL2. I ended up having to rewrite the entire interfacing layer of my mobile application (which used to be WebAssembly running in WebKit/Safari on iOS) because I was getting horrible performance losses each time I crossed that barrier. For graphics applications where you have to allocate and pass buffers or in general piping commands, you take a horrible hit. Firefox and Chrome on Windows/macOS/Linux did quite well, but Safari... Everything has to pass the JavaScript barrier before it hits the browser. It's so annoying!
- MisterTea 1y agoI am confused by this. If WASM is a VM then why would it understand the DOM? To me it akin to asking "When will Arm get DOM support?" Seems like the answer is "When someone writes the code that runs on WASM that interacts with the DOM." Am I missing something? (not a web dev.)
- jffry 1y agoThe WASM VM doesn't have any (direct) access to the DOM, so there's no code you can write in it that would affect the DOM. There's a way to make JS functions callable by WASM, and that's how people build a bridge from WASM to the DOM, but it involves extra overhead versus some theoretical direct access.
- MisterTea 1y agoThanks for the clarification. So if I understand correctly - when using WASM you interface to web things through JS forcing the user to always need JS in the stack when e.g. they may want to just use Rust or Go. My first thought would be modules that are akin to a syscall interface to a DOM "device" exposed by the VM.
- jkcxn 1y agoThat's like saying WASM doesn't have a direct way to allocate memory or print to the console. Of course it doesn't, it doesn't have access to anything, that's the whole point.
- xg15 1y agoI think a good analogy would be between user-space and kernel-space code. It's just weird that by this logic, JavaScript - the more high-level, less typesafe and less performant language - would be the kernel, while performance-optimized WASM code would be the userspace program.
- amelius 1y agoAt this point, why not implement DOM inside WebAssembly? The end of DOM compatibility issues ...
- DonHopkins 1y agoEmscripten has a handy tool called "Embind" for binding JavaScript/TypeScript and C/C++/whatever code. It's underappreciated and not well documented all in one place, but here is a soup-to-nuts summary. Emscripten + Embind allow you to subclass and implement C++ interfaces in TypeScript, and easily call back and forth, even pass typed function pointers back and forth, using them to call C++ from TypeScript and TypeScript from C++! Embind: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html https://emscripten.org/docs/porting/connecting_cpp_and_javas... Interacting with Code: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html https://emscripten.org/docs/porting/connecting_cpp_and_javas... Embind's bind.cpp plumbing: https://github.com/emscripten-core/emscripten/blob/main/system/lib/embind/bind.cpp https://github.com/emscripten-core/emscripten/blob/main/syst... C Emscripten macros (like EM_ASM_): https://livebook.manning.com/book/webassembly-in-action/c-emscripten-macros/v-7 https://livebook.manning.com/book/webassembly-in-action/c-em... Emscripten’s embind: https://web.dev/articles/embind https://web.dev/articles/embind I'm using it for the WASM version of Micropolis (open source SimCity). The idea is to be able to cleanly separate the C++ simulator from the JS/HTML/WebGL user interface, and also make plugin zones and robots (like the monster or tornado or train) by subclassing C++ interface and classes in type safe TypeScript! emscripten.cpp binds the C++ classes and interfaces and structs to JavaScript using the magic plumbing in "#include <emscripten/bind.h>". There is an art to coming up with an elegant interface at the right level of granularity that passes parameters efficiently (using zero-copy shared memory when possible, i.e. C++ SimCity Tiles <=> JS WebGL Buffers for the shader that draws the tiles) -- see the comments in the file about that): emscripten.cpp: https://github.com/SimHacker/MicropolisCore/blob/main/MicropolisEngine/src/emscripten.cpp https://github.com/SimHacker/MicropolisCore/blob/main/Microp... /** * @file emscripten.cpp * @brief Emscripten bindings for Micropolis game engine. * * This file contains Emscripten bindings that allow the Micropolis * (open-source version of SimCity) game engine to be used in a web * environment. It utilizes Emscripten's Embind feature to expose C++ * classes, functions, enums, and data structures to JavaScript, * enabling the Micropolis game engine to be controlled and interacted * with through a web interface. This includes key functionalities * such as simulation control, game state management, map * manipulation, and event handling. The binding includes only * essential elements for gameplay, omitting low-level rendering and * platform-specific code. */ [...] //////////////////////////////////////////////////////////////////////// // This file uses emscripten's embind to bind C++ classes, // C structures, functions, enums, and contents into JavaScript, // so you can even subclass C++ classes in JavaScript, // for implementing plugins and user interfaces. // // Wrapping the entire Micropolis class from the Micropolis (open-source // version of SimCity) code into Emscripten for JavaScript access is a // large and complex task, mainly due to the size and complexity of the // class. The class encompasses almost every aspect of the simulation, // including map generation, simulation logic, user interface // interactions, and more. [...] class_<Callback>("Callback") .function("autoGoto", &Callback::autoGoto, allow_raw_pointers()) [...] Here's the WebGL tile renderer that draws the tiles directly out of a Uint16Array pointing into WASM memory: https://github.com/SimHacker/MicropolisCore/blob/main/micropolis/src/lib/WebGLTileRenderer.ts https://github.com/SimHacker/MicropolisCore/blob/main/microp... The corresponding C++ source and header and TypeScript files define the callback interface and plumbing: callback.h defines the abstract Callback interface, as well as a ConsoleCallback interface that just logs to the JS console, for debugging: callback.h: https://github.com/SimHacker/MicropolisCore/blob/main/MicropolisEngine/src/callback.h https://github.com/SimHacker/MicropolisCore/blob/main/Microp... /** * @file callback.h * @brief Interface for callbacks in the Micropolis game engine. * * This file defines the Callback class, which serves as an interface * for various callbacks used in the Micropolis game engine. These * callbacks cover a wide range of functionalities including UI * updates, game state changes, sound effects, simulation events, and * more. The methods in this class are virtual and intended to be * implemented by the game's frontend to interact with the user * interface and handle game events. */ class Callback { public: virtual ~Callback() {} virtual void autoGoto(Micropolis *micropolis, emscripten::val callbackVal, int x, int y, std::string message) = 0; [...] callback.cpp implements just the concrete ConsoleCallback interface in C++ with "EM_ASM_" glue to call out to JavaScript to simply log the parameters of each call: callback.cpp: https://github.com/SimHacker/MicropolisCore/blob/main/MicropolisEngine/src/callback.cpp https://github.com/SimHacker/MicropolisCore/blob/main/Microp... /** * @file callback.cpp * @brief Implementation of the Callback interface for Micropolis game * engine. * * This file provides the implementation of the Callback class defined * in callback.h. It includes a series of methods that are called by * the Micropolis game engine to interact with the user interface. * These methods include functionalities like logging actions, * updating game states, and responding to user actions. The use of * EM_ASM macros indicates direct interaction with JavaScript, typical * in a web environment using Emscripten. */ js_callback.h contains an implementation of the Callback interface that caches a "emscripten::val jsCallback" (an enscripten value reference to a JS object that implements the interface), and uses jsCallback.call to make calls to JavaScript: js_callback.h: https://github.com/SimHacker/MicropolisCore/blob/main/MicropolisEngine/src/js_callback.h https://github.com/SimHacker/MicropolisCore/blob/main/Microp... #include <emscripten/val.h> #include "callback.h" class JSCallback : public Callback { public: explicit JSCallback(emscripten::val jsCallback) : Callback(), jsCallback(jsCallback) {} // Implement all pure virtual functions from Callback void autoGoto(Micropolis *micropolis, emscripten::val callbackVal, int x, int y, std::string message) override { jsCallback.call<void>("autoGoto", emscripten::val(micropolis), callbackVal, x, y, message); } [...] private: emscripten::val jsCallback; }; Then emscripten/embind generates a TypeScript file that defines the JS side of things: micropolisengine.d.ts: https://github.com/SimHacker/MicropolisCore/blob/main/micropolis/src/types/micropolisengine.d.ts https://github.com/SimHacker/MicropolisCore/blob/main/microp... // TypeScript bindings for emscripten-generated code. Automatically generated at compile time. [...] export interface Callback { autoGoto(_0: Micropolis, _1: any, _2: number, _3: number, _4: EmbindString): void; [...] export type MainModule = WasmModule & typeof RuntimeExports & EmbindModule; export default function MainModuleFactory (options?: unknown): Promise<MainModule>; Then you can import that TypeScript interface (using a weird "<reference path=" thing I don't quite understand but is necessary), and implement it in nice clean safe TypeScript: https://github.com/SimHacker/MicropolisCore/blob/main/micropolis/src/lib/MicropolisCallbackLog.ts https://github.com/SimHacker/MicropolisCore/blob/main/microp... /// <reference path="../types/micropolisengine.d.ts" /> import type { Micropolis, JSCallback } from '../types/micropolisengine.d.js'; // Micropolis Callback Interface Implementation export class MicropolisCallbackLog implements JSCallback { verbose: boolean = false; autoGoto(micropolis: Micropolis, callbackVal: any, x: number, y: number, message: string): void { console.log('MicropolisCallbackLog: autoGoto:', 'x:', x, 'y:', y, 'message:', message); } It's all nice and type safe, and Doxygen will even generate documentation for you: https://micropolisweb.com/doc/classJSCallback.html https://micropolisweb.com/doc/classJSCallback.html And it even works, and it's pretty fast! (Type "9" to go super fast, but for the love of god DO NOT PRESS THE SPACE BAR!!!) https://micropolisweb.com https://micropolisweb.com
- xg15 1y agoIs there any data on the performance cost of JS/WASM context switches? The way the architecture is described, it sounds as if the costs could be substantial, but the approaches described in the article basically hand them out like candy. This would sort of defeat the point that WASM is supposed to be for the "performance critical" parts of the application only. It doesn't seem very useful if your business logic runs fast, but requires so many switching steps that all performance benefits are undone again.
- breve 1y agoHere are a couple of talks on Leptos (https://www.leptos.dev/ https://www.leptos.dev/), how it works and performs: https://www.youtube.com/watch?v=4KtotxNAwME https://www.youtube.com/watch?v=4KtotxNAwME https://www.youtube.com/watch?v=V1cqQRmVAK0 https://www.youtube.com/watch?v=V1cqQRmVAK0
- giancarlostoro 1y agoNot entirely sure, but C#'s Blazor is amazing. I can stick to purely C# code, front-end and back-end, we rarely call out to JS unless its for like file uploading dialogs. I don't want to ever touch JavaScript again after this workflow. Edit: And if you don't want to do "WebAssembly" you can have it do it all server rendered, think of a SPA on steroids.
- markdog12 1y agoYeah, it's very unfortunate for WebGL/WebGPU apps, where every call has to pass/convert typed arrays and issue a js gl call. It pretty much kills any advantage of using WASM. Hope that changes.
- breve 1y agoWebAssembly is the faster option for WebGL applications on the web, not least because you also might want to run things like physics engines: https://playgama.com/blog/general/boost-html5-game-performance-with-webassembly/#assessing-current-performance-bottlenecks-in-html5-games https://playgama.com/blog/general/boost-html5-game-performan...
- naikrovek 1y agoThe fact that this needs to be explained with mentions of pointers and data alignment and garbage collection tells me that the decisions that the web standards committees make continue to be just completely disconnected from anything sane. maybe my read is wrong, but everything i look at today just screams to me that the web is extremely poorly designed; everything about it is simply wrong.
- cookiengineer 1y agoActually my journey was quite similar. I started to build a bindings and web components framework in Pure Go so that I can build user interfaces with webview/webview. My apps just go:embed all their assets and spawn a local webview as their UI, which is quite nice because client and server use the same schemas and same validations for e.g. web forms and the fetch/REST APIs. Server-side-rendered components are implemented using a web components graph whose components can be String()ified into HTML. It's a bit Experimental though, and the API in the components graph might change in the future: https://github.com/cookiengineer/gooey https://github.com/cookiengineer/gooey
- flakiness 1y agoTangent: ACM queue this months seems to be dedicated to Wasm. Nice! https://queue.acm.org/issuedetail.cfm?issue=3747201 https://queue.acm.org/issuedetail.cfm?issue=3747201
- jazzypants 1y agoYeah, the concurrency article is quite excellent as well. I definitely recommend it! I also don't think it has been posted here, so feel free to do so.
- deleted 1y ago[deleted]
- dfabulich 1y agoI think this article is written in a very confusing way. I think I would have written it this way. When writing most non-web software, you can usually write it easily in a high-level language (with a rich standard library and garbage collection), but you can get better performance (with more effort) by writing your code in a lower-level language. WASM seems like an opportunity to get better performance by rewriting JavaScript web apps in lower-level languages like C or Rust, but it doesn't work that way, because of standardization. Today, the web's core DOM APIs are defined in standards committees as inherently JavaScript APIs, in the form of WebIDL documents. https://developer.mozilla.org/en-US/docs/Glossary/WebIDL https://developer.mozilla.org/en-US/docs/Glossary/WebIDL When defining standardized APIs in WebIDL, WebIDL assumes that you can use JavaScript strings, JavaScript objects + properties, JavaScript Exceptions, JavaScript Promises, JavaScript garbage collection, and on and on and on. Almost all of the WebIDL specification is about the dozens of types that it assumes the platform already provides. https://webidl.spec.whatwg.org/ https://webidl.spec.whatwg.org/ WASM doesn't have any of those things. No one has ever standardized a DOM API for low-level languages. You'd need to start by standardizing a new "low-level API" for DOM access, and presumably a new low-level WebIDL to define those standards. Designing the web by committee makes it hard to add/change stuff in browsers. You have to get Apple, Google, Microsoft, and Mozilla to agree on literally everything. (Defining WebIDL itself has taken decades!) It can be hard to even get agreement from browser vendors to discuss the same topic, to even just get them to read your proposed standards document and to say "no, we won't implement it like this, because..." You have to convince them that the standard you're proposing is one of their top priorities. (And before you can do that, you have to convince them to pay attention to you at all.) So, someone would have to persuade all of the browser vendors that one of their top priorities should be to invent a new way to standardize DOM APIs and begin the process of standardizing DOM access on top of a lower-level IDL. Today, the browser vendors aren't convinced that this is worth their time. As the article says: > For now, web folks don't seem to be sold on the urgency of this very large project. There is no active work by browser vendors in this direction. And that's why you can't get top-notch performance by rewriting your web app in Rust. You can rewrite your web app in Rust, and it can access JS APIs, but when touching the DOM APIs, Rust has to interop with JS. Rust's interop with JS is no faster than JS itself (and it's often slower, because it requires added glue code, translating between JS and WASM). As a result, if you're writing a web app, you mostly have to do it in JS. If you have some very CPU-intensive code, you can write that in WASM and slowly copy the result of your computation to JS, as long as you don't cross the boundary between WASM and JS too often. Alternately, if you have existing code in non-JS languages, you can port it to web via WASM, but it'll probably run slower that way; the best performance improvement you can do is to rewrite it in JS!
- jokoon 1y agoBlame browsers. Things like QT and browsers became popular because people realize they could short circuit OS vendors asking developer to be loyal to them. The glue won. But QT and browsers and JS are just hotfixes, they're not sound technologies, they're just glue.
- fatata123 1y ago[dead]
- pton_xd 1y agoWhy does WASM need to manipulate the DOM when JS already excels at that? Interfacing with JS was never really an issue; yes you do have to design reasonable module boundaries and understand how data is going to be shared. That just leads to simpler / stronger program design. If you're writing a DOM UI heavy app, use JavaScript. Many WASM apps, like games, have no interest in the DOM. It's just more spec bloat.
- replyifuagree 1y agoI wonder how better DOM support would help a rust web application frontend framework like Leptos (https://leptos.dev https://leptos.dev)? Maybe a smaller WASM payload?
- vsmenon 1y agoYou can effectively try this today in Dart. When running in the browser, Dart can compile to either JavaScript or Wasm and both backends support DOM access via https://pub.dev/packages/web https://pub.dev/packages/web. The DOM access in Wasm does trampoline through JavaScript under the hood, which introduces some overhead. Dart uses WasmGC, though, which is supported on Chrome/FF/Safari and lowers that overhead by enabling objects to be shared across the Wasm / JS boundary. In the benchmarks we've tried, the overhead is not that noticeable. But direct access (from Wasm) would be faster. Jaspr (https://jaspr.site https://jaspr.site) is a react-style framework that sits on top of this. You can see example usage here: https://github.com/vsmenon/todomvc/ https://github.com/vsmenon/todomvc/ This app is too small to show benefits, but the code size is about the same across the two and similar to those at todomvc.com. We are seeing potential benefits on page load time (Wasm is faster to parse/initialize) and compute (Wasm is faster on many workloads).
- vsmenon 1y agoThere is a recent YT video on Dart & Wasm: https://www.youtube.com/watch?v=vgOABOvtBT8 https://www.youtube.com/watch?v=vgOABOvtBT8
- msie 1y agoIt's amazing how some are spinning that wasm shouldn't get DOM support.