feat: remove nextjs production runtime (#1389)
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
# scripts/dev-isolated [options]
|
||||
#
|
||||
# Options:
|
||||
# --web Also start the Next.js dev frontend (default: backend only)
|
||||
# --web Also start the Vite dev frontend (default: backend only)
|
||||
# --backend-port N Force the backend port (default: auto from base 48429)
|
||||
# --web-port N Force the web port (default: auto from base 47429)
|
||||
# --agentctl-port N Force the agentctl base port (default: auto from base 49429)
|
||||
@@ -281,10 +281,10 @@ if [[ "$healthy" -ne 1 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Optionally launch the web frontend (Next.js dev) ---
|
||||
# --- Optionally launch the web frontend (Vite dev) ---
|
||||
WEB_STARTED=0
|
||||
if [[ "$WANT_WEB" -eq 1 ]]; then
|
||||
echo "dev-isolated: starting web (next dev) on :$WEB_PORT ..."
|
||||
echo "dev-isolated: starting web (vite dev) on :$WEB_PORT ..."
|
||||
env \
|
||||
NEXT_PUBLIC_KANDEV_API_PORT="$BACKEND_PORT" \
|
||||
KANDEV_API_BASE_URL="$BACKEND_URL" \
|
||||
|
||||
+16
-70
@@ -7,10 +7,9 @@
|
||||
#
|
||||
# Sources:
|
||||
# - backend PID + listening port: `ss -tlnp` (falls back to `lsof`)
|
||||
# - web port: the separate `next-server` listener pointing at this backend
|
||||
# (matched via its KANDEV_API_BASE_URL / NEXT_PUBLIC_KANDEV_API_PORT, port
|
||||
# read from `ss`); falls back to the backend's KANDEV_WEB_INTERNAL_URL
|
||||
# (else `?`). The backend's own port is never the web port.
|
||||
# - web port: a separate Vite dev listener from KANDEV_WEB_INTERNAL_URL when
|
||||
# configured and reachable; otherwise the backend port, because production
|
||||
# serves the SPA from the Go backend.
|
||||
# - agentctl port: KANDEV_AGENT_STANDALONE_PORT / AGENTCTL_PORT in environ,
|
||||
# else the `-port=` flag of a child `agentctl` process (else `?`)
|
||||
# - HOME_DIR: KANDEV_HOME_DIR in environ, else HOME, else `?`
|
||||
@@ -97,75 +96,22 @@ port_has_listener() {
|
||||
|
||||
# Resolve the web port for a backend.
|
||||
#
|
||||
# The web UI is served by a SEPARATE `next-server` process, not the backend, so
|
||||
# the backend's own listening port is never the web port. We resolve in two
|
||||
# steps, preferring the authoritative source:
|
||||
#
|
||||
# 1. The next-server process that points back at THIS backend. Each web
|
||||
# process is launched with KANDEV_API_BASE_URL=http://host:<backend_port>
|
||||
# (and/or NEXT_PUBLIC_KANDEV_API_PORT=<backend_port>) and its own
|
||||
# PORT=<web_port>. We find the next-server whose backend-pointing env
|
||||
# matches this backend's port, then read its ACTUAL listening port from ss
|
||||
# (authoritative — the real socket, not an env hint).
|
||||
# 2. Fallback: the backend's KANDEV_WEB_INTERNAL_URL=http://host:<web_port>,
|
||||
# which the backend uses to reach the web server. Parse the trailing
|
||||
# :<port> (the host:port pair, never the scheme's colon).
|
||||
#
|
||||
# If neither resolves, print `?` rather than guessing a wrong port (e.g. the
|
||||
# backend port from PORT / NEXT_PUBLIC_KANDEV_API_PORT, which are the backend's).
|
||||
# Production serves the SPA from the backend port. In development, a separate
|
||||
# Vite server may still be configured via KANDEV_WEB_INTERNAL_URL; report that
|
||||
# port only when something is actually listening there.
|
||||
resolve_web_port() {
|
||||
local backend_pid="$1" backend_port="${2:-}" port
|
||||
port="$(resolve_web_port_via_next_server "$backend_port")"
|
||||
if [[ -z "$port" ]]; then
|
||||
local url cand=""
|
||||
url="$(read_environ_var "$backend_pid" KANDEV_WEB_INTERNAL_URL)"
|
||||
# Match the LAST :<port> so an IPv6 host or path can't fool us; the trailing
|
||||
# host:port is what we want, not the scheme separator (http:).
|
||||
if [[ "$url" =~ :([0-9]+)([/?#].*)?$ ]]; then
|
||||
cand="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
# KANDEV_WEB_INTERNAL_URL is the web URL the backend was CONFIGURED with — it
|
||||
# may name a web port that never started (e.g. a backend-only dev-isolated
|
||||
# run). Only trust it if something is actually listening there; otherwise the
|
||||
# web UI isn't reachable, so report `?` rather than a dead port.
|
||||
if [[ -n "$cand" ]] && port_has_listener "$cand"; then
|
||||
port="$cand"
|
||||
fi
|
||||
local url cand=""
|
||||
url="$(read_environ_var "$backend_pid" KANDEV_WEB_INTERNAL_URL)"
|
||||
# Match the LAST :<port> so an IPv6 host or path can't fool us; the trailing
|
||||
# host:port is what we want, not the scheme separator (http:).
|
||||
if [[ "$url" =~ :([0-9]+)([/?#].*)?$ ]]; then
|
||||
cand="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
printf '%s\n' "${port:-?}"
|
||||
}
|
||||
|
||||
# Find the next-server process bound to this backend and return its listening
|
||||
# port (the web port). Empty output means "not found".
|
||||
resolve_web_port_via_next_server() {
|
||||
local backend_port="$1"
|
||||
[[ -n "$backend_port" ]] || return 0
|
||||
command -v ss >/dev/null 2>&1 || return 0
|
||||
|
||||
# Enumerate listening next-server sockets as "pid port" pairs.
|
||||
local pid web_port api_port api_url
|
||||
while read -r _ _ _ local_addr _ procinfo; do
|
||||
case "$procinfo" in
|
||||
*'next-server'*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
# sed (not grep) so a no-match yields empty + exit 0 instead of tripping
|
||||
# `set -o pipefail` when a socket line carries no pid= field.
|
||||
pid="$(printf '%s\n' "$procinfo" | sed -nE 's/.*pid=([0-9]+).*/\1/p' | head -1)"
|
||||
web_port="${local_addr##*:}"
|
||||
[[ -n "$pid" && -n "$web_port" ]] || continue
|
||||
# Does this web process point back at OUR backend port?
|
||||
api_port="$(read_environ_var "$pid" NEXT_PUBLIC_KANDEV_API_PORT)"
|
||||
if [[ -z "$api_port" ]]; then
|
||||
api_url="$(read_environ_var "$pid" KANDEV_API_BASE_URL)"
|
||||
[[ "$api_url" =~ :([0-9]+)([/?#].*)?$ ]] && api_port="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
if [[ "$api_port" == "$backend_port" ]]; then
|
||||
printf '%s\n' "$web_port"
|
||||
return 0
|
||||
fi
|
||||
done < <(ss -tlnpH 2>/dev/null)
|
||||
return 0
|
||||
if [[ -n "$cand" ]] && port_has_listener "$cand"; then
|
||||
port="$cand"
|
||||
fi
|
||||
printf '%s\n' "${port:-$backend_port}"
|
||||
}
|
||||
|
||||
# Emit "PID PORT" pairs for every listening kandev backend socket.
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# kandev-kill — terminate exactly ONE kandev instance: the backend listening on
|
||||
# a given port, plus its agentctl child(ren) and its matching web/next server.
|
||||
# a given port, plus its agentctl child(ren) and matching Vite dev server.
|
||||
#
|
||||
# This NEVER does a blanket `pkill kandev`. It resolves the backend PID from the
|
||||
# port, confirms the process is actually a kandev backend, computes the exact
|
||||
@@ -210,8 +210,8 @@ collect_descendants() {
|
||||
|
||||
mapfile -t TREE < <(collect_descendants "$BACKEND_PID")
|
||||
|
||||
# The web/next server is typically a sibling (spawned by the launcher, not a
|
||||
# child of the backend). If a pidfile sidecar lists it, include it.
|
||||
# The optional Vite dev server is typically a sibling (spawned by the launcher,
|
||||
# not a child of the backend). If a pidfile sidecar lists it, include it.
|
||||
WEB_PID=""
|
||||
if [[ -n "$PIDFILE" && -f "${PIDFILE%.pid}.web.pid" ]]; then
|
||||
WEB_PID="$(tr -d '[:space:]' <"${PIDFILE%.pid}.web.pid" 2>/dev/null || true)"
|
||||
|
||||
@@ -6,7 +6,7 @@ class Kandev < Formula
|
||||
license "AGPL-3.0-only"
|
||||
version "__VERSION__"
|
||||
|
||||
# Node is required: the CLI launcher and Next.js standalone server both need it.
|
||||
# Node is required for the CLI launcher.
|
||||
depends_on "node"
|
||||
|
||||
on_macos do
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Finalize the dist/kandev/ release layout from already-built pieces.
|
||||
# Caller must have run, in this order:
|
||||
# - scripts/release/package-web.sh (produces dist/web/)
|
||||
# - scripts/release/package-cli.sh (produces dist/kandev/cli/)
|
||||
# - go build ./cmd/{kandev,agentctl} -o dist/kandev/bin/...
|
||||
# After this: dist/kandev/{bin,web,cli} is ready to install or tar.
|
||||
# - go build ./cmd/{kandev,agentctl} -o dist/kandev/bin/... with Vite
|
||||
# assets synced into the backend embed package before building kandev.
|
||||
# After this: dist/kandev/{bin,cli} is ready to install or tar.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
WEB_SRC="$ROOT_DIR/dist/web"
|
||||
BUNDLE="$ROOT_DIR/dist/kandev"
|
||||
|
||||
if [ ! -d "$WEB_SRC" ]; then
|
||||
echo "Missing $WEB_SRC; run scripts/release/package-web.sh first" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$BUNDLE/web"
|
||||
cp -R "$WEB_SRC/." "$BUNDLE/web/"
|
||||
|
||||
if [ ! -f "$BUNDLE/cli/bin/cli.js" ]; then
|
||||
echo "Missing $BUNDLE/cli/bin/cli.js; run scripts/release/package-cli.sh first" >&2
|
||||
exit 1
|
||||
|
||||
@@ -1,62 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# Used by .github/workflows/release.yml to package the Next.js standalone output.
|
||||
# Used by .github/workflows/release.yml to package the Vite SPA output.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
WEB_DIR="$ROOT_DIR/apps/web"
|
||||
OUT_DIR="$ROOT_DIR/dist/web"
|
||||
|
||||
echo "Packaging Next.js standalone output for release..."
|
||||
echo "Packaging Vite web output for release..."
|
||||
|
||||
if [ ! -d "$WEB_DIR/.next/standalone" ]; then
|
||||
echo "Missing standalone output at $WEB_DIR/.next/standalone"
|
||||
echo "Run: pnpm -C apps --filter @kandev/web build"
|
||||
if [ ! -f "$WEB_DIR/dist/index.html" ]; then
|
||||
echo "Missing Vite output at $WEB_DIR/dist/index.html"
|
||||
echo "Run: pnpm -C apps --filter @kandev/web build:vite"
|
||||
exit 1
|
||||
fi
|
||||
"$ROOT_DIR/scripts/release/validate-web-bundle.sh" "$WEB_DIR/dist"
|
||||
|
||||
rm -rf "$OUT_DIR"
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
# Copy with symlinks dereferenced so pnpm's .pnpm/ structure survives
|
||||
# archiving (symlinks cause issues on Windows even inside tar). The
|
||||
# standalone output may contain broken symlinks from partial tracing —
|
||||
# --safe-links skips those and rsync exits with code 23 (partial transfer),
|
||||
# which is expected.
|
||||
rsync -a --copy-links --safe-links "$WEB_DIR/.next/standalone/" "$OUT_DIR/" || {
|
||||
rc=$?
|
||||
if [ "$rc" -eq 23 ]; then
|
||||
echo "Warning: some broken symlinks were skipped (expected for standalone output)"
|
||||
else
|
||||
exit "$rc"
|
||||
fi
|
||||
}
|
||||
# pnpm's .pnpm virtual store keeps hoisted packages in
|
||||
# node_modules/.pnpm/node_modules/ which is unreachable via normal Node
|
||||
# module resolution from web/node_modules/next/. Copy everything into
|
||||
# web/node_modules/ so Next.js (and its deps) can find them at runtime.
|
||||
PNPM_HOISTED="$OUT_DIR/node_modules/.pnpm/node_modules"
|
||||
NEXT_MODULES="$OUT_DIR/web/node_modules"
|
||||
if [ -d "$PNPM_HOISTED" ] && [ -d "$NEXT_MODULES" ]; then
|
||||
for pkg in "$PNPM_HOISTED"/*; do
|
||||
name="$(basename "$pkg")"
|
||||
if [ ! -e "$NEXT_MODULES/$name" ]; then
|
||||
cp -R "$pkg" "$NEXT_MODULES/$name"
|
||||
fi
|
||||
done
|
||||
echo "Hoisted pnpm packages into web/node_modules/"
|
||||
# Remove the .pnpm virtual store — everything needed is now in
|
||||
# web/node_modules/ and the root node_modules/ is unreachable from
|
||||
# the server. Removing it avoids 3-4x duplication in the archive.
|
||||
rm -rf "$OUT_DIR/node_modules"
|
||||
fi
|
||||
|
||||
# Static assets and public/ must be alongside server.js (inside web/)
|
||||
# so Next.js can serve them. The standalone trace puts build artifacts
|
||||
# at web/.next/ but doesn't include static/ — copy it there.
|
||||
cp -R "$WEB_DIR/.next/static" "$OUT_DIR/web/.next/"
|
||||
|
||||
if [ -d "$WEB_DIR/public" ]; then
|
||||
cp -R "$WEB_DIR/public" "$OUT_DIR/web/public"
|
||||
fi
|
||||
cp -R "$WEB_DIR/dist/." "$OUT_DIR/"
|
||||
"$ROOT_DIR/scripts/release/validate-web-bundle.sh" "$OUT_DIR"
|
||||
|
||||
echo "Web bundle packaged at $OUT_DIR"
|
||||
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
# Validate that a directory contains a complete Vite SPA bundle.
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "usage: $0 <web-bundle-dir>" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
WEB_DIR="$1"
|
||||
|
||||
if [ ! -f "$WEB_DIR/index.html" ]; then
|
||||
echo "Missing Vite SPA index: $WEB_DIR/index.html" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$WEB_DIR/assets" ]; then
|
||||
echo "Missing Vite SPA assets directory: $WEB_DIR/assets" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! find "$WEB_DIR/assets" -type f -name '*.js' -print -quit | grep -q .; then
|
||||
echo "Missing Vite SPA JavaScript assets under: $WEB_DIR/assets" >&2
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user