Performance: - Lazy-load pages, docx, and mammoth (initial JS 1,298 KB -> ~290 KB) - Gzip responses and cache hashed assets for a year - Memoize DrawCanvas strokes so ink isn't redrawn on every render - Precompute whole-Bible search index and defer the query while typing - Reload once if a lazy chunk is missing after a deploy Deployment: - setup.sh builds and runs one production server on APP_PORT (default 5173); --dev keeps the old Vite dev setup - Session cookie uses secure: 'auto' so login works behind any proxy Chunk editor: - Remove the Draw layout, Ink Notes panel, and ink in HTML export (existing inkStrokes data is left in saved projects) Refactor: - Move module-level helpers out of App.jsx into src/utils/* - Extract Bible reader state and logic into hooks/useBibleReader Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
152 lines
5.2 KiB
Bash
Executable File
152 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Installs dependencies, builds the frontend, and runs the app.
|
|
#
|
|
# bash setup.sh Production: one Express server serves the optimized
|
|
# build + API on $APP_PORT (default 5173).
|
|
# bash setup.sh --dev Development: Express API on 3001 + Vite dev server
|
|
# with hot reload (slower; not for real users).
|
|
set -euo pipefail
|
|
|
|
MODE="prod"
|
|
if [ "${1:-}" = "--dev" ]; then
|
|
MODE="dev"
|
|
fi
|
|
|
|
# Production serves on the port the Vite dev server used to use, so an
|
|
# existing reverse proxy pointed at it keeps working. Override with APP_PORT=.
|
|
APP_PORT="${APP_PORT:-5173}"
|
|
PREFERRED_VITE_PORT=5173
|
|
MAX_VITE_PORT=5200
|
|
API_PORT=3001
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
VITE_PID_FILE="$ROOT_DIR/.vite.pid"
|
|
API_PID_FILE="$ROOT_DIR/.api.pid"
|
|
VITE_LOG_FILE="$ROOT_DIR/.vite.log"
|
|
API_LOG_FILE="$ROOT_DIR/.api.log"
|
|
|
|
# ── Find an available Vite port ───────────────────────────────────────────────
|
|
find_port() {
|
|
local port=$PREFERRED_VITE_PORT
|
|
while [ $port -le $MAX_VITE_PORT ]; do
|
|
if ! lsof -i TCP:"$port" -sTCP:LISTEN -t >/dev/null 2>&1 && \
|
|
! ss -tlnH "sport = :$port" 2>/dev/null | grep -q .; then
|
|
echo "$port"
|
|
return
|
|
fi
|
|
port=$((port + 1))
|
|
done
|
|
echo ""
|
|
}
|
|
|
|
# ── Stop a process by PID file ────────────────────────────────────────────────
|
|
stop_pid_file() {
|
|
local pid_file="$1"
|
|
local label="$2"
|
|
if [ -f "$pid_file" ]; then
|
|
local old_pid
|
|
old_pid=$(cat "$pid_file")
|
|
if kill -0 "$old_pid" 2>/dev/null; then
|
|
echo "Stopping previous $label (PID $old_pid)..."
|
|
kill "$old_pid"
|
|
sleep 1
|
|
fi
|
|
rm -f "$pid_file"
|
|
fi
|
|
}
|
|
|
|
echo "=== Bible Study App Setup ($MODE) ==="
|
|
echo ""
|
|
|
|
# ── Node check ───────────────────────────────────────────────────────────────
|
|
if ! command -v node >/dev/null 2>&1; then
|
|
echo "ERROR: Node.js is not installed. Install it from https://nodejs.org/ (v18+)."
|
|
exit 1
|
|
fi
|
|
NODE_VERSION=$(node -v | sed 's/v//' | cut -d. -f1)
|
|
if [ "$NODE_VERSION" -lt 18 ]; then
|
|
echo "ERROR: Node.js v18 or higher is required (found $(node -v))."
|
|
exit 1
|
|
fi
|
|
echo "Node.js $(node -v) found."
|
|
|
|
# ── npm check ────────────────────────────────────────────────────────────────
|
|
if ! command -v npm >/dev/null 2>&1; then
|
|
echo "ERROR: npm is not installed."
|
|
exit 1
|
|
fi
|
|
echo "npm $(npm -v) found."
|
|
|
|
# ── Install dependencies ──────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "Installing dependencies..."
|
|
npm install
|
|
|
|
# ── Production ────────────────────────────────────────────────────────────────
|
|
if [ "$MODE" = "prod" ]; then
|
|
# Build before stopping anything, so a failed build leaves the running site up.
|
|
echo ""
|
|
echo "Building frontend..."
|
|
npm run build
|
|
|
|
stop_pid_file "$API_PID_FILE" "server"
|
|
stop_pid_file "$VITE_PID_FILE" "Vite dev server"
|
|
|
|
echo ""
|
|
echo "Starting production server on http://localhost:$APP_PORT"
|
|
echo "Logs: $API_LOG_FILE"
|
|
|
|
NODE_ENV=production PORT="$APP_PORT" \
|
|
nohup node "$ROOT_DIR/server/index.js" > "$API_LOG_FILE" 2>&1 &
|
|
echo $! > "$API_PID_FILE"
|
|
echo "Server PID: $(cat "$API_PID_FILE")"
|
|
|
|
echo ""
|
|
echo "To stop: kill \$(cat .api.pid)"
|
|
echo "To view logs: tail -f .api.log"
|
|
exit 0
|
|
fi
|
|
|
|
# ── Development ───────────────────────────────────────────────────────────────
|
|
stop_pid_file "$API_PID_FILE" "API server"
|
|
stop_pid_file "$VITE_PID_FILE" "Vite server"
|
|
|
|
echo ""
|
|
VITE_PORT=$(find_port)
|
|
if [ -z "$VITE_PORT" ]; then
|
|
echo "ERROR: No free port found between $PREFERRED_VITE_PORT and $MAX_VITE_PORT."
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$VITE_PORT" -ne "$PREFERRED_VITE_PORT" ]; then
|
|
echo "Port $PREFERRED_VITE_PORT is in use. Using port $VITE_PORT instead."
|
|
else
|
|
echo "Port $VITE_PORT is available for Vite."
|
|
fi
|
|
|
|
echo ""
|
|
echo "Starting API server on http://localhost:$API_PORT"
|
|
echo "API logs: $API_LOG_FILE"
|
|
|
|
nohup node "$ROOT_DIR/server/index.js" > "$API_LOG_FILE" 2>&1 &
|
|
echo $! > "$API_PID_FILE"
|
|
echo "API server PID: $(cat "$API_PID_FILE")"
|
|
|
|
# Give the API a moment to initialise before Vite starts
|
|
sleep 1
|
|
|
|
echo ""
|
|
echo "Starting Vite dev server on http://localhost:$VITE_PORT"
|
|
echo "Vite logs: $VITE_LOG_FILE"
|
|
|
|
nohup npx vite --port "$VITE_PORT" --host > "$VITE_LOG_FILE" 2>&1 &
|
|
echo $! > "$VITE_PID_FILE"
|
|
echo "Vite server PID: $(cat "$VITE_PID_FILE")"
|
|
|
|
echo ""
|
|
echo "Both servers are running."
|
|
echo ""
|
|
echo "To stop both: kill \$(cat .api.pid) \$(cat .vite.pid)"
|
|
echo "To view API logs: tail -f .api.log"
|
|
echo "To view Vite logs: tail -f .vite.log"
|