perf: bundle and fingerprint the PWA runtime (#379)
CI / lint (pull_request) Successful in 42s
CI / build-release (pull_request) Successful in 5s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-09 06:59:05 +00:00
1 parent 56a9a0cba6
commit a919242b8f
8 files changed
+187 -16

No files matched your search

+70
View File
@@ -0,0 +1,70 @@
"""Build the content-addressed browser shell served by the dashboard."""
from __future__ import annotations
import hashlib
import re
from dataclasses import dataclass
from pathlib import Path
SCRIPT_TAG = re.compile(r'^<script src="(static/[^"?]+\.js)"></script>$', re.MULTILINE)
WORKER_RUNTIME_SOURCE = "static/background-issue-sync.js"
@dataclass(frozen=True)
class FrontendBuild:
dashboard_html: str
runtime_bytes: bytes
runtime_digest: str
runtime_name: str
page_sources: tuple[str, ...]
service_worker_source: str
def _bundle(frontend_dir: Path, sources: tuple[str, ...]) -> bytes:
chunks = []
for source in sources:
path = frontend_dir / source.removeprefix("static/")
chunks.append(f"/* {source} */\n".encode() + path.read_bytes() + b"\n;\n")
return b"".join(chunks)
def build_frontend(frontend_dir: Path) -> FrontendBuild:
"""Return one internally consistent HTML, runtime, and offline-worker build."""
source_html = (frontend_dir / "index.html").read_text()
sources = tuple(SCRIPT_TAG.findall(source_html))
if not sources:
raise ValueError("dashboard entry document has no page scripts")
runtime = _bundle(frontend_dir, sources)
digest = hashlib.sha256(runtime).hexdigest()[:16]
runtime_name = f"runtime-{digest}.js"
dashboard_html = SCRIPT_TAG.sub("", source_html)
dashboard_html = dashboard_html.replace(
"</body>", f'<script src="{runtime_name}"></script>\n</body>'
)
worker = (frontend_dir / "service-worker.js").read_text()
for source in sources:
if source != WORKER_RUNTIME_SOURCE:
worker = worker.replace(f" BASE + '{source}',\n", "")
worker = worker.replace(
" BASE + 'static/dashboard.css',\n",
f" BASE + 'static/dashboard.css',\n BASE + '{runtime_name}',\n",
)
worker = re.sub(
r"const CACHE = 'stackchain-dashboard-shell-v\d+';",
f"const CACHE = 'stackchain-dashboard-shell-{digest}';",
worker,
count=1,
)
return FrontendBuild(
dashboard_html=dashboard_html,
runtime_bytes=runtime,
runtime_digest=digest,
runtime_name=runtime_name,
page_sources=sources,
service_worker_source=worker,
)
+8 -2
View File
@@ -37,7 +37,7 @@ from src.request_boundary import RequestBodyLimitMiddleware, request_body_limit
from src.suggestion_engine import compute
from src.later_store import LaterStore
from src.today_store import TodayPlanFull, TodayStore
from src.views import router as frontend_router
from src.views import FRONTEND_BUILD, router as frontend_router
@asynccontextmanager
async def lifespan(_app: FastAPI):
@@ -588,7 +588,13 @@ async def require_operator_session(request: Request, call_next):
return await call_next(request)
public = (
path in {"/healthz", "/readyz", "/login", "/manifest.webmanifest"}
path in {
"/healthz",
"/readyz",
"/login",
"/manifest.webmanifest",
"/" + FRONTEND_BUILD.runtime_name,
}
or path.startswith("/static/")
or (path == "/api/v1/session" and request.method == "POST")
)
+21 -8
View File
@@ -1,12 +1,14 @@
from pathlib import Path
from fastapi import APIRouter
from fastapi.responses import FileResponse, HTMLResponse
from fastapi import APIRouter, HTTPException
from fastapi.responses import FileResponse, HTMLResponse, Response
from src.frontend_bundle import build_frontend
router = APIRouter()
DASHBOARD_FILE = Path(__file__).resolve().parent.parent / "frontend" / "index.html"
MANIFEST_FILE = DASHBOARD_FILE.parent / "manifest.webmanifest"
SERVICE_WORKER_FILE = DASHBOARD_FILE.parent / "service-worker.js"
FRONTEND_BUILD = build_frontend(DASHBOARD_FILE.parent)
LOGIN_HTML = """<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
@@ -26,7 +28,7 @@ class RevalidatingHTMLResponse(HTMLResponse):
@router.get("/", response_class=RevalidatingHTMLResponse)
async def dashboard() -> str:
return DASHBOARD_FILE.read_text()
return FRONTEND_BUILD.dashboard_html
@router.get("/login", response_class=RevalidatingHTMLResponse)
@@ -39,10 +41,21 @@ async def web_app_manifest() -> FileResponse:
return FileResponse(MANIFEST_FILE, media_type="application/manifest+json")
@router.get("/service-worker.js", response_class=FileResponse)
async def service_worker() -> FileResponse:
return FileResponse(
SERVICE_WORKER_FILE,
@router.get("/service-worker.js")
async def service_worker() -> Response:
return Response(
FRONTEND_BUILD.service_worker_source,
media_type="application/javascript",
headers={"Service-Worker-Allowed": "/", "Cache-Control": "no-cache"},
)
@router.get("/runtime-{digest}.js")
async def runtime_bundle(digest: str) -> Response:
if digest != FRONTEND_BUILD.runtime_digest:
raise HTTPException(status_code=404, detail="Runtime revision not found")
return Response(
FRONTEND_BUILD.runtime_bytes,
media_type="application/javascript",
headers={"Cache-Control": "public, max-age=31536000, immutable"},
)