feat: add favicons, support embedded assets properly

- Refactor asset serving to check embedded assets before proxying
This commit is contained in:
2026-01-06 12:26:06 -06:00
parent c6dd1dffb0
commit be718976d6
8 changed files with 25 additions and 3 deletions
+11 -1
View File
@@ -9,10 +9,14 @@ static ERROR_PAGES: Dir = include_dir!("$CARGO_MANIFEST_DIR/web/build/prerendere
pub async fn serve_embedded_asset(uri: Uri) -> Response { pub async fn serve_embedded_asset(uri: Uri) -> Response {
let path = uri.path(); let path = uri.path();
serve_asset_by_path(path)
}
/// Serve an embedded asset by path, or return None if not found
pub fn try_serve_embedded_asset(path: &str) -> Option<Response> {
let asset_path = path.strip_prefix('/').unwrap_or(path); let asset_path = path.strip_prefix('/').unwrap_or(path);
if let Some(file) = CLIENT_ASSETS.get_file(asset_path) { CLIENT_ASSETS.get_file(asset_path).map(|file| {
let mime_type = mime_guess::from_path(asset_path) let mime_type = mime_guess::from_path(asset_path)
.first_or_octet_stream() .first_or_octet_stream()
.as_ref() .as_ref()
@@ -39,6 +43,12 @@ pub async fn serve_embedded_asset(uri: Uri) -> Response {
} }
(StatusCode::OK, headers, file.contents()).into_response() (StatusCode::OK, headers, file.contents()).into_response()
})
}
fn serve_asset_by_path(path: &str) -> Response {
if let Some(response) = try_serve_embedded_asset(path) {
response
} else { } else {
tracing::debug!(path, "Embedded asset not found"); tracing::debug!(path, "Embedded asset not found");
(StatusCode::NOT_FOUND, "Asset not found").into_response() (StatusCode::NOT_FOUND, "Asset not found").into_response()
+10 -1
View File
@@ -23,7 +23,7 @@ mod middleware;
mod og; mod og;
mod r2; mod r2;
mod tarpit; mod tarpit;
use assets::serve_embedded_asset; use assets::{serve_embedded_asset, try_serve_embedded_asset};
use config::{Args, ListenAddr}; use config::{Args, ListenAddr};
use formatter::{CustomJsonFormatter, CustomPrettyFormatter}; use formatter::{CustomJsonFormatter, CustomPrettyFormatter};
use health::HealthChecker; use health::HealthChecker;
@@ -1235,6 +1235,15 @@ async fn isr_handler(State(state): State<Arc<AppState>>, req: Request) -> Respon
return (StatusCode::NOT_FOUND, "Not found").into_response(); return (StatusCode::NOT_FOUND, "Not found").into_response();
} }
// Check if this is a static asset that exists in embedded CLIENT_ASSETS
// This handles root-level files like favicon.ico, favicon.svg, etc.
if is_static_asset(path) {
if let Some(response) = try_serve_embedded_asset(path) {
return response;
}
// If not found in embedded assets, continue to proxy (might be in Bun's static dir)
}
let bun_url = if state.downstream_url.starts_with('/') || state.downstream_url.starts_with("./") let bun_url = if state.downstream_url.starts_with('/') || state.downstream_url.starts_with("./")
{ {
if query.is_empty() { if query.is_empty() {
+3 -1
View File
@@ -35,7 +35,9 @@
</script> </script>
<svelte:head> <svelte:head>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="icon" href="/favicon-192.png" type="image/png" sizes="192x192" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<!-- Primary Meta Tags --> <!-- Primary Meta Tags -->
<title>{metadata.title}</title> <title>{metadata.title}</title>
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.2 MiB