assets.rs
⎇
Raw
1//! Static frontend assets: embedded at compile time (`--features embedded`)
2//! or read from disk in the dev flow (Trunk's output dir or $FBNG_DIST).
3
4#[cfg(not(feature = "embedded"))]
5use std::path::PathBuf;
6
7#[cfg(feature = "embedded")]
8mod embedded { use rust_embed::RustEmbed;
9
10 #[derive(RustEmbed)]
11 #[folder = "dist/"]
12 pub struct Assets;
13}
14
15/// Look up an asset by (slash-separated) path.
16/// Returns (bytes, content-type, cache-control).
17pub(crate) fn get_asset(path: &str) -> Option<(Vec<u8>, String, String)> {
18 let (bytes, from_disk) = read(path)?;
19 let mime = mime_guess::from_path(path).first_or_octet_stream().to_string();
20 let cache = if from_disk || path == "index.html" {
21 "no-cache".to_string()
22 } else {
23 // Trunk hashes asset file names, so they are safe to cache forever.
24 "public, max-age=31536000, immutable".to_string()
25 };
26 Some((bytes, mime, cache))
27}
28
29#[cfg(feature = "embedded")]
30fn read(path: &str) -> Option<(Vec<u8>, bool)> {
31 embedded::Assets::get(path).map(|c| (c.data.to_vec(), false))
32}
33
34#[cfg(not(feature = "embedded"))]
35fn dev_dist_dir() -> PathBuf {
36 std::env::var_os("FBNG_DIST")
37 .map(PathBuf::from)
38 .unwrap_or_else(|| {
39 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../web/dist")
40 })
41}
42
43#[cfg(not(feature = "embedded"))]
44fn read(path: &str) -> Option<(Vec<u8>, bool)> {
45 let p = dev_dist_dir().join(path);
46 if p.is_file() {
47 std::fs::read(&p).ok().map(|b| (b, true))
48 } else {
49 None
50 }
51}
52