Files
stash/build.rs
CNWei e522a98f6f refactor: 合并为单 crate,前端改为内嵌 React 控制台
合并 stash-cli / stash-core 为根目录单 crate(lib + bin),新增 React + Vite + TS 控制台替换 Askama 模板。
build.rs 用 walkdir 把 stash-web/dist 同步到 $OUT_DIR/web,由 include_dir! 编译期内嵌,产出单文件二进制。
路由改为 / 与 /assets/** 走内嵌前端,其余交给 ServeDir,缺失路径返回内置 404。同步更新依赖、.gitignore 与 README。
2026-10-21 17:59:08 +08:00

89 lines
2.7 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// build.rs
//
// 把前端产物 stash-web/dist 同步到 $OUT_DIR/web,
// 供 include_dir!("$OUT_DIR/web") 在编译期内嵌进二进制。
//
// 这里只做「校验 + 搬运」,不在这里跑 npm:
// 那样会把 Node 和网络依赖带进 cargo build。
// 编译 Rust 之前请先执行:cd stash-web && npm install && npm run build
use std::{
env, fs,
path::{Path, PathBuf},
};
use walkdir::WalkDir;
/// 前端工程目录,相对 crate 根目录。
const WEB_PROJECT_DIR: &str = "stash-web";
/// 前端构建产物目录,相对前端工程目录。
const WEB_DIST_DIR: &str = "dist";
/// 同步到 $OUT_DIR 下的子目录名,需与 include_dir! 中的路径保持一致。
const EMBED_DIR: &str = "web";
fn main() {
// 前端产物变了要重新嵌入(Cargo 对目录会递归扫描)
println!("cargo:rerun-if-changed={}/{}", WEB_PROJECT_DIR, WEB_DIST_DIR);
println!("cargo:rerun-if-changed={}/package.json", WEB_PROJECT_DIR);
let dist = Path::new(env!("CARGO_MANIFEST_DIR"))
.join(WEB_PROJECT_DIR)
.join(WEB_DIST_DIR);
let out = PathBuf::from(env::var("OUT_DIR").expect("构建环境缺少 OUT_DIR")).join(EMBED_DIR);
// 缺产物就给出人能看懂的报错,而不是 proc-macro 的 "No such file or directory"
assert!(
dist.join("index.html").is_file(),
"未找到前端产物:{}\n请先执行: cd {} && npm install && npm run build",
dist.display(),
WEB_PROJECT_DIR
);
// 必须整体重建,否则 Vite 换 hash 后旧 chunk 会残留在二进制里
let _ = fs::remove_dir_all(&out);
fs::create_dir_all(&out).expect("创建内嵌目录失败");
copy_dir(&dist, &out).expect("复制前端产物失败");
}
/// 用 walkdir 递归复制 `from` 到 `to`,并保留目录结构。
fn copy_dir(from: &Path, to: &Path) -> Result<(), Box<dyn std::error::Error>> {
let mut copied = 0usize;
for entry in WalkDir::new(from) {
let entry = entry?;
let relative = entry.path().strip_prefix(from)?;
// 跳过 dist 目录自身
if relative.as_os_str().is_empty() {
continue;
}
let destination = to.join(relative);
if entry.file_type().is_dir() {
fs::create_dir_all(&destination)?;
continue;
}
// 符号链接等非普通文件不参与内嵌
if !entry.file_type().is_file() {
continue;
}
fs::copy(entry.path(), &destination)?;
copied += 1;
}
if copied == 0 {
return Err(std::io::Error::other(format!(
"{} 中没有任何文件可内嵌",
from.display()
))
.into());
}
Ok(())
}