//! Static frontend assets: embedded at compile time (`--features embedded`) //! or read from disk in the dev flow (Trunk's output dir or $FBNG_DIST). #[cfg(not(feature = "embedded"))] use std::path::PathBuf; #[cfg(feature = "embedded")] mod embedded { use rust_embed::RustEmbed; #[derive(RustEmbed)] #[folder = "dist/"] pub struct Assets; } /// Look up an asset by (slash-separated) path. /// Returns (bytes, content-type, cache-control). pub(crate) fn get_asset(path: &str) -> Option<(Vec, String, String)> { let (bytes, from_disk) = read(path)?; let mime = mime_guess::from_path(path) .first_or_octet_stream() .to_string(); let cache = if from_disk || path == "index.html" { "no-cache".to_string() } else { // Trunk hashes asset file names, so they are safe to cache forever. "public, max-age=31536000, immutable".to_string() }; Some((bytes, mime, cache)) } #[cfg(feature = "embedded")] fn read(path: &str) -> Option<(Vec, bool)> { embedded::Assets::get(path).map(|c| (c.data.to_vec(), false)) } #[cfg(not(feature = "embedded"))] fn dev_dist_dir() -> PathBuf { std::env::var_os("FBNG_DIST") .map(PathBuf::from) .unwrap_or_else(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../web/dist")) } #[cfg(not(feature = "embedded"))] fn read(path: &str) -> Option<(Vec, bool)> { let p = dev_dist_dir().join(path); if p.is_file() { std::fs::read(&p).ok().map(|b| (b, true)) } else { None } }