fire-planner: SPA cache headers — index.html no-cache, hashed assets immutable
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Browsers were caching the old index.html which still pointed at the pre-Wave-2 bundle hash. Hashed assets under /assets/ stay cacheable for a year (immutable), but index.html (and any SPA fallback) must revalidate every request so a fresh deploy is visible immediately.
This commit is contained in:
parent
727e0bed08
commit
2f95c891fa
1 changed files with 19 additions and 2 deletions
|
|
@ -166,17 +166,34 @@ class _SPAStaticFiles(StaticFiles):
|
|||
|
||||
`StaticFiles(html=True)` only serves index.html for *directories*,
|
||||
not arbitrary not-found paths — that's not enough for a SPA.
|
||||
|
||||
Cache policy: Vite hashes assets (e.g. ``index-XjyVM1-C.js``) so they
|
||||
are immutable and can be cached forever. ``index.html`` references
|
||||
those by hash — if the browser caches a stale ``index.html`` it'll
|
||||
keep loading the OLD bundle. Force ``index.html`` (and any non-hashed
|
||||
response, including SPA fallbacks) to revalidate on every request.
|
||||
"""
|
||||
|
||||
async def get_response(self, path: str, scope: Scope): # type: ignore[no-untyped-def]
|
||||
try:
|
||||
return await super().get_response(path, scope)
|
||||
response = await super().get_response(path, scope)
|
||||
except StarletteHTTPException as exc:
|
||||
if exc.status_code == 404:
|
||||
index = Path(self.directory) / "index.html" # type: ignore[arg-type]
|
||||
if index.is_file():
|
||||
return FileResponse(index)
|
||||
return FileResponse(
|
||||
index,
|
||||
headers={"Cache-Control": "no-cache, must-revalidate"},
|
||||
)
|
||||
raise
|
||||
# Hashed Vite assets live under /assets/ and contain an 8-char
|
||||
# hash — safe to cache aggressively. index.html and anything
|
||||
# else (logos, favicons) revalidate.
|
||||
if path.startswith("assets/") and "-" in path:
|
||||
response.headers["Cache-Control"] = "public, max-age=31536000, immutable"
|
||||
else:
|
||||
response.headers["Cache-Control"] = "no-cache, must-revalidate"
|
||||
return response
|
||||
|
||||
|
||||
# Mount the SPA last so it catches any path the API didn't claim.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue