Top
Best
New

Posted by skwee357 1 day ago

Farewell, Rust for web(yieldcode.blog)
115 points | 107 commentspage 2
ysleepy 1 day ago|
Rust for web backends is such a weird choice.

Use a (statically typed) GC language for that.

andrewaylett 1 day ago||
It's a throwaway comment in the article, but I feel it's important to push back on: HTML is very definitely a programming language, by any reasonable definition of "programming language".

Edit to add: It might not be an imperative language, but having written some HTML and asked the computer to interpret it, the computer now has a programmed capability, determined by what was written, that's repeatable and that was not available apart from the HTML given. QED.

Dylan16807 1 day ago||
Please explain how your edit doesn't apply to a .txt file
tracker1 1 day ago|||
How would one do an if condition or enumerate a list in HTML alone? For that functionality you need another language to generate/manipulate the HTML.. not to mention interpreting HTML for display.

HTML is a markup language, it's even in the name... but it's not a complete programming language by any stretch.

andrewaylett 1 day ago||
It's not Turing-complete, and as you say, it's a markup language and it's not general purpose. But neither is a necessary component of "programming language".
zem 1 day ago||
agreed, it's a hill i am very willing to die on too.
taylorallred 1 day ago||
Rust shines in user-space systems-level applications (databases, cloud infrastructure, etc.) but definitely feels a bit out of place in more business-logic heavy applications.
stevage 1 day ago||
> And the occasional struggles with typescript where the runtime seems to be changing too often; is it ts-node? tsx? tsm? The built-in typescript runtime in node? deno? bun?

This whole paragraph is so true. The last couple of years have been pretty rough in Node land.

zem 1 day ago||
rescript [https://rescript-lang.org/] would make a nice middle ground between rust and typescript
cyberax 1 day ago||
Well, yep. People underappreciate the Typescript/JS ecosystem.

Typescript is pretty type-safe, and it's perfectly integrated with hot code reload, debuggers, and all the usual tools. Adding transpilation in that flow only creates friction.

That's also why things like Blazor are going nowhere. C# is nicer than Typescript, but the additional friction of WASM roundtrips just eats all the advantage.

mdasen 1 day ago||
I think the big thing keeping Blazor back is that C# doesn't work well with WASM. It was built at a time when JIT-optimized languages with a larger runtime were in-vogue. That's fine in a lot of cases, but it means that C# isn't well suited for shipping a small amount of code over the wire to browsers. A Blazor payload is going to end up being over 4MB. If you use ahead of time compilation, that can balloon to 3x more. The fact that C# offers internal pointers makes it incompatible with the current WASM GC implementation.

Blazor performance is around 3x slower than React, it'll use 15-20x more RAM, and it's 20x larger over the wire. I think if Blazor could match React performance, it'd be quite popular. As it stands, it's hard to seriously consider it for something where users have other options.

Microsoft has been working to make C#/.NET better for AOT compilation, but it's tough. Java has been going through this too. I don't really know what state it's at, but (for example) when you have a lot of libraries doing runtime code generation, that's fine when you have a JIT compiler running the program. Any new code generated at runtime can be run and optimized like any other code that it's running.

People do underappreciate the JS/TS ecosystem, but I think there are other reasons holding back stuff running on WASM. With Blazor, performance, memory usage, and payload size are big issues. With Flutter and Compose Multiplatform, neither is giving you a normal HTML page and instead just renders onto a canvas. With Rust, projects like Dioxus are small and relatively new. And before WASM GC and the shared heap, there was always more overhead for anything doing DOM stuff. WASM GC is also pretty new - it's only been a little over a year since all the major browsers supported it. We're really in the infancy of other languages in the browser.

sroerick 1 day ago|||
I feel like it was less than a year ago that Typescript was basically the only game in town and if you liked anything else you were a loon.

I have been an anti Typescript guy for a long time but I wouldn't deny for a moment that it's probably by far the most mature ecosystem.

throw-the-towel 1 day ago||
IDK, I still miss Rust's strictness and exhaustive enum matching.
socalgal2 1 day ago||
I don't know about what other strictness you're referring to but exhaustive enum matching is common check in most TS stacks via eslint. Yea, it's not builtin, just saying there's a solution and it's super common.
tcfhgj 1 day ago|||
last time I researched enums in TS for a project, they were a mess such that it was better not to use enums in the first place
cyberax 1 day ago|||
You can actually have it built-in (via default case in 'switch' statements having a 'never()' statement). But it's less powerful than Rust's.
nikeee 1 day ago||
Or you don't use the defualt case and rely on definite assignment analysis or checks for returns in every code path.

I find the never type in TS actually being a proper bottom type + having control-flow based types vastly superior to what rust offers.

aaroninsf 1 day ago||
This is oddly timed in as much as one of the big success stories I've heard from a friend is their new practice of having Claude Code develop in Rust, than translate that to WebAssembly.

That seems much more like the future than embracing Node... <emoji here>

Wintamute 1 day ago|
If you’re making a web app your fancy rust wasm module still has to interface with the dom, so you can’t escape that. Claude might offer you some fake simplicity on that front for awhile, but skeptical that’s it fully scalable
slopinthebag 1 day ago||
There are plenty of Rust frameworks that handle this interface for you, including calling Rust functions from JS and JS functions from Rust.
slopinthebag 1 day ago||
As someone who went in the opposite direction from Node to Rust, I feel like OP is just trading one set of problems for another set of substantially worse problems. I guess the grass is always greener in the other ecosystem ¯\_(ツ)_/¯

Idk, it just feels like OP chose all the wrong approaches with Rust, including using a separate language and ecosystem for the frontend, which is where most of the friction comes from. For example, Dioxus is a React clone that is somehow leagues better than React (and Next.js, too), and it has hot-reloading that brings compiles down to subsecond times, which makes building UI with it just as productive as with Node / Vite etc. I use it for server side code as well and it's great. Compilation times can be an issue with Rust, it's something I miss from Go, but there are ways to improve on it, and just being smart about what deps you include, avoiding overuse of macros etc can make a difference. I know these things were not around when OP started using Rust for their application, but they are around now.

Node and TS are quite frankly inferior to Rust in most ways. Bad language, ecosystem full of buggy unmaintained packages with the worse security profile of all the common languages, no unified build tooling that seems to break your project every 6 months, constant churn of blessed frameworks and tools, an stdlib that is not much more comprehensive than Rust's and outright broken in some ways, at least three different approaches to modules (esm, commonjs, umd, and more...?), I could go on an on. There is a reason why everyone seemingly reinvents the wheel in that ecosystem over and over again -- the language and platform is fundamentally not capable of achieving peoples goals, and every solution developed comes with massive tradeoffs that the next iteration attempts to solve, but that just creates additional issues or regressions for future attempts to tackle.

I've been using Rust with Dioxus and was completely mind blown when I started with it. With barely knowing any Rust (just React) I was able to jump right in and build with it, somehow it was more intuitive to me than most modern JS full stack frameworks. It seemingly already has most if not all of the features that similar JS frameworks have been developing for years, and because it's written in Rust things like conditional compilation are built into the language instead of being a third party babel plugin. That helps to remove a ton of friction. And it's trivial to build those same apps for desktop and mobile as well, something that's basically not possible with the JS frameworks.

Even stuff like websockets, go try to implement a type safe web socket connection with a server and client in Next.js or Astro. You'll need a ws library, something like Zod for validation, etc. In Rust it's just:

   #[derive(Serialize, Deserialize, Clone, Default)]
   enum SocketMessage { Hello(id: i32) }
  
   #[get("/api/ws")]
   async fn web_socket(options: WebSocketOptions) -> Websocket<SocketMessage> {
     options.on_upgrade(move |mut socket| async move {
       while let Ok(msg) = socket.recv().await {
         match msg { SocketMessage::Hello(id) => {} } // handle messages
       }
     })
   }

   fn App() -> Component {
     let mut socket = use_websocket(web_socket);
     rsx!{ button { onclick: move || socket.send(SocketMessage::Hello(42), "say hello" } }
   }
killerbreeze 1 day ago|
I think this is spot on. I've used Iced and Dioxus and both are great. I do take the author's point that the actual UI code, even in Dioxus, is verbose. It is. And that's a trade off I'm willing to make for guaranteed correctness.
slopinthebag 1 day ago||
I haven't used Iced but re. Dioxus, I don't know if it's necessary more verbose conceptually. One of the most frustrating things with React is handling async updates, and while Rust's async story is conceptually difficult, it's ultimately much easier to reason about (imo). Like are we sure a comparable component in React would be any less verbose?

   let mut breed = use_signal(|| "hound".to_string());

   let dogs = use_resource(move || async move {
     reqwest::Client::new()
       .get(format!("https://dog.ceo/api/breed/{breed}/images"))
       .send()
       .await?
       .json::<BreedResponse>()
       .await
   });

   rsx! {
     input {
       value: "{breed}",
       oninput: move |e| breed.set(e.value()),
     }

     div {
       display: "flex",
       flex_direction: "row",
       if let Some(response) = &*dogs.read() {
         match response {
           Ok(urls) => rsx! {
             for image in urls.iter().take(3) {
               img {
                 src: "{image}",
                 width: "100px",
                 height: "100px",
               }
             }
           },
           Err(err) => rsx! { "Failed to fetch response: {err}" },
         }
       } else {
         "Loading..."
       }
     }
   }
Imo the RSX here is much less verbose than JSX. Inline match statement, inline if statement, inline for loop, .take(3) compared to `Array.from({ length: 3 }).map((_, i) => urls[i]))`, etc etc. This gives you automatic cancellation of the future, whereas with React you would need a third party library like React Query, and then manually abort requests in the asynchronous function with an abort signal -- in Rust, you get that for free. You also get data validation for free, instead of needing eg. Zod for manual runtime validation.
clarabennett26 1 day ago|
[dead]
More comments...