Serving Astro with Rust
yieldcode.blog
yieldcode.blog
Defining your UI as more-or-less normal functions in your main programming language that take normal arguments and return return composable UI-typed values is a massive, massive productivity win. Lots of teams pick Typescript/React over other languages/frameworks they prefer or that have better performance for only that reason!
I'm very happy that many production UI systems are moving towards a React/Elm-inspired API. On Android, Jetpack Compose means I don't need to screw around copy pasting method names between XML files and Java classes. On iOS, SwiftUI means I never need to plumb delegates around Interface Builder again. In Typescript land, there's a zillion React-inspired frameworks, like Astro, that carry this learning forward.
If I was in OP's position, I'd be looking for some macros / sugar (https://docs.rs/typed-html/latest/typed_html/ came up in a quick google search) that make it really easy to write composable UI snippets in my regular Rust files. Why introduce a new language, a new typechecker, and muck around iteroperating between Rust and Typescript, if you can do it all in Rust? You can even add a little bit of glue to make HTMX directives that eg do form things type-check against the form action they'll POST to. You should be able to rely on the Rust compiler to make function calls that return strings not error at runtime.
I use html-node which has a typed submodule for even greater strictness. I just build some valid html, make a string and write that to the output directory and get on with my life. Eg: https://github.com/0atman/noboilerplate/
Templates... Rust functions
Flow control... Rust match expression
Abstraction... Rust modules
Html validation... Rust compiler
I like to think that in writing the html-node crate, Vidhan taught the compiler to speak html! https://lib.rs/crates/html-node
Does this exist somewhere? My impression is that the tedious use of half-baked expression language to pull content from the (typed or not) programming language world into the template has always remained not quite enough of a pain point to drive this reversal and the rise of approaches that don't use separate templates at all (react et al) has made interface-from-template even less likely to happen.
As an example, if the template was "<span>{name}</span>" then if I follow you correctly, it would generate some `Model` struct/interface/whatever that would have a `name: String` field.
I think a problem comes about when it's instead:
"<span>{itemCount}</span>"
Obviously it can't know that this intends to be an integer. Would it generate an `itemCount` field that is something generic like "impl Display"? Or still String? Either way, you may have other logic that needs this `itemCount` as an integer, for arithmetic or something. Perhaps two models, both auto-generated for all String fields but one you don't touch and the other you can change fields as long as they're convertable to String.
I think the main problem is going from a more structured to less structured (model to template) is possible but going the reverse way (template to model) can't always infer the structure.
It would not solve any big problems when you start with a detailed plan and everything is going according to it. Perhaps that's the reason why fragile expression languages are so often considered good enough: it cements the importance of the person writing the spec (sorry for the sarcasm)
Just write a function in the host language, it already has a great way of expressing the types of arguments passed to a function (hopefully)
Crazy that rust stuff just gets upvoted.
Also “server side rendering” as a term just needs to go away. Serving HTML is the way it all started.
People immersed in development using front-end JavaScript frameworks have been sufficiently isolated from server-side rendering for long enough that it’s a foreign concept.
A recent optimisation in front-end frameworks is to generate the initial HTML on the server instead of sending an empty shell that does nothing but load the JavaScript application.
As you point out, this is just server-side rendering, which is a very old concept. However, if you have spent the majority of your time with front-end frameworks, “SSR” is a new concept that has recently been invented, not that old thing that people used to do before front-end JavaScript frameworks took over the world.
I've done that sort of thing explicitly in the past, with great results, which is why I think you overlooked such.
I also think you're missing the idea that server side rendering implies a class of network traffic reductions, with resulting UX improvements.
An example might would be that a subset of possible javascript, which might have been sent to a browser which was "Serving HTML", might be responsible for resulting network requests right back to the server serving the html.
And this pointless network traffic which uses nothing on the browser except a javascript engine might be identified and run with no network overhead on the server, which is serving whatever in the first place. i.e., it's a network traffic 'optimization' since latency is a big deal in UX.
You could read up on server side rendering ideas at https://bun.sh or https://deno.com for just two examples.
One of the coolest features of Go is the embed package. You can build, and bundle a React, Vue, SvelteKit, Astro or w.e framework directly into your binary and have it serve with your API. Makes deploying very easy, just ship the single file binary.