mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-23 03:27:43 +09:00
The Windows-side port sweep now respects the same opt-out dev.sh has, and the startup banner leads with http://localhost:<port> (the WSL interface IP stays as a printed fallback) so the URL you open is never the dead one.
180 lines
6.5 KiB
PowerShell
180 lines
6.5 KiB
PowerShell
#Requires -Version 5.1
|
|
<#
|
|
.SYNOPSIS
|
|
Windows entry point for the ServerKit development environment.
|
|
.DESCRIPTION
|
|
Delegates to dev/dev.sh through WSL so local development runs in a
|
|
Linux-like environment and stays in sync with the Bash launcher.
|
|
|
|
With several distros installed, the launcher picks the first one that has a
|
|
real Linux node (not the Windows shim reached through PATH interop) rather
|
|
than trusting the current WSL default. Set SERVERKIT_WSL_DISTRO to override.
|
|
.EXAMPLE
|
|
.\dev.ps1
|
|
Start backend + frontend through WSL on stable non-default ports.
|
|
.EXAMPLE
|
|
.\dev.ps1 frontend -BackendPort 5600
|
|
Start Vite through WSL, targeting an existing backend on port 5600.
|
|
.EXAMPLE
|
|
$env:SERVERKIT_WSL_DISTRO = 'Ubuntu-22.04'; .\dev.ps1
|
|
Force a specific distro instead of auto-detecting one.
|
|
#>
|
|
|
|
$ProjectRoot = $PSScriptRoot
|
|
|
|
if (-not (Get-Command wsl.exe -ErrorAction SilentlyContinue)) {
|
|
Write-Host "Error: WSL is required for .\dev.ps1." -ForegroundColor Red
|
|
Write-Host "Install WSL, then run this again, or run ./dev.sh directly from Linux/WSL." -ForegroundColor Yellow
|
|
exit 1
|
|
}
|
|
|
|
# Which distro to run in. Pinning this matters on machines with more than one:
|
|
# a distro without a Linux node/npm silently falls through WSL's PATH interop to
|
|
# the Windows node shim under /mnt/c, which then fails with messages that read
|
|
# like a WSL problem ("WSL 1 is not supported", "Could not determine Node.js
|
|
# install directory") rather than "node isn't installed here". So prefer a
|
|
# distro that actually has node, instead of trusting whichever one happens to be
|
|
# the current default.
|
|
function Get-WslDistros {
|
|
# `wsl -l -q` emits UTF-16LE; decode explicitly or every name arrives with
|
|
# NUL bytes interleaved.
|
|
$prevEncoding = [Console]::OutputEncoding
|
|
try {
|
|
[Console]::OutputEncoding = [System.Text.Encoding]::Unicode
|
|
return (& wsl.exe -l -q) |
|
|
ForEach-Object { $_.Trim() } |
|
|
Where-Object { $_ -and $_ -ne 'docker-desktop' -and $_ -ne 'docker-desktop-data' }
|
|
} finally {
|
|
[Console]::OutputEncoding = $prevEncoding
|
|
}
|
|
}
|
|
|
|
function Test-DistroHasNode {
|
|
param([string]$Distro)
|
|
# `command -v node` alone is not enough: PATH interop makes the Windows
|
|
# shim answer. Require the resolved path to be a real Linux one.
|
|
#
|
|
# The probe can emit several lines (a failing Windows shim prints its own
|
|
# errors), so scan every line for one absolute Linux path rather than
|
|
# assuming a single-string result.
|
|
$lines = @(& wsl.exe -d $Distro --exec bash -lc 'command -v node 2>/dev/null' 2>$null)
|
|
foreach ($line in $lines) {
|
|
$path = "$line".Trim()
|
|
if ($path.StartsWith('/') -and -not $path.StartsWith('/mnt/')) { return $true }
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Resolve-DevDistro {
|
|
if ($env:SERVERKIT_WSL_DISTRO) { return $env:SERVERKIT_WSL_DISTRO }
|
|
|
|
$distros = @(Get-WslDistros)
|
|
if ($distros.Count -le 1) { return $null } # nothing to choose between
|
|
|
|
foreach ($d in $distros) {
|
|
if (Test-DistroHasNode -Distro $d) { return $d }
|
|
}
|
|
return $null
|
|
}
|
|
|
|
$distro = Resolve-DevDistro
|
|
$distroArgs = if ($distro) { @('-d', $distro) } else { @() }
|
|
|
|
$wslRoot = (& wsl.exe @distroArgs --exec wslpath -a -u "$ProjectRoot" 2>$null)
|
|
if ($LASTEXITCODE -ne 0 -or -not $wslRoot) {
|
|
Write-Host "Error: Could not map this Windows path into WSL: $ProjectRoot" -ForegroundColor Red
|
|
Write-Host "Make sure a WSL distro is installed and can access this repository." -ForegroundColor Yellow
|
|
exit 1
|
|
}
|
|
|
|
$wslRoot = $wslRoot.Trim()
|
|
$devArgs = @($args)
|
|
$forwardedEnv = @()
|
|
|
|
function Get-DevMode {
|
|
foreach ($arg in $devArgs) {
|
|
if ($arg -in @('start', 'backend', 'frontend', 'tunnel', 'validate')) {
|
|
return $arg
|
|
}
|
|
}
|
|
return 'start'
|
|
}
|
|
|
|
function Get-DevPort {
|
|
param(
|
|
[string[]]$Names,
|
|
[string]$EnvName,
|
|
[int]$Default
|
|
)
|
|
|
|
for ($i = 0; $i -lt $devArgs.Count; $i++) {
|
|
$arg = [string]$devArgs[$i]
|
|
foreach ($name in $Names) {
|
|
if ($arg -eq $name -and ($i + 1) -lt $devArgs.Count) {
|
|
return [int]$devArgs[$i + 1]
|
|
}
|
|
if ($arg.StartsWith("$name=")) {
|
|
return [int]$arg.Substring($name.Length + 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
$item = Get-Item -Path "Env:$EnvName" -ErrorAction SilentlyContinue
|
|
if ($item -and $item.Value) {
|
|
return [int]$item.Value
|
|
}
|
|
|
|
return $Default
|
|
}
|
|
|
|
function Stop-WindowsListenersOnPort {
|
|
param(
|
|
[int]$Port,
|
|
[string]$Label
|
|
)
|
|
|
|
# Parity with dev.sh: SERVERKIT_KILL_PORTS=0 opts out of port cleanup.
|
|
if ($env:SERVERKIT_KILL_PORTS -eq '0') { return }
|
|
|
|
$listeners = @(Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue |
|
|
Select-Object -ExpandProperty OwningProcess -Unique |
|
|
Where-Object { $_ -and $_ -ne 0 -and $_ -ne $PID })
|
|
|
|
foreach ($processId in $listeners) {
|
|
$proc = Get-Process -Id $processId -ErrorAction SilentlyContinue
|
|
if (-not $proc) {
|
|
continue
|
|
}
|
|
|
|
Write-Host "Stopping existing $Label listener on port $Port ($($proc.ProcessName) PID $processId)..." -ForegroundColor Yellow
|
|
Stop-Process -Id $processId -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
$mode = Get-DevMode
|
|
$backendPort = Get-DevPort -Names @('--backend-port', '-BackendPort') -EnvName 'SERVERKIT_BACKEND_PORT' -Default 47927
|
|
$frontendPort = Get-DevPort -Names @('--frontend-port', '-FrontendPort') -EnvName 'SERVERKIT_FRONTEND_PORT' -Default 41921
|
|
$isHelp = $devArgs -contains '-h' -or $devArgs -contains '--help'
|
|
|
|
if (-not $isHelp -and $mode -in @('start', 'backend', 'tunnel')) {
|
|
Stop-WindowsListenersOnPort -Port $backendPort -Label 'backend'
|
|
}
|
|
if (-not $isHelp -and $mode -in @('start', 'frontend', 'tunnel')) {
|
|
Stop-WindowsListenersOnPort -Port $frontendPort -Label 'frontend'
|
|
}
|
|
|
|
foreach ($name in @('SERVERKIT_BACKEND_PORT', 'SERVERKIT_FRONTEND_PORT', 'SERVERKIT_BROWSER_BACKEND_HOST', 'SERVERKIT_BACKEND_VENV', 'SERVERKIT_KILL_PORTS', 'NGROK_DOMAIN', 'NGROK_AUTHTOKEN', 'CORS_ORIGINS')) {
|
|
$item = Get-Item -Path "Env:$name" -ErrorAction SilentlyContinue
|
|
if ($item -and $item.Value) {
|
|
$forwardedEnv += "$name=$($item.Value)"
|
|
}
|
|
}
|
|
|
|
if ($distro) {
|
|
Write-Host "Launching ServerKit dev environment in WSL ($distro)..." -ForegroundColor Cyan
|
|
} else {
|
|
Write-Host "Launching ServerKit dev environment in WSL..." -ForegroundColor Cyan
|
|
}
|
|
& wsl.exe @distroArgs --cd "$wslRoot" --exec env @forwardedEnv bash ./dev/dev.sh @devArgs
|
|
exit $LASTEXITCODE
|