Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Sauron – A web framework in Rust that adheres to the Elm architecture (github.com)
305 points by ivanceras 6 months ago | hide | past | web | favorite | 97 comments

Between this and Blazor ( http://blazor.net/, among other wasm projects I'm forgetting right now), I'm glad more complicated UIs are being once again designed on the backend and keeping bundle sizes (relatively) small, rather than making everything in JS on the frontend and expecting everyone to download megabytes of code to visit a website.

I'm looking in your direction Medium, at 6MB with a cold cache!

Large bundle sizes are not a consequence of creating UIs on the frontend, they are a consequence of bad practice. I have created plenty of purely frontend apps that don't even approach 1 MB let alone 6 MB. In fact, most languages that can target WASM seem to produce enormous modules compared to a reasonable frontend JavaScript app. Rust is an outlier in my experience because of its minimal runtime.

It's also worth noting for example that only 1/5th of the data transferred when I load medium.com cold is their JavaScript, so WASM can't really help them either way.

I did not know about tinygo and this is pretty impressive. However, it is only a subset of Go missing a few features, most notably the fact that memory is never deallocated.

Also, the equivalent JavaScript is still a fraction of this size. That's actually roughly the size of Preact, which implements nearly all of React.

Agreed, though it's a lot easier for bad practice to happen with JavaScript than a lot of other languages, and frameworks like this (hopefully) will make for a larger 'pit of success'.

Uuuggghhh, the baseless and ignorant JavaScript hate is a weak argument. It’s not any different than other baseless, weak, ignorant arguments; such as: ______ because _____(protected class) people.

I am paid well to do no work, essentially on retainer, because it’s so common for people to dick this up and then blame the technology for one’s own incompetence. Like anything else it only requires a little bit of practice. Running screaming into the night only to bury your head in the sand behind the magnificent glory of favorite pet framework x isn’t practice.

I describe this to nonprogrammers as hating on pianos because there is too much potential for bad music.

>> I am paid well to do no work

To be fair, working in this industry you could have been doing that without doing JavaScript :)

I said it was bad practice that led to the large size of Medium's website, but only 20% of that download size is their application's JavaScript. In what way did the use of JavaScript make it “easier” for the remaining 80% of the download size to happen?

Another lightweight contender, not WASM though, is Phoenix Live View[1]

[1] https://github.com/phoenixframework/phoenix_live_view

My bet is LiveView will become the king of the fast prototype. It doesn't do SPA, but it does damn near everything else with ease and so few lines of code.

I wonder how this copes with long-running pages. What happens if the server is updated and the minimal update format changes?

I have no experience doing this, but Erlang and Elixir do support hot upgrades.

The Big Elixir 2018 - Desmond Bowe - Hot Upgrade Are Not Scary https://www.youtube.com/watch?v=IeUF48vSxwI

Does Phoenix Live View currently support or intend to support SSE over HTTP2 instead of websockets?

Where are you seeing 6MB on Medium? It looks everything aside from images is <1MB compressed.


If I get this correctly, both this and Blazor are handling most of the UI logic in front-end, despite they are WASM.

So WASM is just another bytecode encoding that relatively smaller than JavaScript, without solving the problem from the root.

In contrast, a server-side heavy solution like Phoenix LiveView that has been heavily mentioned in this thread would do hold the logic on the server side, so in the client, there's only very few generic logic handling the DOM patching.

iirc WASM will tend to be larger than minified javascript.

It depends on the JS and the WASM framework... Blazor in particular carries a lot of framework overhead with it. Also, like mentioned elsewhere in the article, something similar to JSX for one of these WASM frameworks would be very useful. As would a close to in the box UI toolkit that at least used or resembled material design or bootstrap.

Blazor's bundle size (assuming client/wasm rendering) is pretty damned big. Also, JS is a pretty cool language imho.

Blazor is nowhere near optimized yet - give Microsoft some time. They just committed to Blazor officially (it was an 'experimental' project until the 19th of April.)

From the README

  One crate to rule the DOM
  One crate to find the elements
  One crate to bring JSON
  And in the Rust code bind Strings

"Lord of the Crates" doesn't quite have the same ring to it

Cardinal of the Crates?

Lord of the Strings

Sauron looks really great and I for one am super excited about the future of Rust + WASM for web apps(with Backend). However I am a bit concerned that even the minimal example is 1.17MB of WASM which seems really high since Rust compiled to WASM should be quite small.

You need to use the script for release mode.

$> wasm-pack build --target no-modules --release -- --features "wee_alloc"

It will shrink it down to 165KB

Doh. My bad for being a dummy.

165kb is still fairly big for a minimal example, much smaller than 1.17MB though, compared to React for example. Are there ways to analyze what contributes to the size for WASM compiled projects? I guess wasm-bindgen contributes significantly to the size currently.

EDIT: It's 68KB gzipped and 165KB is the uncompressed size. One great benefit of WASM is that as described in "Making WebAssembly even faster: Firefox’s new streaming and tiering compiler"[0] it's much faster than JS to parse and execute.

0: https://hacks.mozilla.org/2018/01/making-webassembly-even-fa...

I think If you start adding more code, the growth of the release binary will diminish. The todomvc code is only 207KB when compiled and has relatively more code than the minimal example.

There is a lot of rust compilation flags, and I have only tested a few. I also enabled a lot of wasm-bindgen features in the library, I will eventually tighten it up.

On top of that it's still pretty favorable compared to other web framework sizes.

> EDIT: It's 68KB gzipped and 165KB is the uncompressed size

What's the state of brotli content type support in browsers? Wasn't that supposed to be the next generation beyond gzip? Would it get a better still compression ratio? And FB is pushing zstd -- is that something that might be supported eventually?

168k is nothing, that's less than an image by the standards of many web elements these days.

It's still a lot given that when targetting the entire world (especially either mobile links or portions of the globe that don't have a CDN a millisecond away), a typical assumed link is on the order of 512 kbps bandwidth with 100ms RTT. That's two and a half seconds to load just your framework with a cold cache and without including any content.

Yes, many web developers are just targeting their own areas and test on high-speed links and everything seems fine, but frameworks that aim for widespread use still need to care about every single byte.

jQuery is 84KB. react + react-dom is 109KB. Bootstrap 4 is 187KB.

Par for the course

Images are not comparable to WASM and especially not to JS. This is described in "Making WebAssembly even faster: Firefox’s new streaming and tiering compile", but the TL;DR is that network is less so the bottleneck than parsing and execution these days.

Further the notion that 168kb is nothing is a bit sad when you consider emerging markets and other low bandwith/CPU scenarios. One of my hopes with WASM is that it can achieve both smaller bundles and better parse/execute performance. To my understanding one of the big blockers for this right now is the lack of a DOM API for WASM.

I think you can still reduce that size further with binaryen

Elm gets plundered repeatedly before it ever reaches version 1.0. Is name-brand Elm still growing in adoption?

> Elm gets plundered repeatedly before it ever reaches version 1.0.

I concur. Ever since Elm 0.17 [1], when Evan removed event streams and standardized on The Elm Architecture, Elm seems to have lost its way. Just saying as an interested outsider.

[1] https://elm-lang.org/blog/farewell-to-frp

I presume it is a matter of perception: Elm is now perceived as a GUI toolkit rather than a language in its own right. Elm achieved simplicity and, ironically because of that, it is now plain easy to port its main ideas to other languages.

Because elm is elegant. I have written web-app with elm on the client side and rust in the backend. It was great, except for duplication of code when serializing/deserializing json data when making API calls. With sauron, I save up a lot of duplicated codes, and gotta squeeze that webassembly performance as well.

Do you have any experience with Sauron vs Yew? I'm quite interested in Yew due to the benchmark and that their code examples look similar to me. Yew also says Elm inspired.

Since I don't know anything about Elm, I'm curious to see what about Sauron makes it more Elm-y than Yew.

The main issue with Elm is the glacial development pace. I understand why it is the way it is (it shows in how well designed what is there is), but it really does hurt as someone who wants to adopt it.

some might say that’s a feature though!

Yep! I'm writing this from Elm in the Spring, the 2nd of 4 dedicated Elm conferences in 2019.

JS/TS continue to dwarf everything else, but it's possible that Elm is the most widely used JS alternative at this point. (Hard to know definitely though!)

> it's possible that Elm is the most widely used JS alternative at this point

Cough. Cough. Clojurescript. Cough.

I like to think Elm is the most influential web framework that no-one uses.

We're using Elm for our front-end UI. With Erlang in the backend (not Elixir). It's very reliable and predictable. I hope it succeeds.

How is Elm/Om doing so well in those benchmarks? I would think that most wasm frameworks would be able to blow past any js framework fairly easily.

edit: Ah, calls to js are still necessary to create DOM elements, so there's lots of back and forth necessary in the wasm frameworks.

Would it be fair to expect the performance to get better once the Web IDL Bindings Proposal for WebAssembly is done?

If my hypothesis is correct and it loses ground in benchmarks due to overhead of calling js dom methods, then I would expect native bindings to improve performance. I'm not an expert or anything in this field though, so maybe someone closer to the issue can chime in.

Yes, that's why it's being pursued.

Obvious questions first: How does it compare to Yew?

1.) The syntax in creating the view: is just plain function calls which the rust compiler can accurately tell you about errors in your code, ie: typo, unclosed brackets/braces/parenthesis mismatch.

2.) Concise code, there is not too much ceremonial/boilerplate code to get started.

3.) Less code in the library maintain, there is no parser(which are mostly complex).

4.) Sauron is using wasm-bindgen, yew is using stdweb.

5.) It's in the early phase, so the performance is not yet optimized. https://github.com/ivanceras/todomvc-perf-comparison/

Thanks, good luck with this project :) I'm looking forward to a mature Elm-like web framework in Rust in the future.

> 4.) Sauron is using wasm-bindgen, yew is using stdweb.

FYI, since the most recent stdweb version it's possible to use `wasm-bindgen` with Yew

Nothing compares. Nothing compares to Yew.

In which way?

It's based on Yew itself and since Yew is React/Elm like, but this is more Elm inspired I assume it compares like Elm vs React.

As far as I can tell by the Cargo.toml file, it's not based on Yew.

The README mentions "This project is based on the existing projects: (...) Yew (...)", but I think the author meant "inspired by", not "based on".

What I mean "based" is "I look at their code, and take only what I need".

Performance: Is not too bad.

I laughed at this, idk why.

The usual mentality is "Use us 'cause we're faster than all those SLOW frameworks!" and then they show you a graph of a benchmark was in a specific instance they're X faster than the common options.

It's fun to see some people being honest about it. "It's good enough" is pretty honest here.

I traded a bit of performance for aesthetics by cloning the children of a node. I tried the todomvc benchmark and saw it wasn't so bad without employing optimizations in placed. It's still in it's early stage though.

yeah sorry. i meant that i laughed at it in a good way. i just found humor in the way it was worded.

The Rust community has high standards for perf!

Would there be an easy/straightforward way to put a jsx transpiler in front of the rust compilation step, potentially with hot reloading?

I realize that jsx in react is really just calls react.createElement, but I do think it's a very useful abstraction when you're ultimately constructing html.

The main issue is that jsx can contain both mutable references to a variable and immutable references. For example <div onClick={() => count = count + 1}>{count}</div> contains both a mutable reference to count and an immutable reference. Thus, the naive way of storing this in a single struct will fail. The use of the elm architecture (where the onClick handler returns a message, instead of directly updating count) side steps the complicated borrow-checker issues.

It is certainly possible to get around this with the proper procedural macro, but it is not easy, and will never be as "magic-free" as people want.

Look into the framework Yew. It sits somewhere between elm and react in how it's designed, and makes use of an html macro that allows for jsx-like markup.

Since Rust supports macros, I think you can actually implement most of JSX's syntax in it directly without needing an additional compiler.

(Disclaimer: very limited knowledge about WASM)

Curious as to how WASM impacts browser caching?

In the JS scenario, several modules will be cached and change in one may still allow usage of other cached modules, thereby reducing future load times.

How will that work in WASM work, since I'm assuming that the entire app will be packaged at build time as a single binary. Is the assumption even correct?

Or, is it simply a question of architecting your app well into several WASM modules, since I'm assuming WASM modules (or whatever they are called) can call each other and do lazy loading.

I can see this going in two ways: either we'll have WASM "shared libraries" that can be cached, or every website will go the way of apps and contain duplicate WASM modules in it.

Commend on the attempt, foward thinking now wasm is getting more traction. but I can imagine that view syntax turning into an insane > circa the old days of callbacks in nodejs

Not convinced that's the case, with a bit of code splitting the view may end looking more like (pseudo-code):

    fn view(&self) -> Node<Msg> {
        div(self.attributes(), self.content())
    fn content(&self) -> Node<Msg> {
            class("client"), r#type("button"), value("Click me!"),
            onclick(|_| {sauron::log("Button is clicked"); Msg::Click})

You can also take a look at the window_tab_rows example. It will allow you to modularize into isolated subcomponents which you can embed into the main component.

As long as all event callbacks are delegated into the update function and unified in an Msg enum, the code will have the same pattern regardless of how big the project is.

Didn’t mean callbacks, meant shape of the code with indents could get large and difficult to grep. JSX style macro over the top might help .

In that case, breaking up the functions into several smaller functions helps. The rule of thumb of the size of a function body shouldn't be larger than the size of a computer screen.

Looks cool, really like the name. It’s always interesting to me to see other developers who are good at branding, despite no obvious marketing background.

Thanks. I think I'm pretty good at naming. I have a few repo with good names as well.

rustorm - an orm in rust

diwata - a database UI in rust.

Hey, interesting! Have you seen dodrio from mozilla? Could be a good candidate for your diffing algorithm and improve performance a lot.

Check out http://blazor.net/

So one thing, these are still slower and more expensive in performance, compared to JS frameworks, right?

Slightly off topic - I can’t imagine calling the framework Sauron and posting a photo from the LOTR movie is legal.

Probably not, technically, but it's sort of in that (Gandalf The) Grey area where nobody really gives a shit so you'll get away with it. This is just a random project on GitHub, it's not like a major corporation is putting this out. If they did, they could just remove the copyright images and possibly rename it if they felt it was really necessary.

I’m not an expert, but that seems like an example of fair use to me.

Is that the Internet's idea of "fair use" which is "I can pretty much do whatever I want as long as I say 'fair use'", or the legal one?

Calling it Sauron is almost certainly OK. Using an image from the movie probably isn't, and the reason why isn't copyright, it's trademark. It makes it look like it may be officially related to the trademark owner. This may sound silly to you, but in a world where the New York Times has an active open source contribution page, along with other non-tech-companies that have put out open source like financial companies, audio companies, etc., the idea that a movie production company might put out a web framework is well within the bounds of possibility. For similar reasons, calling it Sauron is OK but I'd want to lean away from any obvious relationship to the Lord of the Rings, such as posting a satirical version of the ring's inscriptions. (A literary estate putting out a web framework is much less plausible, but on the other hand, they're well known to be on the litigious side, so personally I'd avoid it even so.)

On the plus side, the worst case plausible scenario is a cease and desist, which may never come. Things only get nasty if the project refuses after that.

The granting of trademarks is narrower than that. The protection only applies to products and services that are "identical or 'colourfully' similar to the "registered" products or services".

This is not to say that the holder would still not litigate out of fear of losing their mark, though.

That's for using the same word for different things. You can start a new company called Apple in other industries, no problem. You can not use the Apple computer company's logo as yours, though.

You can probably use Sauron, but you can not literally put up a picture of the Eye of Sauron as your project logo without making it appear that you are operating specifically as that trademark holder. With that picture, they're not just claiming to be "a" Sauron, they're implicitly claiming to be associated with whoever currently holds the rights to those movies.

(I'm only hedging on the "probably" because of the known litigiousness of the Tolkien estate. Normally it shouldn't be a problem.)

In Europe probably not. In the US it falls under first as fair use.

I'm still waiting for something like scala.js for Rust. I don't like the thought of using two different programming languages and currently it seems scala.js is the most dependable front-end library

What specifically are you waiting for? You can already run rust in the browser, by compiling it to wasm and talking to the DOM using wasm-bindgen (like this Sauron library is doing).

You ever tried Clojurescript?

Folks please take care in how you name your open source project. Sauron is not something I want to think about every time I sit down to work, neither are cockroaches (CockroachDB).

Does Sauron evoke some sort of primal disgust in you like cockroaches do?

There was a time when people named stuff after positive things. If you asked my psychologist ex about people who name things after Saurons and Cockroaches, she'll jump to some 'priliminary conclusions'. This country needs frequent mental checkups like we have frequent dental checkups

That's white supremacist thinking... /sarcasm

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact