forked from niuniu/llm-intelligence
93 lines
2.7 KiB
Bash
93 lines
2.7 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||
|
|
FRONTEND_DIR="$PROJECT_ROOT/frontend"
|
||
|
|
LIGHTHOUSE_PORT="${LIGHTHOUSE_PORT:-4173}"
|
||
|
|
LIGHTHOUSE_SCORE_THRESHOLD="${LIGHTHOUSE_SCORE_THRESHOLD:-80}"
|
||
|
|
LIGHTHOUSE_FCP_THRESHOLD_MS="${LIGHTHOUSE_FCP_THRESHOLD_MS:-2000}"
|
||
|
|
LIGHTHOUSE_URL="http://127.0.0.1:${LIGHTHOUSE_PORT}"
|
||
|
|
LIGHTHOUSE_JSON="${TMPDIR:-/tmp}/llm_lighthouse_report.json"
|
||
|
|
PREVIEW_LOG="${TMPDIR:-/tmp}/llm_lighthouse_preview.log"
|
||
|
|
PREVIEW_PID=""
|
||
|
|
CHROME_BIN=""
|
||
|
|
|
||
|
|
cleanup() {
|
||
|
|
if [[ -n "${PREVIEW_PID:-}" ]] && kill -0 "$PREVIEW_PID" >/dev/null 2>&1; then
|
||
|
|
kill "$PREVIEW_PID" >/dev/null 2>&1 || true
|
||
|
|
wait "$PREVIEW_PID" >/dev/null 2>&1 || true
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
trap cleanup EXIT
|
||
|
|
|
||
|
|
for candidate in /usr/bin/google-chrome-stable /usr/bin/google-chrome /snap/bin/chromium /usr/bin/chromium /usr/bin/chromium-browser; do
|
||
|
|
if [[ -x "$candidate" ]]; then
|
||
|
|
CHROME_BIN="$candidate"
|
||
|
|
break
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
|
||
|
|
if [[ -z "$CHROME_BIN" ]]; then
|
||
|
|
echo "LIGHTHOUSE_ERROR=chrome-not-found"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
cd "$FRONTEND_DIR"
|
||
|
|
npm run build >/tmp/llm_lighthouse_build.out 2>/tmp/llm_lighthouse_build.err
|
||
|
|
|
||
|
|
npm exec vite preview -- --host 127.0.0.1 --port "$LIGHTHOUSE_PORT" >"$PREVIEW_LOG" 2>&1 &
|
||
|
|
PREVIEW_PID=$!
|
||
|
|
|
||
|
|
for _ in $(seq 1 30); do
|
||
|
|
if curl -fsS "$LIGHTHOUSE_URL" >/dev/null 2>&1; then
|
||
|
|
break
|
||
|
|
fi
|
||
|
|
sleep 0.5
|
||
|
|
done
|
||
|
|
|
||
|
|
if ! curl -fsS "$LIGHTHOUSE_URL" >/dev/null 2>&1; then
|
||
|
|
echo "LIGHTHOUSE_ERROR=preview-not-ready"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
npx lighthouse "$LIGHTHOUSE_URL" \
|
||
|
|
--chrome-path="$CHROME_BIN" \
|
||
|
|
--only-categories=performance \
|
||
|
|
--preset=desktop \
|
||
|
|
--output=json \
|
||
|
|
--output-path="$LIGHTHOUSE_JSON" \
|
||
|
|
--quiet \
|
||
|
|
--chrome-flags="--headless=new --no-sandbox --disable-dev-shm-usage" \
|
||
|
|
>/tmp/llm_lighthouse_stdout.out 2>/tmp/llm_lighthouse_stderr.err
|
||
|
|
|
||
|
|
read -r score fcp speed_index lcp <<EOF
|
||
|
|
$(node -e '
|
||
|
|
const fs = require("fs");
|
||
|
|
const report = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
||
|
|
const perf = Math.round((report.categories.performance.score || 0) * 100);
|
||
|
|
const fcp = Math.round(report.audits["first-contentful-paint"]?.numericValue || 0);
|
||
|
|
const speedIndex = Math.round(report.audits["speed-index"]?.numericValue || 0);
|
||
|
|
const lcp = Math.round(report.audits["largest-contentful-paint"]?.numericValue || 0);
|
||
|
|
console.log(`${perf} ${fcp} ${speedIndex} ${lcp}`);
|
||
|
|
' "$LIGHTHOUSE_JSON")
|
||
|
|
EOF
|
||
|
|
|
||
|
|
echo "LIGHTHOUSE_SCORE=${score}"
|
||
|
|
echo "LIGHTHOUSE_FCP_MS=${fcp}"
|
||
|
|
echo "LIGHTHOUSE_SPEED_INDEX_MS=${speed_index}"
|
||
|
|
echo "LIGHTHOUSE_LCP_MS=${lcp}"
|
||
|
|
|
||
|
|
if (( score < LIGHTHOUSE_SCORE_THRESHOLD )); then
|
||
|
|
echo "LIGHTHOUSE_ERROR=score-below-threshold"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
if (( fcp >= LIGHTHOUSE_FCP_THRESHOLD_MS )); then
|
||
|
|
echo "LIGHTHOUSE_ERROR=fcp-above-threshold"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|