From 97b28031671e7c017502342411c84505ccce9dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sat, 13 Sep 2025 01:37:48 +0200 Subject: [PATCH] serveWebappDist --- packages/server/src/http.ts | 51 ++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/packages/server/src/http.ts b/packages/server/src/http.ts index 1cb25b8..59936f6 100644 --- a/packages/server/src/http.ts +++ b/packages/server/src/http.ts @@ -1,5 +1,5 @@ -import { HttpMiddleware, HttpRouter, HttpServer, HttpServerResponse, Path } from "@effect/platform" -import { Console, Effect, flow, Layer } from "effect" +import { FileSystem, HttpMiddleware, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse, Path } from "@effect/platform" +import { Duration, Effect, flow } from "effect" const router = HttpRouter.empty.pipe( @@ -13,23 +13,38 @@ export const HttpAppDevelopment = router.pipe( HttpServer.withLogAddress, ) -export const HttpAppProduction = Effect.Do.pipe( - Effect.bind("path", () => Path.Path), - Effect.bind("webappDist", ({ path }) => Effect.map( - path.fromFileUrl(new URL(".", import.meta.resolve("@website/webapp"))), - v => path.join(v, "dist"), + +const serveWebappDist = Effect.fnUntraced(function*(file: string) { + const path = yield* Path.Path + const fs = yield* FileSystem.FileSystem + const source = path.join( + yield* path.fromFileUrl(new URL(".", import.meta.resolve("@website/webapp"))), + "dist", file, + ) + const exists = yield* fs.stat(source).pipe( + Effect.andThen(stat => stat.type === "File"), + Effect.catchAll(() => Effect.succeed(false)), + ) + + return exists + ? yield* HttpServerResponse.setHeader( + yield* HttpServerResponse.file(source), + "Cache-Control", + `public, max-age=${Duration.toSeconds("365 days")}, immutable` + ) + : yield* HttpServerResponse.setStatus(HttpServerResponse.empty(), 404) +}) + +export const HttpAppProduction = router.pipe( + HttpRouter.all("/assets/*", Effect.andThen( + HttpServerRequest.HttpServerRequest, + req => serveWebappDist(req.url), )), + HttpRouter.all("*", serveWebappDist("index.html")), - Effect.map(({ path, webappDist }) => router.pipe( - HttpRouter.all("/", HttpServerResponse.file(path.join(webappDist, "index.html"))), - HttpRouter.all("/assets", HttpServerResponse.file(path.join(webappDist, "assets"))), - - HttpServer.serve(flow( - HttpMiddleware.logger, - HttpMiddleware.xForwardedHeaders, - )), - HttpServer.withLogAddress, + HttpServer.serve(flow( + HttpMiddleware.logger, + HttpMiddleware.xForwardedHeaders, )), - - Layer.unwrapEffect, + HttpServer.withLogAddress, )