Using servo as a GUI Library

Question: Is there anyway to use Servo as a Rust GUI library?

Pre-emptive comments:

1. Why would you want to do that?
A: Of all the GUI libraries out there, I dislike HTML/DOM least.

2. Why not just use rust/wasm32, stdweb, yew?
A: I like debugging Rust more than I like debugging rust/wasm32.

3. Why Servo ?
A: It basically has all the GUI components I could ever want. If only there was a way to use it as a GUI library.
3 Likes

In other words, you are searching for an electron that uses servo as display engine rather than whatever chrome and safari are using?

I can tell you that there are frameworks that want to make working with electron easier, but all of them require you to compile at least parts of your code to wasm.

Then they connect via abstracted IPC to a server process running in "native" rust binary.

I'm not aware of something similar that uses servo, but even if there were, I'm pretty sure it would rely on wasm as well.

It seems with an Electron based approach, one ends up either:

  1. writing lots of rust/wasm32 OR
  2. building something similar to threepenny-gui: GUI framework that uses the web browser as a display. where the logic is in server-side-rust, and the 'gui' is a very thin rust/wasm32/dom layer which does communication over websockets

Why do you believe that using servo would rely on wasm? Servo itself is able to display DOM elements, despite being only in rust. It seems like there should be some layer there that we can hijack and use.

Servo is a rendering engine for HTML and not a GUI Toolkit like GTK or wx. I have not looked at its exposed interface and if it provides necessary types, functions etc to directly inject gui elements and listen for their events.

But taking the idea of electron and porting it to servo seems to be the most obvious thing.

1 Like

Have a look at "Azul" it is specifically working on this idea. Now, it doesn't bring in the whole "Servo" but rather uses the "Webrender" part of servo as a lightweight library to create a GUI framework. Personally, I think this is the best idea I've seen for a Rust GUI library that can gain real traction.

11 Likes

@gbutler69 : Azul looks amazing. Is there by chance a way to toggle the Azul output, i.e.

one code base

mode 1 = outputs desktop app, panics = stack traces, debug as desktop app

mode 2 = uses wasm32-unknown-*, and outputs a wasm32 that I can run in the browser?

This would be amazing. :slight_smile:

2 Likes

Not that I'm aware of, but, it doesn't seem like something that couldn't fit with its overall design. I do know that the developer of Azul (last I heard) is not accepting PR's as he wants to get something "working" before he opens it up to a lot of discussion. He has a particular vision himself and wants to see his vision through to a 1.0 release before trying to incorporate others' visions (which I find a reasonable position). That being said, it couldn't hurt to open and issue or start a discussion with him, or, alternatively, fork it and try building a fork with your own ideas.

Electron apps can link to native libraries, so you can also use neon (and neon-serde) rather than wasm or websockets. See Building a fast Electron app with Rust

The point is that with Electron, short of something like ThreePenny, the code that manipulates the DOM has to be in JS.

Which means Rust -> wasm32.

Are you telling me that in Rust/Electron, it is possible to directly manipulate the DOM in Rust, without going through JS?

No, azul doesn't support WASM, at least right now - while you can theoretically re-route the OpenGL to WebGL, this is really not a practical solution as custom rendering generally will result in a worse performing application (azul is essentially a mini-browser engine, you'd be running a browser in a browser, which won't be performant). You can however, re-use CSS stylesheets on the web (with some minor adjustments, the layout works the same - absolute / relative layout, padding / margin, flexbox, styling, etc.). In a distant future, there might be a azul-to-DOM compiler and a XML-ish loader (see this discussion). While it would be technically possible to compile Azuls DOM model to HTML, it's not really practical right now.

Once WASM has DOM access and is better supported (i.e. something like <script type="wasm"> - getting WASM to run is currently a pain), it would be feasible to re-use azuls DOM renderer + the business logic in Rust to the web, however, this needs some serious re-architecting and is not a 0.1 goal.

However, webview-rs might fit your description (very similar to threepenny) - essentially business logic in Rust and UI in HTML (communicating between Rust and JS via a JSON rpc). This would be portable to WASM with a bit of effort.

About the PRs: Sure, I do accept PRs and bug fixes, but yeah I do have a plan / architecture in mind. Feel free to open issues about things, that's what they're there for.

3 Likes

Yep. It doesn't have any friendly wrappers like stdweb, but it's definitely possible. I made you an example repo - GitHub - jamii/neon-dom: A minimal example showing how to manipulate the dom from neon in electron.

The only tricky part is that you can't store js values on the rust side between neon calls, so you need a couple of lines of javascript to call require and pass all the necessary modules into rust and then you can do the rest directly in rust.

1 Like

@jamii : Thanks for taking the time to put this together. I can't believe it works.

The only ugliness is the untyped Rust/JS interaction of things like:

    let create_text_node = document
        .get(&mut cx, "createTextNode")
        .unwrap()
        .downcast::<JsFunction>()
        .unwrap();
    let click_me_string = cx.string("click me");
    let button_text = create_text_node
        .call(&mut cx, document, vec![click_me_string])
        .unwrap();

    let append_child = button
        .get(&mut cx, "appendChild")
        .unwrap()
        .downcast::<JsFunction>()
        .unwrap();
    append_child
        .call(&mut cx, button, vec![button_text])
        .unwrap();

Howrver, there only seems to a be a finite # of such calls we need to make, so if we had a library to wrap this, this would be a really cool gui library.

It's pretty mechanical, so I think you could make a macro like let button_text = js!(cx, document.createTextNode("click me"))?; that would handle all the casting and error conversion.

so to clarify , in the future there could be a mode where azul is used like a virtual dom to interface with the browser's ; the xml loader is an unrelated effort and wont be needed it or be part of the infraestructure requiered for a hypothetical web browser version

Yes, that's the idea. Azul has (internally) DOM diffing (not finished yet, though), so that could run as WASM (and then instead of rendering the DOM to the screen, it renders the DOM to the webpage).

1 Like

i have been reading the docs to see if there are any glaring difference between standard css and azul's that would cause the latter to be difficult to run on a web browser . I haven't been able to find any , which makes me question why the toolkit is implementing its own engine instead of using stylo

Stylo is heavily dependent upon the JS execution model, which, in a compiled desktop app that doesn't have JS, doesn't make much sense. There is no concept of "immutable CSS" for example, because on the web, JS can change every CSS property.
Second, cascading CSS is very easy, it's just one function (which can be easily parallelized if needed, but right now cascading isn't a bottleneck).
Third, while there are no differences between azul-css and stylo, there are differences in the type of things that azul supports. Azul does not have any concepts of "buttons" or "input fields" as a browser does, for example. So there is little need for [attribute = "x"] selectors, because azul doesn't have attributes.
Fourth, stylo handles errors very differently - azul just fails to parse the CSS while stylo gracefully fails. Which means that azul-css will be valid CSS, but not necessarily the other way around. Plus, CSS cascading and selection is probably the easiest part, the hardest part is state management and rendering, not CSS parsing.
And last, but not least, stylo has hundreds upon hundreds of dependencies that slow down compile and link time (azul already has 145 dependencies minimum, and it used to have more than 280, I've already cut everything down as much as possible). I don't want to go back to 10-minute compile times and minute-long debug build times, I really don't.

So yeah... stylo does not really offer any advantages, imports hundreds of extra dependencies and is generally not that useful outside of Firefox.

4 Likes

Azul looks really interesting, but I have a hard time knowing what state it's in. The features described sound great, but they're all covered by a giant boldface caveat that suggests none of it necessarily works. An aspirational list is fine, but some clarity on what does work would really help decide whether it's time to dive in.

I check back in every so often to see if the caveat has gone or been updated. However, this time I checked in and there's more detail in an issue, which has been left open specifically for visibility and noted as a FAQ.

Since I'm clearly not the only one, I thought I'd highlight it here too.

https://github.com/maps4print/azul/issues/75

2 Likes

No, azul doesn’t support WASM, at least right now - while you can theoretically re-route the OpenGL to WebGL, this is really not a practical solution as custom rendering generally will result in a worse performing application (azul is essentially a mini-browser engine, you’d be running a browser in a browser, which won’t be performant).

I don't think that it matters that Azul would be less performant on WASM than native. If there is one code base, then users can op-in to the native experience by getting the app. However, having most (or just some) of the app on the web still be completely functional is still very beneficial.

May you like to have a look at the new crate alcro