Skip to content
Clone
eeff292
92 lines 3.3 KB Rust
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
/// 前端构建产物目录(`pnpm build` 的输出)。
const WEB_DIST: &str = "../../../view/dist";
fn main() {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR"));
build_web_assets(manifest_dir, &out_dir);
}
/// 把根目录 `view/dist` 下的前端产物编进二进制:认证中心自带登录页,不依赖外部静态站点。
fn build_web_assets(manifest_dir: &Path, out_dir: &Path) {
let root = manifest_dir.join(WEB_DIST);
println!("cargo:rerun-if-changed={}", root.display());
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-env-changed=KENOAUTH_SKIP_WEB_ASSETS");
if std::env::var_os("KENOAUTH_SKIP_WEB_ASSETS").is_some() {
// 纯后端编译(未装 pnpm 的环境)跳过前端资产,服务启动后退化为 501 页面。
let source = "// web assets skipped via KENOAUTH_SKIP_WEB_ASSETS\npub static ASSETS: &[Asset] = &[];\n";
fs::write(out_dir.join("assets.rs"), source).expect("writing generated asset table");
return;
}
let mut files = Vec::new();
collect_assets(&root, &root, &mut files);
files.sort();
let mut source = String::from(concat!(
"// generated by build.rs from ",
"../../../view/dist\n",
"pub static ASSETS: &[Asset] = &[\n"
));
for file in &files {
let absolute = root.join(file);
let absolute = absolute
.canonicalize()
.unwrap_or(absolute)
.to_string_lossy()
.replace('\\', "/");
let _ = writeln!(
source,
" Asset {{ path: {file:?}, content_type: {:?}, bytes: include_bytes!({absolute:?}) }},",
content_type(file)
);
}
source.push_str("];\n");
fs::write(out_dir.join("assets.rs"), source).expect("writing generated asset table");
}
fn collect_assets(root: &Path, dir: &Path, files: &mut Vec<String>) {
let Ok(entries) = fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
collect_assets(root, &path, files);
} else if let Ok(relative) = path.strip_prefix(root) {
files.push(relative.to_string_lossy().replace('\\', "/"));
}
}
}
fn content_type(file: &str) -> &'static str {
match file.rsplit_once('.').map(|(_, extension)| extension) {
Some("html" | "htm") => "text/html; charset=utf-8",
Some("js" | "mjs") => "text/javascript; charset=utf-8",
Some("css") => "text/css; charset=utf-8",
Some("json" | "map") => "application/json",
Some("svg") => "image/svg+xml",
Some("png") => "image/png",
Some("jpg" | "jpeg") => "image/jpeg",
Some("webp") => "image/webp",
Some("gif") => "image/gif",
Some("ico") => "image/x-icon",
Some("txt") => "text/plain; charset=utf-8",
Some("woff") => "font/woff",
Some("woff2") => "font/woff2",
Some("ttf") => "font/ttf",
Some("otf") => "font/otf",
Some("wasm") => "application/wasm",
Some("xml") => "application/xml",
Some("pdf") => "application/pdf",
_ => "application/octet-stream",
}
}