$ErrorActionPreference = "Stop" $root = Split-Path -Parent $PSCommandPath $backendPort = 3000 $frontendPort = 5173 function Test-TcpPort { param( [Parameter(Mandatory = $true)] [int]$Port ) $client = [System.Net.Sockets.TcpClient]::new() try { $task = $client.ConnectAsync("127.0.0.1", $Port) if (-not $task.Wait(500)) { return $false } return $client.Connected } catch { return $false } finally { $client.Dispose() } } function Assert-PortFree { param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [int]$Port ) if (Test-TcpPort -Port $Port) { Write-Host "[error] $Name 端口 $Port 已被占用,请先停止占用该端口的进程" -ForegroundColor Red exit 1 } } function Wait-Port { param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [int]$Port, [Parameter(Mandatory = $true)] [System.Diagnostics.Process]$Process, [int]$TimeoutSeconds = 90 ) $deadline = (Get-Date).AddSeconds($TimeoutSeconds) while ((Get-Date) -lt $deadline) { if ($Process.HasExited) { Write-Host "[error] $Name 进程已退出,退出码 $($Process.ExitCode),请查看对应窗口日志" -ForegroundColor Red exit 1 } if (Test-TcpPort -Port $Port) { Write-Host "[$Name] 已就绪 (port $Port)" -ForegroundColor Green return } Start-Sleep -Milliseconds 500 } Write-Host "[error] $Name 未在 $TimeoutSeconds 秒内监听端口 $Port,请查看对应窗口日志" -ForegroundColor Red exit 1 } # 0. 初始化 PATH $env:Path = "C:\Program Files\Go\bin;C:\Users\Chaos\.bun\bin;$env:Path" # 1. 检查 .env if (-not (Test-Path "$root\.env")) { Write-Host "[setup] 复制 .env.example -> .env" -ForegroundColor Yellow Copy-Item "$root\.env.example" "$root\.env" } # 2. 检查前端依赖 if (-not (Test-Path "$root\web\default\node_modules")) { Write-Host "[setup] 安装前端依赖..." -ForegroundColor Yellow Set-Location "$root\web\default" bun install Set-Location $root if ($LASTEXITCODE -ne 0) { Write-Host "[error] bun install 失败" -ForegroundColor Red exit 1 } } # 3. 创建 go:embed 所需目录 $embedDirs = @("web\default\dist", "web\classic\dist", "web\image-gen\dist") foreach ($dir in $embedDirs) { $fullPath = Join-Path $root $dir if (-not (Test-Path $fullPath)) { New-Item -ItemType Directory -Force -Path $fullPath | Out-Null } $indexFile = Join-Path $fullPath "index.html" if (-not (Test-Path $indexFile)) { Set-Content -Path $indexFile -Value "" } } # 4. 初始化 PATH $goPath = "C:\Program Files\Go\bin" $bunPath = "C:\Users\Chaos\.bun\bin" $initPath = "`$env:Path = '$goPath;$bunPath;' + `$env:Path;" # 5. 检查端口占用 Assert-PortFree -Name "Backend" -Port $backendPort Assert-PortFree -Name "Frontend" -Port $frontendPort # 6. 启动后端 Write-Host "[backend] 启动 API 服务 (port $backendPort)..." -ForegroundColor Green $backendJob = Start-Process -FilePath "powershell" -ArgumentList "-NoExit", "-Command", "$initPath Set-Location '$root'; Write-Host '=== Backend :$backendPort ===' -ForegroundColor Cyan; go run main.go" -PassThru # 7. 启动前端 Write-Host "[frontend] 启动前端开发服务 (port $frontendPort)..." -ForegroundColor Green $frontendJob = Start-Process -FilePath "powershell" -ArgumentList "-NoExit", "-Command", "$initPath Set-Location '$root\web\default'; Write-Host '=== Frontend :$frontendPort ===' -ForegroundColor Magenta; bun run dev" -PassThru # 8. 等待服务就绪 Wait-Port -Name "Backend" -Port $backendPort -Process $backendJob -TimeoutSeconds 90 Wait-Port -Name "Frontend" -Port $frontendPort -Process $frontendJob -TimeoutSeconds 60 Write-Host "" Write-Host "==============================" -ForegroundColor White Write-Host " Backend : http://localhost:$backendPort" -ForegroundColor Cyan Write-Host " Frontend : http://localhost:$frontendPort" -ForegroundColor Magenta Write-Host "==============================" -ForegroundColor White Write-Host "" Write-Host "关闭窗口即可停止服务" -ForegroundColor Gray