# Ensure web frontend: npm install + optional dist build for Docker nginx. # Called automatically by start.ps1 / start-host.ps1 (no manual npm). param( [switch]$BuildDist ) $ErrorActionPreference = "Stop" $Root = Split-Path -Parent $PSScriptRoot if (-not (Test-Path (Join-Path $Root "web\package.json"))) { throw "web/package.json not found under repo root" } $WebDir = Join-Path $Root "web" $npmCmd = Get-Command npm.cmd -ErrorAction SilentlyContinue if (-not $npmCmd) { $npmCmd = Get-Command npm -ErrorAction SilentlyContinue } if (-not $npmCmd) { throw "npm not found" } Push-Location $WebDir try { if (-not (Test-Path "node_modules")) { Write-Host " npm install (web) ..." -ForegroundColor DarkGray & $npmCmd.Source install if ($LASTEXITCODE -ne 0) { throw "npm install failed" } } if (-not $BuildDist) { # Clear stale native exit code left by caller (e.g. docker compose failure) $global:LASTEXITCODE = 0 return } $distIndex = Join-Path $WebDir "dist\index.html" $needBuild = -not (Test-Path $distIndex) if (-not $needBuild) { $distTime = (Get-Item $distIndex).LastWriteTime $newer = Get-ChildItem -Path (Join-Path $WebDir "src") -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $_.LastWriteTime -gt $distTime } | Select-Object -First 1 if ($newer) { $needBuild = $true } $cfgNewer = Get-ChildItem -Path $WebDir -File -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^(vite\.config|index\.html|package\.json)' -and $_.LastWriteTime -gt $distTime } | Select-Object -First 1 if ($cfgNewer) { $needBuild = $true } } if ($needBuild) { Write-Host " npm run build (web dist, includes /#/preview) ..." -ForegroundColor DarkGray & $npmCmd.Source run build if ($LASTEXITCODE -ne 0) { throw "npm run build failed" } if (-not (Test-Path $distIndex)) { throw "web/dist/index.html missing after build" } Write-Host " OK web/dist ready" -ForegroundColor DarkGray } else { Write-Host " OK web/dist up to date" -ForegroundColor DarkGray } $global:LASTEXITCODE = 0 } finally { Pop-Location }