dev: fix the Vite proxy and add a one-command dev runner
Running `pnpm dev` alone gave ECONNREFUSED on every request, because nothing was listening on :7788. Two separate causes: - the backend simply was not running, and - Vite bound [::1]:5173 while the proxy target was "localhost", which Node resolves to ::1 first. The Go server binds IPv4, so even with the backend up the proxy could fail before falling back. - vite.config.ts: proxy target is now 127.0.0.1 explicitly and overridable via VELLUM_API; server.host is true so both stacks are served. - scripts/dev.sh + `make dev`: builds the backend, waits for /healthz, starts Vite, and stops the backend on exit. Ctrl-C tears down both. - README documents that running Vite alone needs the backend already up.
This commit is contained in:
parent
1d7831ac10
commit
7754b0f504
4 changed files with 85 additions and 4 deletions
6
Makefile
6
Makefile
|
|
@ -7,7 +7,11 @@ BINARY := vellum
|
||||||
VERSION ?= 0.4.0-dev
|
VERSION ?= 0.4.0-dev
|
||||||
LDFLAGS := -s -w -X main.version=$(VERSION)
|
LDFLAGS := -s -w -X main.version=$(VERSION)
|
||||||
|
|
||||||
.PHONY: build web run test fmt vet tidy check docker clean
|
.PHONY: build web build-go dev run test fmt vet tidy check docker clean
|
||||||
|
|
||||||
|
# Backend + Vite dev server together, with hot reload. Ctrl-C stops both.
|
||||||
|
dev:
|
||||||
|
./scripts/dev.sh
|
||||||
|
|
||||||
# Build the frontend first: the Go build embeds web/dist.
|
# Build the frontend first: the Go build embeds web/dist.
|
||||||
build: web
|
build: web
|
||||||
|
|
|
||||||
11
README.md
11
README.md
|
|
@ -141,9 +141,18 @@ The application never writes to `/media`.
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
make dev # backend + Vite dev server together, with hot reload
|
||||||
make build # builds the frontend, then the Go binary with it embedded
|
make build # builds the frontend, then the Go binary with it embedded
|
||||||
make build-go # Go only, when the frontend is unchanged
|
make build-go # Go only, when the frontend is unchanged
|
||||||
make check # gofmt + vet + test
|
make check # gofmt + vet + test
|
||||||
make run # run the server on :7788
|
make run # run the server on :7788
|
||||||
cd web && pnpm dev # frontend dev server, proxies /api to :7788
|
cd web && pnpm dev # frontend only; needs the backend running on :7788
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`make dev` is the one to reach for while developing: it builds and starts the
|
||||||
|
backend, waits for it to answer, then starts Vite. Vite proxies `/api` to the
|
||||||
|
backend so the browser sees a single origin and sessions behave exactly as in
|
||||||
|
production. Ctrl-C stops both.
|
||||||
|
|
||||||
|
If you run Vite on its own, the backend must already be running, or every
|
||||||
|
request fails with `ECONNREFUSED` on `:7788`.
|
||||||
|
|
|
||||||
61
scripts/dev.sh
Executable file
61
scripts/dev.sh
Executable file
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Run the backend and the Vite dev server together.
|
||||||
|
#
|
||||||
|
# ./scripts/dev.sh
|
||||||
|
#
|
||||||
|
# The Go server runs in the background; the Vite dev server runs in the
|
||||||
|
# foreground. Ctrl-C stops both. Vite proxies /api to the Go server, so the
|
||||||
|
# browser sees one origin and sessions behave exactly as in production.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
# A local preview instance, so this works on a fresh clone without touching
|
||||||
|
# your real media or your real database.
|
||||||
|
export VELLUM_DATA_DIR="${VELLUM_DATA_DIR:-$PWD/demo/data}"
|
||||||
|
export VELLUM_CONFIG_DIR="${VELLUM_CONFIG_DIR:-$PWD/demo/config}"
|
||||||
|
export VELLUM_LISTEN="${VELLUM_LISTEN:-127.0.0.1:7788}"
|
||||||
|
export VELLUM_ADMIN_USER="${VELLUM_ADMIN_USER:-admin}"
|
||||||
|
export VELLUM_ADMIN_PASSWORD="${VELLUM_ADMIN_PASSWORD:-vellumdemo}"
|
||||||
|
export VELLUM_LOG_LEVEL="${VELLUM_LOG_LEVEL:-info}"
|
||||||
|
|
||||||
|
if ! command -v go >/dev/null 2>&1; then
|
||||||
|
export PATH="$PATH:/usr/lib/golang/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "building backend..."
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o vellum ./cmd/vellum
|
||||||
|
|
||||||
|
echo "starting backend on ${VELLUM_LISTEN}"
|
||||||
|
./vellum &
|
||||||
|
BACKEND=$!
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
echo
|
||||||
|
echo "stopping backend..."
|
||||||
|
kill "$BACKEND" 2>/dev/null || true
|
||||||
|
wait "$BACKEND" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
|
# Wait for the API to answer before handing over to Vite, so the first page
|
||||||
|
# load does not race the backend's startup.
|
||||||
|
for _ in $(seq 1 50); do
|
||||||
|
if curl -fsS -m 1 "http://${VELLUM_LISTEN#*:}/healthz" >/dev/null 2>&1; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if ! kill -0 "$BACKEND" 2>/dev/null; then
|
||||||
|
echo "backend exited during startup" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "backend: http://${VELLUM_LISTEN} (${VELLUM_ADMIN_USER} / ${VELLUM_ADMIN_PASSWORD})"
|
||||||
|
echo "frontend: http://localhost:5173"
|
||||||
|
echo
|
||||||
|
|
||||||
|
cd web
|
||||||
|
pnpm install --silent
|
||||||
|
pnpm dev
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
||||||
|
|
||||||
|
// The backend the dev server proxies to. 127.0.0.1 rather than localhost on
|
||||||
|
// purpose: Node resolves "localhost" to ::1 first, and the Go server binds
|
||||||
|
// IPv4, so the proxy would fail before falling back.
|
||||||
|
const apiTarget = process.env.VELLUM_API ?? 'http://127.0.0.1:7788'
|
||||||
|
|
||||||
// The bundle is embedded into the Go binary and served from /, so all asset
|
// The bundle is embedded into the Go binary and served from /, so all asset
|
||||||
// paths must be relative (base: './').
|
// paths must be relative (base: './').
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
|
@ -13,9 +18,11 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: 5173,
|
||||||
|
// Listen on both stacks so a browser using either localhost works.
|
||||||
|
host: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': 'http://localhost:7788',
|
'/api': apiTarget,
|
||||||
'/healthz': 'http://localhost:7788',
|
'/healthz': apiTarget,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue