From 3040e5539b0d9682ba3848eac57a8a2ebc6d51e4 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 11 Dec 2024 12:59:43 +0100 Subject: [PATCH] Fix assets for production --- Cargo.lock | 21 +++++++++++++++ Cargo.toml | 2 ++ src/backend/assets.rs | 59 ++++++++++++++++++++----------------------- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75e2672..18b0cc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1783,6 +1783,7 @@ dependencies = [ "gloo-net", "hex", "http", + "include_dir", "jsonwebtoken", "katex", "leptos", @@ -1797,6 +1798,7 @@ dependencies = [ "markdown-it-heading-anchors", "markdown-it-sub", "markdown-it-sup", + "mime_guess", "once_cell", "pretty_assertions", "rand", @@ -1975,6 +1977,25 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indexmap" version = "2.6.0" diff --git a/Cargo.toml b/Cargo.toml index 7f2abae..ad224d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,8 @@ send_wrapper = "0.6.0" web-sys = "0.3.72" http = "1.1.0" serde_urlencoded = "0.7.1" +include_dir = "0.7.4" +mime_guess = "2.0.5" # backend-only deps [target.'cfg(not(target_family = "wasm"))'.dependencies] diff --git a/src/backend/assets.rs b/src/backend/assets.rs index 7a3b78f..6171878 100644 --- a/src/backend/assets.rs +++ b/src/backend/assets.rs @@ -1,12 +1,16 @@ +use super::error::MyResult; +use anyhow::anyhow; use axum::{ body::Body, extract::{Request, State}, - http::StatusCode, response::{IntoResponse, Response}, }; use axum_macros::debug_handler; +use http::{HeaderMap, HeaderName, HeaderValue}; +use include_dir::include_dir; use leptos::prelude::*; -use tower::ServiceExt; +use mime_guess::mime::APPLICATION_OCTET_STREAM; +use tower::util::ServiceExt; use tower_http::services::ServeDir; // from https://github.com/leptos-rs/start-axum @@ -14,35 +18,28 @@ use tower_http::services::ServeDir; #[debug_handler] pub async fn file_and_error_handler( State(options): State, - req: Request, -) -> Result, StatusCode> { - let root = options.site_root.clone(); - let (parts, _) = req.into_parts(); - - let mut static_parts = parts.clone(); - static_parts.headers.clear(); - if let Some(encodings) = parts.headers.get("accept-encoding") { - static_parts - .headers - .insert("accept-encoding", encodings.clone()); - } - - let res = get_static_file(Request::from_parts(static_parts, Body::empty()), &root).await?; - - if res.status() == StatusCode::OK { - Ok(res.into_response()) + request: Request, +) -> MyResult> { + if cfg!(debug_assertions) { + // in debug mode serve assets directly from local folder + Ok(ServeDir::new(options.site_root.as_ref()) + .oneshot(request) + .await + .into_response()) } else { - Err(StatusCode::NOT_FOUND) + // for production embed assets in binary + let mut headers = HeaderMap::new(); + let dir = include_dir!("target/site/"); + let path = request.uri().path().replacen('/', "", 1); + let content = dir.get_file(&path).ok_or(anyhow!("not found"))?; + headers.insert( + HeaderName::from_static("content-type"), + HeaderValue::from_str( + mime_guess::from_path(path) + .first_raw() + .unwrap_or_else(|| APPLICATION_OCTET_STREAM.essence_str()), + )?, + ); + Ok((headers, content.contents()).into_response()) } } - -async fn get_static_file(request: Request, root: &str) -> Result, StatusCode> { - // `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot` - // This path is relative to the cargo root - Ok(ServeDir::new(root) - .precompressed_gzip() - .precompressed_br() - .oneshot(request) - .await - .into_response()) -}