Add a general SPA fallback instead of an explicit per-route list

Direct hits on client-side routes not in the hardcoded list (e.g. a
browser refresh on /faktiska or /udens-temperatura) 404ed instead of
loading the app — a known limitation that was actually hit in
production. Real files now serve as-is; anything else falls back to
index.html so the SolidJS router handles it, matching the existing
"TODO rewrite in more generic way" comment. Future routes need no
backend changes.
This commit is contained in:
b0txec
2026-08-24 10:32:38 +03:00
parent 1086c8b548
commit 2c4488846e
+14 -11
View File
@@ -2,6 +2,7 @@ package server
import cats.effect._ import cats.effect._
import cats.implicits.toTraverseOps import cats.implicits.toTraverseOps
import cats.syntax.semigroupk._
import com.comcast.ip4s.IpLiteralSyntax import com.comcast.ip4s.IpLiteralSyntax
import data.DataService import data.DataService
import db.PostgresService import db.PostgresService
@@ -203,18 +204,20 @@ class Server(postgresService: PostgresService, dataService: DataService, fetch:
private val apiRoutesCors = CORS(apiRoutes, corsConfig) private val apiRoutesCors = CORS(apiRoutes, corsConfig)
private val httpApp = Router( // Real files (JS/CSS/images/favicon) are served as-is; anything else falls
"/" -> staticcontent.fileService[IO](FileService.Config("./web/dist")), // back to index.html so the SolidJS router can handle it client-side. This
"/api" -> apiRoutesCors, // replaces an explicit per-route list that silently 404ed on a direct hit
// (e.g. a browser refresh) for any client-side route not on the list —
// real, observed on /faktiska and /udens-temperatura in production.
private val assets = staticcontent.fileService[IO](FileService.Config("./web/dist"))
private val spaFallback = HttpRoutes.of[IO] {
case req @ GET -> _ =>
StaticFile.fromPath(Path("./web/dist/index.html"), Some(req)).getOrElseF(NotFound())
}
// TODO rewrite in more generic way private val httpApp = Router(
"/station" -> staticcontent.fileService[IO](FileService.Config("./web/dist")), "/api" -> apiRoutesCors,
"/cities" -> staticcontent.fileService[IO](FileService.Config("./web/dist")), "/" -> (assets <+> spaFallback),
"/latvia" -> staticcontent.fileService[IO](FileService.Config("./web/dist")),
"/database" -> staticcontent.fileService[IO](FileService.Config("./web/dist")),
"/harmonie" -> staticcontent.fileService[IO](FileService.Config("./web/dist")),
"/lvgmc-forecast" -> staticcontent.fileService[IO](FileService.Config("./web/dist")),
"/bridinajumi" -> staticcontent.fileService[IO](FileService.Config("./web/dist")),
).orNotFound ).orNotFound
def run: IO[ExitCode] = def run: IO[ExitCode] =