feat: 添加 build.rs 自动构建前端,cargo build 时自动执行 npm install + npm run build

This commit is contained in:
oudecheng 2026-08-03 17:29:46 +08:00
parent 389e222b11
commit c484a918b5
4 changed files with 71 additions and 27 deletions

View File

@ -28,10 +28,9 @@ dev-frontend:
@echo "Starting frontend dev server..." @echo "Starting frontend dev server..."
cd web && npm run dev cd web && npm run dev
# Build for production # Build for production (frontend is built automatically by cargo via build.rs)
build: build:
@echo "Building PicoBot Web UI..." @echo "Building PicoBot Web UI..."
cd web && npm run build
cargo build --release cargo build --release
@echo "Build complete!" @echo "Build complete!"

63
build.rs Normal file
View File

@ -0,0 +1,63 @@
use std::path::Path;
use std::process::Command;
fn run_npm(args: &[&str], web_dir: &Path) {
let is_windows = cfg!(target_os = "windows");
if is_windows {
let mut cmd_args = vec!["/c", "npm"];
cmd_args.extend_from_slice(args);
let status = Command::new("cmd")
.args(&cmd_args)
.current_dir(web_dir)
.status()
.unwrap_or_else(|e| panic!("failed to spawn npm {}: {}", args.join(" "), e));
if !status.success() {
panic!("npm {} failed with status {}", args.join(" "), status);
}
} else {
let status = Command::new("npm")
.args(args)
.current_dir(web_dir)
.status()
.unwrap_or_else(|e| panic!("failed to spawn npm {}: {}", args.join(" "), e));
if !status.success() {
panic!("npm {} failed with status {}", args.join(" "), status);
}
}
}
fn main() {
println!("cargo:rerun-if-env-changed=SKIP_FRONTEND_BUILD");
let web_dir = Path::new("web");
if web_dir.exists() {
println!("cargo:rerun-if-changed=web/src");
println!("cargo:rerun-if-changed=web/index.html");
println!("cargo:rerun-if-changed=web/package.json");
println!("cargo:rerun-if-changed=web/vite.config.ts");
println!("cargo:rerun-if-changed=web/tailwind.config.js");
println!("cargo:rerun-if-changed=web/postcss.config.js");
println!("cargo:rerun-if-changed=web/tsconfig.json");
}
if std::env::var("SKIP_FRONTEND_BUILD").is_ok() {
println!("cargo:warning=SKIP_FRONTEND_BUILD is set, skipping frontend build");
return;
}
if !web_dir.exists() {
println!("cargo:warning=web/ directory not found, skipping frontend build");
return;
}
println!("cargo:warning=building frontend (npm install)...");
run_npm(&["install"], web_dir);
println!("cargo:warning=building frontend (npm run build)...");
run_npm(&["run", "build"], web_dir);
println!("cargo:warning=frontend build complete, output in static/");
}

View File

@ -12,15 +12,7 @@ if [ ! -f "Cargo.toml" ]; then
fi fi
echo "" echo ""
echo "Step 1: Building frontend..." echo "Building PicoBot (frontend is built automatically by cargo via build.rs)..."
echo "----------------------------------------"
cd web
npm install
npm run build
cd ..
echo ""
echo "Step 2: Building Rust backend..."
echo "----------------------------------------" echo "----------------------------------------"
cargo build --release cargo build --release

View File

@ -14,18 +14,8 @@ $DistDir = "$Root\dist\$PackageName"
Write-Host "=== PicoBot v$Version Build ===" -ForegroundColor Cyan Write-Host "=== PicoBot v$Version Build ===" -ForegroundColor Cyan
# Step 1: build frontend # Build Rust backend (frontend is built automatically via build.rs)
Write-Host "[1/4] Building web frontend..." -ForegroundColor Yellow Write-Host "[1/3] Building PicoBot (frontend auto-built by cargo)..." -ForegroundColor Yellow
Push-Location "$Root\web"
try {
npm run build
if ($LASTEXITCODE -ne 0) { throw "web build failed" }
} finally {
Pop-Location
}
# Step 2: build Rust backend
Write-Host "[2/4] Building Rust release..." -ForegroundColor Yellow
Push-Location $Root Push-Location $Root
try { try {
cargo build --release cargo build --release
@ -34,16 +24,16 @@ try {
Pop-Location Pop-Location
} }
# Step 3: assemble dist directory # Assemble dist directory
Write-Host "[3/4] Assembling package..." -ForegroundColor Yellow Write-Host "[2/3] Assembling package..." -ForegroundColor Yellow
New-Item -ItemType Directory -Force -Path $DistDir | Out-Null New-Item -ItemType Directory -Force -Path $DistDir | Out-Null
# exe + package contents # exe + package contents
Copy-Item "$Root\target\release\picobot.exe" $DistDir Copy-Item "$Root\target\release\picobot.exe" $DistDir
Copy-Item "$Root\package\*" $DistDir Copy-Item "$Root\package\*" $DistDir
# Step 4: zip # Create zip
Write-Host "[4/4] Creating zip..." -ForegroundColor Yellow Write-Host "[3/3] Creating zip..." -ForegroundColor Yellow
$ZipPath = "$Root\dist\$PackageName.zip" $ZipPath = "$Root\dist\$PackageName.zip"
if (Test-Path $ZipPath) { Remove-Item $ZipPath } if (Test-Path $ZipPath) { Remove-Item $ZipPath }
Compress-Archive -Path $DistDir -DestinationPath $ZipPath Compress-Archive -Path $DistDir -DestinationPath $ZipPath