mirror of
https://github.com/ZhuLinsen/daily_stock_analysis
synced 2026-09-20 10:53:33 +08:00
* fix: detect stale static bundles in build pipeline and at runtime (#1064) Add a packaging-time sanity check and a backend startup self-check that verifies index.html only references /assets/*.js and /assets/*.css files that actually exist on disk. This is the most common root cause of the 'Preparing backend...' / blank-page bug seen on the Windows immutable Release packages: vite emits a fresh index.html with new content hashes, but the desktop packaging step picks up a stale static/ directory, so the browser receives a 404 (returned as application/json) for the main bundle and refuses to execute it. - scripts/check_static_assets.py: cross-platform sanity script. - scripts/build-backend{.ps1,-macos.sh}: run the script after npm build on the source static/, and again after PyInstaller on the packaged static directory; fail the build on mismatch. - api/app.py: log an actionable ERROR when an inconsistency is detected at startup so the root cause appears in logs/desktop.log instead of surfacing as a silent blank page. - api/app.py: replace the StaticFiles mount with an explicit /assets/* route so misses return a plain-text 404 with a JS/CSS Content-Type, not the default JSON error response that masked diagnosis in #1064. - tests/test_static_assets_consistency.py: 7 deterministic tests for both code paths. Refs #1064 #1065 #1050
127 lines
3.3 KiB
Bash
Executable File
127 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
|
|
log() {
|
|
echo "$1"
|
|
}
|
|
|
|
PYTHON_BIN="${PYTHON_BIN:-}"
|
|
if [[ -z "${PYTHON_BIN}" ]]; then
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
PYTHON_BIN="python3"
|
|
else
|
|
PYTHON_BIN="python"
|
|
fi
|
|
fi
|
|
|
|
if ! command -v "${PYTHON_BIN}" >/dev/null 2>&1; then
|
|
echo "Python not found. Please install Python 3.10+ and retry."
|
|
exit 1
|
|
fi
|
|
|
|
log "Building React UI (static assets)..."
|
|
pushd "${ROOT_DIR}/apps/dsa-web" >/dev/null
|
|
if [[ ! -d node_modules ]]; then
|
|
npm install
|
|
fi
|
|
npm run build
|
|
popd >/dev/null
|
|
|
|
log "Verifying static asset references (source)..."
|
|
"${PYTHON_BIN}" "${SCRIPT_DIR}/check_static_assets.py" "${ROOT_DIR}/static"
|
|
|
|
log "Building backend executable..."
|
|
if ! "${PYTHON_BIN}" -m PyInstaller --version >/dev/null 2>&1; then
|
|
"${PYTHON_BIN}" -m pip install pyinstaller
|
|
fi
|
|
|
|
log "Installing backend dependencies..."
|
|
"${PYTHON_BIN}" -m pip install -r "${ROOT_DIR}/requirements.txt"
|
|
|
|
log "Checking python-multipart availability..."
|
|
"${PYTHON_BIN}" -c "import multipart, multipart.multipart"
|
|
|
|
if [[ -d "${ROOT_DIR}/dist/backend" ]]; then
|
|
rm -rf "${ROOT_DIR}/dist/backend"
|
|
fi
|
|
mkdir -p "${ROOT_DIR}/dist/backend"
|
|
|
|
if [[ -d "${ROOT_DIR}/dist/stock_analysis" ]]; then
|
|
rm -rf "${ROOT_DIR}/dist/stock_analysis"
|
|
fi
|
|
|
|
if [[ -d "${ROOT_DIR}/build/stock_analysis" ]]; then
|
|
rm -rf "${ROOT_DIR}/build/stock_analysis"
|
|
fi
|
|
|
|
hidden_imports=(
|
|
"multipart"
|
|
"multipart.multipart"
|
|
"json_repair"
|
|
"tiktoken"
|
|
"tiktoken_ext"
|
|
"tiktoken_ext.openai_public"
|
|
"api"
|
|
"api.app"
|
|
"api.deps"
|
|
"api.v1"
|
|
"api.v1.router"
|
|
"api.v1.endpoints"
|
|
"api.v1.endpoints.analysis"
|
|
"api.v1.endpoints.history"
|
|
"api.v1.endpoints.stocks"
|
|
"api.v1.endpoints.health"
|
|
"api.v1.schemas"
|
|
"api.v1.schemas.analysis"
|
|
"api.v1.schemas.history"
|
|
"api.v1.schemas.stocks"
|
|
"api.v1.schemas.common"
|
|
"api.middlewares"
|
|
"api.middlewares.error_handler"
|
|
"src.services"
|
|
"src.services.task_queue"
|
|
"src.services.analysis_service"
|
|
"src.services.history_service"
|
|
"uvicorn.logging"
|
|
"uvicorn.loops"
|
|
"uvicorn.loops.auto"
|
|
"uvicorn.protocols"
|
|
"uvicorn.protocols.http"
|
|
"uvicorn.protocols.http.auto"
|
|
"uvicorn.protocols.websockets"
|
|
"uvicorn.protocols.websockets.auto"
|
|
"uvicorn.lifespan"
|
|
"uvicorn.lifespan.on"
|
|
)
|
|
|
|
hidden_import_args=()
|
|
for module in "${hidden_imports[@]}"; do
|
|
hidden_import_args+=("--hidden-import=${module}")
|
|
done
|
|
|
|
pushd "${ROOT_DIR}" >/dev/null
|
|
cmd=("${PYTHON_BIN}" -m PyInstaller --name stock_analysis --onedir --noconfirm --noconsole --add-data "static:static" --collect-data litellm --collect-data tiktoken)
|
|
cmd+=("${hidden_import_args[@]}" "main.py")
|
|
|
|
echo "Running: ${cmd[*]}"
|
|
"${cmd[@]}"
|
|
popd >/dev/null
|
|
|
|
cp -R "${ROOT_DIR}/dist/stock_analysis" "${ROOT_DIR}/dist/backend/stock_analysis"
|
|
|
|
log "Verifying static asset references (packaged)..."
|
|
packaged_static="${ROOT_DIR}/dist/backend/stock_analysis/_internal/static"
|
|
if [[ ! -d "${packaged_static}" ]]; then
|
|
packaged_static="${ROOT_DIR}/dist/backend/stock_analysis/static"
|
|
fi
|
|
if [[ -d "${packaged_static}" ]]; then
|
|
"${PYTHON_BIN}" "${SCRIPT_DIR}/check_static_assets.py" "${packaged_static}"
|
|
else
|
|
log "WARNING: could not locate packaged static directory under dist/backend/stock_analysis; skipping post-package check."
|
|
fi
|
|
|
|
log "Backend build completed."
|