use axum::{ Router, body::Bytes, extract::Path, http::{StatusCode, header}, response::IntoResponse, routing::{MethodRouter, get}, }; use include_dir::{Dir, include_dir}; use mime_guess::from_path; static DIST_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../frontend/build/client"); const INDEX_HTML_PATH: &str = "index.html"; const INDEX_FILE_NOT_FOUND_HTML: &str = r#" 404 Not Found

404 Not Found

The requested resource was not found on this server. Possibly the frontend build is missing or corrupted.

"#; pub fn get_view_router() -> Router { Router::new() // Serve the root index.html .route("/", get(root_view_handler)) .route( "/{*wildcard}", MethodRouter::new() .get(|Path(path): Path| async move { view_handler(Some(path)).await }), ) } async fn root_view_handler() -> impl IntoResponse { view_handler(None).await } async fn view_handler(path: Option) -> impl IntoResponse { // If path is empty, serve index.html let incoming_path = if let Some(p) = path { p.trim_start_matches('/').to_string() } else { INDEX_HTML_PATH.to_string() }; let path = match DIST_DIR.get_file(&incoming_path) { Some(_) => incoming_path, None => INDEX_HTML_PATH.to_string(), }; match DIST_DIR.get_file(&path) { Some(file) => { let mime = from_path(&path).first_or_octet_stream(); let body: Bytes = Bytes::copy_from_slice(file.contents()); ([(header::CONTENT_TYPE, mime.as_ref())], body).into_response() } // This should never happen, but just in case... None => ( StatusCode::NOT_FOUND, [(header::CONTENT_TYPE, "text/plain")], Bytes::from(INDEX_FILE_NOT_FOUND_HTML), ) .into_response(), } }