fix(frontend): emit relative asset paths so SPA loads under any subpath (#1195)

Vite's default base of '/' baked absolute asset URLs into the built
  index.html (/assets/..., /manifest.json, /img/..., /sw-register.js),
  so any path-prefixed reverse proxy (Traefik, nginx subpath, Cloudflare
  Tunnel with path routing) served the SPA as a blank white page — the
  browser requested assets from the host root and got HTML or text/plain
  back, triggering MIME-mismatch errors on every stylesheet/script.

  Set base: '' in vite.config.ts so the HTML transform emits relative
  URLs everywhere. Update public/sw-register.js to register('sw.js')
  (relative) so SW scope auto-pins to whatever subpath the document
  loaded from.

  Out of scope: API_BASE in client.ts is still absolute. The supported
  HA embedding path remains Webpage panel + TRUSTED_FRAME_ORIGINS, not
  HA Ingress (subpath-aware SPA bootstrapping has too many failure modes
  around PWA scope, push subscriptions, and deep-link reloads to take on
  in core). Documented explicitly in docker.md.

  Reported by @Spegeli, follow-up to #1167.
This commit is contained in:
maziggy
2026-05-03 07:33:40 +02:00
parent 875d80ad3c
commit d6a3139397
7 changed files with 16 additions and 8755 deletions
+8 -8
View File
@@ -17,17 +17,17 @@
<meta name="apple-mobile-web-app-title" content="Bambuddy" />
<!-- Manifest -->
<link rel="manifest" href="/manifest.json" />
<link rel="manifest" href="./manifest.json" />
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="./img/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="./img/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="./img/apple-touch-icon.png" />
<!-- Splash screens for iOS -->
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
<script type="module" crossorigin src="/assets/index-CwcBz1oz.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Cw7zekS6.css">
<link rel="apple-touch-startup-image" href="./img/android-chrome-512x512.png" />
<script type="module" crossorigin src="./assets/index-CwcBz1oz.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-Cw7zekS6.css">
</head>
<body>
<div id="root"></div>
@@ -35,6 +35,6 @@
<!-- Service Worker Registration (skip on SpoolBuddy kiosk).
Kept as an external file so the CSP `script-src 'self'` covers it
without needing 'unsafe-inline' or per-build hashes. -->
<script src="/sw-register.js"></script>
<script src="./sw-register.js"></script>
</body>
</html>