I think WASM lets you write code in other languages for the browser. That is a simple way to put it. It is cool, but it sounds hard to use, because it is “close to the metal”. I am sure it is good for some things, but I am curious to hear from web developers how WASM is going these days.
It is useful. Most people don’t need it. People are always trying to “replace React” with it, and it never works. Every week, we see posts from a team that “rewrote their web app” in it. The post always talks about how much work it was. No one ever says what is good about it.
I am not against this tech. These early people are on the “bleeding edge” and having trouble is normal. Maybe it will be used more. But you asked…
Hart said:
@Jessie
Who tried to replace React with WASM? I want to see this. I need a laugh.
Leptos is one, but it is more of a SolidJS replacement than React, i.e. good reactivity. It is a solid thing, I would not make fun of it.
Hart said:
@Jessie
Who tried to replace React with WASM? I want to see this. I need a laugh.
Look at Yew in the Rust world.
Hart said:
@Jessie
Who tried to replace React with WASM? I want to see this. I need a laugh.
The laugh is react itself. I use it, but I hate their constant changes.
I used C# to WASM to do the hard part of a fun project I made recently:
It worked well. It wasn’t any harder than building a library in C#. I was able to add threads and then SIMD to make it faster without any trouble. It was easier than adding Web Workers in JS or TS.
I also did not like that Safari could not save WebP images, so I wrote a C++ program around libwebp and used Emscripten to compile it to WASM. The only hard part was learning enough CMake to change libwebp’s build script to do what I wanted. So I can now save WebP images from the app no matter what browser the person is using. This was nice because the app is 100% client-side. It is just served as a static site from CloudFlare Pages so I can’t offload anything to the server.
I am impressed with WASM. The tools for different languages seem to have come a long way, and I was able to add WASM to my project and make it faster.
@Mackenzie
This is cool! I have nothing else to say about it. The spinning logo is so smooth. Did you check how fast it is? It looks amazing on my MacBook screen.
Shan said:
@Mackenzie
This is cool! I have nothing else to say about it. The spinning logo is so smooth. Did you check how fast it is? It looks amazing on my MacBook screen.
The spinning is that smooth because it’s a CSS transition, and I think browsers have made CSS transitions very good on all the platforms they run on.
I tried the app on a new but slow Android device (a Umidigi A9c) and making an image is very slow, like 1-2 triangles per minute, versus many hundreds of triangles per minute on my iPhone 14. But the logo spun smoothly on the Umidigi!
@Mackenzie
Your project does not work on firefox.
Edit: It starts working as soon as I make this comment.
Edit2: The performance is worse on Firefox. I pressed the start button on Firefox, and I did two on Brave, and the Firefox one is not even halfway done.
Still a cool project.
@Noor
Hmm. The performance is different. Is it the newest version of Firefox?
Maybe it depends on the hardware? Firefox is about the same as Brave on my M2 mac and Ryzen machines, but it could be different on other hardware.
Thanks for trying it and letting me know. I like to figure out performance issues.
@Mackenzie
I tried it on firefox (135.0.1) and brave (133.1.75.178) on my linux machine (ZorinOS on a Lenovo Slim 7 Pro X with Ryzen 7 6800HS) and, at least yesterday.
It seems like turning it off and on again fixed the problem because it’s working now. That’s fun.
@Mackenzie
What version of dotnet core did you use? How is the performance now? I thought it was slow and big because they need to bring the mono clr compiled to wasm to run the bytecode, so it is still a runtime engine and bytecode. This was true with Blazor.
@Jules
I used .NET 9. I think the performance is good. I tried writing the code in C++ and it was not any faster.
Trimming and full AOT help a lot. It still uses Mono compiled Emscripten, but I turned up the optimization settings and set it to compile all DLLs to WASM so there is no CIL to run at runtime. It removes code that is not used, and what is left loads and runs quickly.
The first download is still a few megabytes, but it is cached by a web worker, so it only needs to be downloaded once.
I used Angular instead of Blazor for the UI. I tried Blazor, but some of the optimizations I used to get the most performance and make the runtime small break it. It is better than it was in .NET but was still bigger than I wanted for an app I planned to run on mobile devices.
I decided to use .NET for the rendering engine where things like threading and SIMD would make it faster. I am happy with how it worked.
I have not tested WASM vs full CLR performance, but I made a test to run the code outside the browser, and making the same image takes about the same time either way.
So the WASM .NET runtime with full trimming and AOT gives great performance, at least for me. My use is a best-case scenario. I do the shape rasterization, don’t use reflection, and don’t use any libraries beyond what comes with .NET. So my code can be optimized.
@Mackenzie
How is garbage collection with wasm and .net? I have not looked at that for a while, and I think that was hard for languages like C# and Kotlin to run well on wasm.
The last time I tried to use .net with wasm, it was sending big bundles, much bigger than rust. How was your experience?
@Cedar
Garbage collection has not been a problem for me.
I try to avoid any allocations that would need GC in my inner rasterization loop, but that’s not because of WASM. When rendering an image, I rasterize billions of pixels, and if I am not careful, it is too slow.
But this is true whether I run the code using WASM or in the desktop .NET CLR. When working with image data, you need to re-use array buffers, and Spans, and sometimes pointers if you want good performance.
In other parts of the code, I create things and let them be GC’ed and I have never had any performance or memory issues. And there is still a lot of GC needed. I create Tasks and other things, and I have never had to think about GC.
When using trimming and AOT, bundles are not huge. They are bigger than with Rust, but that is a fixed cost due to the size of the runtime. With good optimizations and trimming, it is a few megabytes in my case. After that, adding to your app does not make the size bigger.
The .NET build process for browser-wasm makes a service worker that caches the reusable bits. So it is a one-time download cost. For my app, starting the AOT compiled .NET runtime happens so quickly that I have never noticed a delay.
So, for my app, I decided that the one-time cost of downloading a few extra megabytes is okay.
If that does not work for your case, you would be better with Rust or C++. I have found Emscripten with C++ and -O3 optimization often makes smaller WASM files than Rust. You lose Rust’s safety, but you can get a lot out of unique_ptr and shared_ptr, and when running in the browser sandbox, that might be enough. It depends on your use and what you like.