param( [ValidateSet("web", "tauri")] [string]$Target = "web", [ValidateSet("Release", "Debug")] [string]$Configuration = "Release", [ValidateSet("none", "nsis", "msi")] [string]$TauriBundles = "none", [switch]$InstallDeps, [switch]$SkipInstall, [switch]$DryRun ) $commonScript = Join-Path $PSScriptRoot "script-common.ps1" if (-not (Test-Path $commonScript)) { throw "Missing helper script: $commonScript" } . $commonScript $repoRoot = Resolve-JournalRepoRoot -StartPath $PSScriptRoot $appRoot = Resolve-JournalAppRoot -RepoRoot $repoRoot Clear-JournalProxyEnv # Keep npm cache and temp local to the repo. $npmCacheDir = Join-Path $repoRoot ".npm\cache" $npmTempDir = Join-Path $repoRoot ".tmp\npm-temp" New-Item -ItemType Directory -Force -Path $npmCacheDir, $npmTempDir | Out-Null $env:npm_config_cache = $npmCacheDir $env:npm_config_update_notifier = "false" $env:npm_config_fund = "false" $env:npm_config_audit = "false" $env:npm_config_offline = "false" $env:npm_config_prefer_offline = "false" $env:npm_config_prefer_online = "true" $env:TEMP = $npmTempDir $env:TMP = $npmTempDir if (-not (Get-Command npm -ErrorAction SilentlyContinue)) { throw "npm is required but was not found in PATH." } $nodeModulesPath = Join-Path $appRoot "node_modules" $packageLockPath = Join-Path $appRoot "package-lock.json" $shouldInstall = $InstallDeps -or (-not (Test-Path $nodeModulesPath)) if ($SkipInstall) { $shouldInstall = $false } Write-Host "Building Journal.App target '$Target' ($Configuration)..." -ForegroundColor Cyan Write-Host "Using app root: $appRoot" -ForegroundColor DarkGray Push-Location $appRoot try { if ($shouldInstall) { $installArgs = if (Test-Path $packageLockPath) { @("ci", "--no-audit", "--fund=false") } else { @("install", "--no-audit", "--fund=false") } Write-Host "> npm $($installArgs -join ' ')" -ForegroundColor DarkGray if (-not $DryRun) { & npm @installArgs if ($LASTEXITCODE -ne 0) { throw "Dependency install failed with exit code $LASTEXITCODE." } } } else { Write-Host "Skipping dependency install (node_modules already present)." -ForegroundColor DarkGray } if ($Target -eq "web") { $buildArgs = @("run", "build") Write-Host "> npm $($buildArgs -join ' ')" -ForegroundColor DarkGray if (-not $DryRun) { & npm @buildArgs if ($LASTEXITCODE -ne 0) { throw "Frontend build failed with exit code $LASTEXITCODE." } } $outputPath = Join-Path $appRoot "build" if ($DryRun) { Write-Host "`nDry run complete (no commands executed)." -ForegroundColor Yellow Write-Host "Expected output: $outputPath" -ForegroundColor Gray } else { Write-Host "`nFrontend build successful." -ForegroundColor Green Write-Host "Output: $outputPath" -ForegroundColor Gray } } else { $tauriArgs = @("run", "tauri", "build") $tauriCliArgs = @() if ($TauriBundles -eq "none") { $tauriCliArgs += "--no-bundle" } else { $tauriCliArgs += @("--bundles", $TauriBundles) } if ($Configuration -eq "Debug") { $tauriCliArgs += "--debug" } if ($tauriCliArgs.Count -gt 0) { $tauriArgs += "--" $tauriArgs += $tauriCliArgs } Write-Host "> npm $($tauriArgs -join ' ')" -ForegroundColor DarkGray if (-not $DryRun) { & npm @tauriArgs if ($LASTEXITCODE -ne 0) { throw "Tauri build failed with exit code $LASTEXITCODE." } } $targetConfigDir = if ($Configuration -eq "Debug") { "debug" } else { "release" } $tauriTargetPath = Join-Path $appRoot "src-tauri\target" $rawExePath = Join-Path $tauriTargetPath "$targetConfigDir\journalapp.exe" if ($DryRun) { Write-Host "`nDry run complete (no commands executed)." -ForegroundColor Yellow if ($TauriBundles -eq "none") { Write-Host "Expected executable: $rawExePath" -ForegroundColor Gray } else { Write-Host "Expected output root: $tauriTargetPath" -ForegroundColor Gray } } else { Write-Host "`nTauri build successful." -ForegroundColor Green if ($TauriBundles -eq "none") { if (Test-Path $rawExePath) { Write-Host "Executable location: $rawExePath" -ForegroundColor Gray } else { $exeCandidates = Get-ChildItem -Path (Join-Path $tauriTargetPath $targetConfigDir) -File -Filter *.exe -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending if ($exeCandidates -and $exeCandidates.Count -gt 0) { Write-Host "Executable location: $($exeCandidates[0].FullName)" -ForegroundColor Gray } else { Write-Host "Output root: $tauriTargetPath" -ForegroundColor Gray } } } else { Write-Host "Output root: $tauriTargetPath" -ForegroundColor Gray } } } } finally { Pop-Location }