back
171 comments
> This is somewhat similar to what Electron accomplishes, but your backend is in Rust rather than JavaScript, and the user navigates to the app from their browser.

An option in the middle is webview[0] which will "appify" it by using OS-native browser lib so you don't have to carry Chromium, V8, or all the multi-process ugliness but you still get the web stack.

Also everybody, don't forget to check your Host headers when building apps running HTTP daemons locally or you'll be open to DNS rebinding attack. And if your use case can support it, a random port is nice too.

0 - https://github.com/zserge/webview 1 - https://en.wikipedia.org/wiki/DNS_rebinding

> This is somewhat similar to what Electron accomplishes,

What? This is nothing like Electron. What it's like is shipping the `node` executable to the end-user along with a .js script. The whole point of Electron is that it bundles a browser.

I just wish electron could somehow harness the fact that everyone has a browser installed.
> ... DNS rebinding attack. And if your use case can support it, a random port is nice too.

Ah, that's a good explanation as to why zserge/webview recommends serving using ephemeral ports.

Also, wanted to pull in from the readme: webview supports interacting with the javascript environment directly, so a web server isn't strictly required.

With all that work why not just link to gtk and build on that?

Why should a desktop app even care about host headers?

Is webview more like Phonegap (throwback) than Electron?
This looks awesome. Does it add much size to the binary?
"Because I’ve been obsessed with static linking for as long as I can remember and I’m not really sure why."

Glad I'm not the only one.

When I was younger, I made a hobby Linux distro that ran completely on floppies with a custom filesystem hierarchy. All the binaries were in /Programs and were statically linked against uClibc. Even X was statically linked, there was some abandoned branch of XFree86 that ran with a VESA driver and fit under 1.44 MB. I thought that I was the bee's knees.

All this was still possible ~2007. Not sure how masochistic you'd have to be to try today.

Same, although people think it's silly I find it less error-prone. The same goes for C++ libraries, only using singe-header or amalgamations because it's less to support and ABIs wont break between versions.
Being able to include arbitrary data inside a static binary is definitely a nice side-effect of rust and golang being able to produce static binaries.

If you're interested in stuff like this for go, I've used https://github.com/GeertJohan/go.rice with great success.

[EDIT]

"feature" -> "side effect"

"rust and golang" -> "rust and golang being able to produce static binaries"

Yeah its definitely nice to avoid an annoying "binary" to source step and then have to waste a bunch of cycles to parse/compile said source. I do embedded work and run into this all the time with C and C++. Its toolchain dependent on how to import binary blobs unfortunately in C/C++. You very quickly run into a wall on how large of a source file can be compiled around 100 MB or so. gcc is the best at handling huge source files, but its still slow.

For example, you can do the import with gcc this way: https://balau82.wordpress.com/2012/02/19/linking-a-binary-bl...

With Green Hills, there is a .rawimport directive.

Maybe for younger generations.

Apple and Microsoft systems have been supporting this on their native toolchains since the mid-90's.

How does go.rice compare with go-bindata[0]? I only have experience with the latter.

[0] https://github.com/jteeuwen/go-bindata

This looks really cool. I'd love to have a library for Rust to make this more seamless. In particular it would be nice to have a "development mode" where you just host the HTML/JS files normally while you're working on them, then flip a production switch when you're ready to have them compiled into the binary. Does go.rice have something like this?
Are these basically statically linked jars?
I turned my private website (not the one listed on my HN profile) into a single binary doing something similar to what OP is doing, except I didn't know about include_str!, only include!, so in my build.rs I first read in my static files and then I write them out as byte array declarations into intermediate Rust files which I then include! in my src/main.rs.

Thanks to this short blog post by OP I learned something that will let me simplify some of my code.

However the thing that I am doing is not completely useless, because I have been able to embed fonts, favicon and images as well with the method that I am using.

The code I have written for this is only the beginning but if anyone wants to look at my code in order to see how I did it here you go:

https://gist.github.com/ctsrc/4c4cc05254d12bbc8937a0ea385fcd...

It's far from great but it's a start. Let me know how you would do it better :)

Speaking of Rust and websites, in Python I have fallen in love with the pyTenjin templating engine. http://www.kuwata-lab.com/tenjin/pytenjin-users-guide.html. Does anyone know of a templating engine like pyTenjin but for Rust?

> However the thing that I am doing is not completely useless, because I have been able to embed fonts, favicon and images as well with the method that I am using.

FWIW there's also an include_bytes! macro to embed binary data right into the executable without going through a separate rustification step.

You can do this in pretty much any language. Back in the early 2000's, people used to take the Perl source code and replace the main loop (you know, the part that actually opens files and reads in your "perl scripts") with the text of a cut and pasted perl script. So when the executable ran, instead opening a file, it simply ran the perl code that was nothing but a (giant) string within the perl interpreter executable. Nothing stopping you from including the code from a perl http server or other perl framework instead. I think cpanel did something like this for many years as their toolset was all perl but distributed as a single binary file.
Can of course still do this with FatPacker: https://metacpan.org/pod/App::FatPacker

But, AFAIK, only supports Pure Perl code, so one is SOL for most database drivers etc...

If is interesting to you, I also suggest to check out my Rust crate bui-backend[0]. This is a library for building Browser User Interface (BUI) backends. The key idea is a datastore which is synced between the backend and the browser. The demo has several example frontends. The most interesting perhaps is the yew[1] framework, which is somewhat like React but in Rust. This lets you share code directly between the backend (natively compiled) and frontend (compiled to wasm). There is also a pure Javascript frontend, an Elm frontend, and a Rust stdweb frontend in the demo.

0 - http://github.com/astraw/bui-backend 1 - https://github.com/DenisKolodin/yew

I don't see the point of this. Why not use nginx which comes with startup scripts and point it to the site's directory that includes the bundle/index files?

If the single binary that just serves static files you're better off with a web server that supports https, rules, vhosts, etc and is battle tested. Not to mention that this binary you created will need startup scripts of some sort depending on the platform.

Ultra portability. And there shouldn't be any startup scripts, however, the binary does need to be compiled for the target platform.

I'm pretty sure the use case of this is more akin to an electron replacement, and not a production web server. So the user would just download and run the binary, and interact with the app from their browser.

I don't see point of this either. I aware this would cost me lot of hardly obtained karma, but I feel I have to say this.

Strange how some people are obsessed with hype. I think what raised interest of this article was just word "Rust" in the title. Rust seems to be wet dream of many developers. They heard it's safe, so it will magically solve all their problems. But the usage of Rust in this case is meaningless. You could do the same with python, nodejs, java, just plain nginx or million other (and better) ways. Just first google query returned probably better solution if you like single static binary http://miniweb.sourceforge.net/. It would be two files instead of one miniweb binary and static site compressed as 7z.

How does this thing scale? What about SSL? Do I have to put reverse SSL terminating proxy in front of it? Yes, you say? Ok, why not just use that proxy for serving those static files too (nginx does that) and skip this thing completely. What about performance? Have you tried to httperf on it?

I would appreciate if this did more then just being a single binary. Like Facebook's HipHop compiler of PHP to static executable or something like that. Sorry but this is real bullshit.

How about a web interface on an embedded device?
As widely used/loved as nginx seems to be, I couldn't for the life of me find any good resources that hand hold a bit more than just reading the docs and hoping for the best.

Know any good nginx books or courses?

Back in the day, Shopify distributed a standalone version of their store server so people could write themes. It was pretty neat. I could see this being used for something similar.
Have done several sites in this exact fashion, except coded in Nim, not Rust. A reasonably sized, musl-linked, absolutely standalone executable with SQLite baked in for data storage. That's two files all told - the program and the data. Super simple deployment, I usually stuff the thing behind a Caddy server these days. Never let me down so far.
I've never used rust before, but have been meaning to look into it and play around some. OP mentions the include_str! function(maybe its a function, not sure what '!' signifies here) and it blew my mind.

I'm betting that almost every language that I've used has something like this, but the succinctness of it and how it's used to keep the source clean, but still compile in the text is really cool.

There's a small typo on the article in /ui/dist/index.html - the script source should be '/bundle.js', not '/main.js'. I think the git repo corrected this error
I do similar, except I just deploy to AWS as a static website. Super duper minimal everything.
I've done this same thing before with Node using [nexe](https://github.com/nexe/nexe) and musl.

With a little bit of effort it's also possible to build and statically link native modules, eg I've had success with nodegit, uws and sqlite. (Needed to rebuild some of the node deps with musl, then rebuilding the native modules with musl, then modifying Node's node.gyp to --whole-archive include the additional .a/.o's (done in nexe), and using rollup to rewrite the .node includes to `process._linkedBinding('the registered module name')`, and then nexe builds the whole lot into a single executable.)

Nexe supports bundling resources (although less cleanly than `include_str` imo) so it can also bundle all your ui resources as well.

Fossil (http://fossil-scm.org/) has been doing very similar for a while in plain C, it ships statically-linked and includes a CLI and a web UI. (not in React, however)
I love these things. I made my resume page by piping together two small rust pograms and a bash script to get a single html, from a json in firebase, a handlebars template and several static assets.
I really like this guide to get started.

Its a bit short though. I would really like to see the setup of a simple uni- or even bi-directional rpc or value binding mechanism between react and rust.

Cool small example. It's helpful to have the actual cli commands on hand.

There's just a small typo. The script path in the HTML mount file and the router path need to be the same, but do not match. Either one needs to change:

    // ui/dist/index.html

    <script src="/main.js"></script>
    


    // src/main.rs

    (GET) ["/bundle.js"] => {
        Response::text(bundle)
    },
How hard would it be to use something like this to deploy directly onto a hypervisor, like with Erlang on Xen?
One reason this is nice is that certain build systems make it easy to copy 1 file or variable into a repository, so this might be easier than pushing a container to a private repository that can be somewhat configuration error prone. However personally I might still use Docker with this :)
To simplify statically cross compiling Rust code for different target platforms, including musl and openssl support, check out https://github.com/messense/rust-musl-cross
For me, the Rust syntax is hard to look at and read. I much prefer Go which reads like C, Perl, PHP, JS or many other common languages.

I'm wondering if people who prefer Phython prefer Rust? I've been developing for 20+ years and the syntax alone makes Rust feel prohibitive to me.

Is there something like "50% statically-linked". I'm trying to understand if static linking can be partial. I often see it done it all in or none.
I wanted to use rust for web development for a while but always struggled with just getting an OAuth2 example running in the past, has this improved recently?
Can it pass C10k?
Or, you know... Python.
it's very rare to only run one http based server app (port 80). So you probably want to put a proxy (like nginx) infront of it, but then you could just let it serve the files.
(misunderstood)
If you want the same thing only with C# instead of Rust you can use https://github.com/ElectronNET/Electron.NET