How to embed svelte site in Rust binary with Axum?

I want to fully embed my entire Svelte site into a binary and use Axum to serve it.

Is there a way to achieve this?
Is V8 required?

My main issue is that with embedded files, I don't see a way to make the files understand that script.css (or other assets) isn't on the filesystem but in memory.

You'd still need to provide an endpoint that serves the file, even if the file is in your server's memory and not on its file system.

I'd suggest looking at Tauri (if you're goal is to embed a browser-based UI into a binary).

But it looks like you want to embed the server in a binary and serve the result using axum. I have no advice for this. It's not the kind of thing people usually do.

This crate might help solve part of the problem:

We already use Tauri for casual applications, but it isn’t suitable for our needs.

Our goal is to set up a server on specific computers that grants access to certain files through a static site generated with Svelte.

I've seen this crate and even use it indirectly in some projects (for embedded Fluent translations), but I'm not sure if it allows the index.html file to see and use the styles.css file.

Another issue is how to link an endpoint to these files, and these are rather interconnected things.

Would something like nginx work? It would be able to reverse proxy traffic to both the static site and the certain files. You could of course only run it on specific computers.

It would need the correct configuration of course, but that could probably be generated along with the static site.

But I probably have the wrong end of the stick entirely, I lack some context or experience to understand your requirements.

Assuming you're using vite to build the svelte project, my first thought is, after building the svete project for production, just creating a bunch of -> &'static str axum endpoints that just include_str!("build/index.html"), include_str!("build/assets/index.js"), etc.

My second thought is to use crabtime to iter the /build directory and create an axum endpoint as above, at compile time.

We want to create a fully embedded application that can run on Windows, Mac, and Linux without relying on Docker or other external dependencies. Since this app will be installed by our clients—many of whom may not be technically inclined—we aim to keep the setup as simple as possible.

My first idea would be to package the data served by the webserver in a tarball or zipfile and include it in the binary. Then make the webserver serve the files from the tarball or zipfile.
This can either be done on the fly (extract on request) or you can extract the archive to a temporary directory, either on the disk or into RAM when the application starts.

I didn't want to use this solution because I thought there must be crates that can do it automatically. But in my tests, axum_embed and similar crates not worked (I probably did something wrong), so I decided to try this approach.

Crabtime looks a bit too complicated for me for this task, so I just used build.rs, which runs a Python script to generate Rust code like this:


pub(crate) fn generate_router() -> Router {
    Router::new()
        .route("/", include_str_item!(include_str!("../static/app.html"), "html") )
        .route("/favicon.png", include_bytes_item!(include_bytes!("../static/favicon.png"), "png") )
}

fn into_simple_response(item: &str/&[u8], extension: &str) -> impl IntoResponse {
  let mime = match extension {
    "html" => mime::TEXT_HTML_UTF_8.as_ref(),
    "css" => mime::TEXT_CSS_UTF_8.as_ref(),
    "js" => mime::APPLICATION_JAVASCRIPT_UTF_8.as_ref(),
    _ => panic!("Unsupported extension - {extension}"),
  };

  let header = [(
    header::CONTENT_TYPE,
    HeaderValue::from_static(mime),
  )];

  (item, s).into_response()
}