Files
sis/app/Main.hs
T
jbrechtel 72b1ee1d3d Add SPA static file serving from backend
Backend (Server.hs):
- serveStaticOrSpa: serves static files from --static-dir
- SPA fallback: extensionless paths serve index.html
- MIME type mapping for html/css/js/png/svg/ico/woff2

Frontend:
- ES module imports with import map for Mithril CDN
- Build script: tsc + copy index.html + static assets

CLI:
- --static-dir flag (default: frontend/dist)
- scripts/run passes through extra args
- Dockerfile CMD points at /usr/local/share/sis/static
2026-07-15 14:59:31 -04:00

65 lines
1.6 KiB
Haskell

{-# LANGUAGE OverloadedStrings #-}
{- | Entry point for the Sis chore tracker server.
Starts a Warp HTTP server, serves the JSON API and the SPA frontend.
-}
module Main (main) where
import Network.Wai.Handler.Warp qualified as Warp
import Options.Applicative qualified as Opt
import System.Posix.Signals qualified as Signals
import Sis.Server qualified as Sis
data Options = Options
{ optPort :: Int
, optStaticDir :: FilePath
}
optionsParser :: Opt.Parser Options
optionsParser =
Options
<$> Opt.option
Opt.auto
( Opt.long "port"
<> Opt.short 'p'
<> Opt.metavar "PORT"
<> Opt.help "Listen port"
<> Opt.value 8080
<> Opt.showDefault
)
<*> Opt.strOption
( Opt.long "static-dir"
<> Opt.metavar "DIR"
<> Opt.help "Directory containing the SPA frontend static files"
<> Opt.value "frontend/dist"
<> Opt.showDefault
)
main :: IO ()
main = do
opts <-
Opt.execParser $
Opt.info (optionsParser Opt.<**> Opt.helper) $
Opt.fullDesc
<> Opt.progDesc "Sis — shared household chore tracker"
<> Opt.header "sis-server"
-- Install a SIGTERM handler so Docker stop works cleanly.
_ <-
Signals.installHandler
Signals.sigTERM
(Signals.Catch (putStrLn "[sis] shutting down"))
Nothing
let waiApp = Sis.app (optStaticDir opts)
let settings =
Warp.setPort (optPort opts) $
Warp.setBeforeMainLoop
(putStrLn $ "[sis] listening on port " ++ show (optPort opts))
Warp.defaultSettings
Warp.runSettings settings waiApp