mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-09 21:49:37 +00:00
feat(scripts): support skipping frontend build on make start (#5053)
* feat(scripts): support skipping frontend build on make start * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix(scripts): validate skip-frontend-build before stop_all and format test --------- Co-authored-by: PoetryLin <PoetryLin@users.noreply.github.com> Co-authored-by: Willem Jiang <willem.jiang@gmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
2d0568a14f
commit
23d8e4b3a3
@ -124,7 +124,7 @@ make extension-enable NAME=... # Enable an installed extension (restart requ
|
|||||||
make extension-disable NAME=... # Disable without uninstalling (restart required)
|
make extension-disable NAME=... # Disable without uninstalling (restart required)
|
||||||
make extension-remove NAME=... # Remove package and config entry (restart required)
|
make extension-remove NAME=... # Remove package and config entry (restart required)
|
||||||
make dev # Start all services with hot-reload (Gateway + Frontend + Nginx)
|
make dev # Start all services with hot-reload (Gateway + Frontend + Nginx)
|
||||||
make start # Start all services in production mode (local, optimized)
|
make start # Start all services in production mode (local, optimized); SKIP_FRONTEND_BUILD=1 reuses the last frontend build
|
||||||
make stop # Stop all running services
|
make stop # Stop all running services
|
||||||
make up / down # Build/stop the production Docker stack (browser at localhost:2026)
|
make up / down # Build/stop the production Docker stack (browser at localhost:2026)
|
||||||
make docker-start / docker-stop / docker-logs # Docker development environment
|
make docker-start / docker-stop / docker-logs # Docker development environment
|
||||||
|
|||||||
8
Makefile
8
Makefile
@ -137,10 +137,12 @@ dev:
|
|||||||
@$(PYTHON) ./scripts/check.py
|
@$(PYTHON) ./scripts/check.py
|
||||||
@$(RUN_WITH_GIT_BASH) ./scripts/serve.sh --dev
|
@$(RUN_WITH_GIT_BASH) ./scripts/serve.sh --dev
|
||||||
|
|
||||||
# Start all services in production mode (with optimizations)
|
# Start all services in production mode (with optimizations).
|
||||||
|
# SKIP_FRONTEND_BUILD=1 reuses the existing frontend build instead of running
|
||||||
|
# `next build`; see scripts/serve.sh --skip-frontend-build.
|
||||||
start:
|
start:
|
||||||
@$(PYTHON) ./scripts/check.py
|
@$(PYTHON) ./scripts/check.py
|
||||||
@$(RUN_WITH_GIT_BASH) ./scripts/serve.sh --prod
|
@$(RUN_WITH_GIT_BASH) ./scripts/serve.sh --prod $(if $(filter 1,$(SKIP_FRONTEND_BUILD)),--skip-frontend-build)
|
||||||
|
|
||||||
# Start all services in daemon mode (background)
|
# Start all services in daemon mode (background)
|
||||||
dev-daemon:
|
dev-daemon:
|
||||||
@ -150,7 +152,7 @@ dev-daemon:
|
|||||||
# Start prod services in daemon mode (background)
|
# Start prod services in daemon mode (background)
|
||||||
start-daemon:
|
start-daemon:
|
||||||
@$(PYTHON) ./scripts/check.py
|
@$(PYTHON) ./scripts/check.py
|
||||||
@$(RUN_WITH_GIT_BASH) ./scripts/serve.sh --prod --daemon
|
@$(RUN_WITH_GIT_BASH) ./scripts/serve.sh --prod --daemon $(if $(filter 1,$(SKIP_FRONTEND_BUILD)),--skip-frontend-build)
|
||||||
|
|
||||||
# Start nginx alone in the foreground with the local dev config
|
# Start nginx alone in the foreground with the local dev config
|
||||||
nginx:
|
nginx:
|
||||||
|
|||||||
@ -392,6 +392,11 @@ DeerFlow runs the agent runtime inside the Gateway API. Development mode enables
|
|||||||
| **Stop** | `./scripts/serve.sh --stop`<br/>`make stop` | `./scripts/docker.sh stop`<br/>`make docker-stop` | `./scripts/deploy.sh down`<br/>`make down` |
|
| **Stop** | `./scripts/serve.sh --stop`<br/>`make stop` | `./scripts/docker.sh stop`<br/>`make docker-stop` | `./scripts/deploy.sh down`<br/>`make down` |
|
||||||
| **Restart** | `./scripts/serve.sh --restart [flags]` | `./scripts/docker.sh restart` | — |
|
| **Restart** | `./scripts/serve.sh --restart [flags]` | `./scripts/docker.sh restart` | — |
|
||||||
|
|
||||||
|
`make start` and `make start-daemon` rebuild the frontend with `next build` on
|
||||||
|
every run. To reuse the last build instead, pass `SKIP_FRONTEND_BUILD=1` (or add
|
||||||
|
`--skip-frontend-build` when calling `./scripts/serve.sh --prod` directly). This
|
||||||
|
is opt-in: it fails fast when `frontend/.next` has no completed build.
|
||||||
|
|
||||||
Gateway owns `/api/langgraph/*` and translates those public LangGraph-compatible paths to its native `/api/*` routers behind nginx.
|
Gateway owns `/api/langgraph/*` and translates those public LangGraph-compatible paths to its native `/api/*` routers behind nginx.
|
||||||
|
|
||||||
#### LangGraph Studio (Optional)
|
#### LangGraph Studio (Optional)
|
||||||
|
|||||||
55
backend/tests/test_serve_frontend_skip_build.py
Normal file
55
backend/tests/test_serve_frontend_skip_build.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
"""Regression coverage for the opt-in --skip-frontend-build startup flag."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
SERVE_SH = REPO_ROOT / "scripts" / "serve.sh"
|
||||||
|
ROOT_MAKEFILE = REPO_ROOT / "Makefile"
|
||||||
|
|
||||||
|
|
||||||
|
def _make_recipe(target: str) -> str:
|
||||||
|
makefile = ROOT_MAKEFILE.read_text(encoding="utf-8")
|
||||||
|
match = re.search(rf"^{target}:\n((?:\t.*\n?)+)", makefile, re.M)
|
||||||
|
assert match, f"target {target!r} not found in root Makefile"
|
||||||
|
return match.group(1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_serve_script_parses_skip_frontend_build_flag() -> None:
|
||||||
|
serve = SERVE_SH.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert "SKIP_FRONTEND_BUILD=false" in serve
|
||||||
|
assert "--skip-frontend-build) SKIP_FRONTEND_BUILD=true ;;" in serve
|
||||||
|
|
||||||
|
|
||||||
|
def test_prod_default_still_builds_via_preview() -> None:
|
||||||
|
serve = SERVE_SH.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
# Verify the control-flow: skip flag -> `run start`, otherwise -> `run preview`.
|
||||||
|
assert re.search(
|
||||||
|
r"elif\s+\$SKIP_FRONTEND_BUILD;\s+then.*?FRONTEND_CMD=.*?run start.*?\nelse\n\s*FRONTEND_CMD=.*?run preview",
|
||||||
|
serve,
|
||||||
|
re.S,
|
||||||
|
), "expected prod default to use `run preview` and --skip-frontend-build to use `run start`"
|
||||||
|
|
||||||
|
|
||||||
|
def test_skip_build_reuses_existing_build_and_requires_build_id() -> None:
|
||||||
|
serve = SERVE_SH.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert 'if [ ! -f "$REPO_ROOT/frontend/.next/BUILD_ID" ]; then' in serve
|
||||||
|
assert "Run 'make start' once (full build)" in serve
|
||||||
|
|
||||||
|
|
||||||
|
def test_skip_build_preflight_runs_before_stop_all() -> None:
|
||||||
|
serve = SERVE_SH.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert serve.index("frontend/.next/BUILD_ID") < serve.index('if [ "$ACTION" = "restart" ]; then')
|
||||||
|
|
||||||
|
|
||||||
|
def test_make_start_exposes_flag_as_opt_in() -> None:
|
||||||
|
for target in ("start", "start-daemon"):
|
||||||
|
recipe = _make_recipe(target)
|
||||||
|
assert "--skip-frontend-build" in recipe
|
||||||
|
assert "$(if $(filter 1,$(SKIP_FRONTEND_BUILD)),--skip-frontend-build)" in recipe
|
||||||
@ -11,9 +11,11 @@
|
|||||||
# --daemon Run all services in background (nohup), exit after startup
|
# --daemon Run all services in background (nohup), exit after startup
|
||||||
#
|
#
|
||||||
# Actions:
|
# Actions:
|
||||||
# --skip-install Skip dependency installation (faster restart)
|
# --skip-install Skip dependency installation (faster restart)
|
||||||
# --stop Stop all running services and exit
|
# --skip-frontend-build With --prod, reuse the existing .next build via `next start`
|
||||||
# --restart Stop all services, then start with the given mode flags
|
# instead of `next build` (opt-in; fails if no build exists)
|
||||||
|
# --stop Stop all running services and exit
|
||||||
|
# --restart Stop all services, then start with the given mode flags
|
||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# ./scripts/serve.sh --dev # Gateway dev, hot reload
|
# ./scripts/serve.sh --dev # Gateway dev, hot reload
|
||||||
@ -53,6 +55,7 @@ _pick_python() {
|
|||||||
DEV_MODE=true
|
DEV_MODE=true
|
||||||
DAEMON_MODE=false
|
DAEMON_MODE=false
|
||||||
SKIP_INSTALL=false
|
SKIP_INSTALL=false
|
||||||
|
SKIP_FRONTEND_BUILD=false
|
||||||
ACTION="start" # start | stop | restart
|
ACTION="start" # start | stop | restart
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
@ -61,11 +64,12 @@ for arg in "$@"; do
|
|||||||
--prod) DEV_MODE=false ;;
|
--prod) DEV_MODE=false ;;
|
||||||
--daemon) DAEMON_MODE=true ;;
|
--daemon) DAEMON_MODE=true ;;
|
||||||
--skip-install) SKIP_INSTALL=true ;;
|
--skip-install) SKIP_INSTALL=true ;;
|
||||||
|
--skip-frontend-build) SKIP_FRONTEND_BUILD=true ;;
|
||||||
--stop) ACTION="stop" ;;
|
--stop) ACTION="stop" ;;
|
||||||
--restart) ACTION="restart" ;;
|
--restart) ACTION="restart" ;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown argument: $arg"
|
echo "Unknown argument: $arg"
|
||||||
echo "Usage: $0 [--dev|--prod] [--daemon] [--skip-install] [--stop|--restart]"
|
echo "Usage: $0 [--dev|--prod] [--daemon] [--skip-install] [--skip-frontend-build] [--stop|--restart]"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@ -268,6 +272,16 @@ stop_all() {
|
|||||||
echo "✓ All services stopped"
|
echo "✓ All services stopped"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Validate the reusable frontend build before any stop_all runs, so start and
|
||||||
|
# restart never tear down a healthy stack only to fail here. --stop is exempt.
|
||||||
|
if [ "$ACTION" != "stop" ] && ! $DEV_MODE && $SKIP_FRONTEND_BUILD; then
|
||||||
|
if [ ! -f "$REPO_ROOT/frontend/.next/BUILD_ID" ]; then
|
||||||
|
echo "✗ --skip-frontend-build requires an existing frontend build."
|
||||||
|
echo " Run 'make start' once (full build), or: cd frontend && pnpm run build"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Action routing ───────────────────────────────────────────────────────────
|
# ── Action routing ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
if [ "$ACTION" = "stop" ]; then
|
if [ "$ACTION" = "stop" ]; then
|
||||||
@ -305,6 +319,12 @@ export DEERFLOW_PNPM_PYTHON DEERFLOW_PNPM_RUNNER
|
|||||||
# Frontend command
|
# Frontend command
|
||||||
if $DEV_MODE; then
|
if $DEV_MODE; then
|
||||||
FRONTEND_CMD='env PORT=3000 "$DEERFLOW_PNPM_PYTHON" "$DEERFLOW_PNPM_RUNNER" run dev'
|
FRONTEND_CMD='env PORT=3000 "$DEERFLOW_PNPM_PYTHON" "$DEERFLOW_PNPM_RUNNER" run dev'
|
||||||
|
if $SKIP_FRONTEND_BUILD; then
|
||||||
|
echo " Note: --skip-frontend-build is ignored in dev mode (next dev does not build)."
|
||||||
|
fi
|
||||||
|
elif $SKIP_FRONTEND_BUILD; then
|
||||||
|
# The BUILD_ID preflight above already guarantees a reusable build exists.
|
||||||
|
FRONTEND_CMD="env PORT=3000 BETTER_AUTH_SECRET=$($DEERFLOW_PNPM_PYTHON -c 'import secrets; print(secrets.token_hex(16))') \"\$DEERFLOW_PNPM_PYTHON\" \"\$DEERFLOW_PNPM_RUNNER\" run start"
|
||||||
else
|
else
|
||||||
FRONTEND_CMD="env PORT=3000 BETTER_AUTH_SECRET=$($DEERFLOW_PNPM_PYTHON -c 'import secrets; print(secrets.token_hex(16))') \"\$DEERFLOW_PNPM_PYTHON\" \"\$DEERFLOW_PNPM_RUNNER\" run preview"
|
FRONTEND_CMD="env PORT=3000 BETTER_AUTH_SECRET=$($DEERFLOW_PNPM_PYTHON -c 'import secrets; print(secrets.token_hex(16))') \"\$DEERFLOW_PNPM_PYTHON\" \"\$DEERFLOW_PNPM_RUNNER\" run preview"
|
||||||
fi
|
fi
|
||||||
@ -405,6 +425,9 @@ echo " Starting DeerFlow"
|
|||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo ""
|
echo ""
|
||||||
echo " Mode: $MODE_LABEL"
|
echo " Mode: $MODE_LABEL"
|
||||||
|
if ! $DEV_MODE && $SKIP_FRONTEND_BUILD; then
|
||||||
|
echo " (frontend: reusing existing build)"
|
||||||
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
echo " Services:"
|
echo " Services:"
|
||||||
echo " Gateway → localhost:8001 (REST API + agent runtime)"
|
echo " Gateway → localhost:8001 (REST API + agent runtime)"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user