@@ -17,6 +17,7 @@ module Obelisk.Backend
1717 , serveDefaultObeliskApp
1818 , prettifyOutput
1919 , runBackend
20+ , runBackendWithAssetsFromDirectory
2021 , staticRenderContentType
2122 , mkRouteToUrl
2223 , getPublicConfigs
@@ -49,6 +50,7 @@ import Snap (MonadSnap, Snap, commandLineConfig, defaultConfig, getsRequest, htt
4950 , rqCookies, Cookie(..))
5051import Snap.Internal.Http.Server.Config (Config (accessLog, errorLog), ConfigLog (ConfigIoLog))
5152import System.IO (BufferMode (..), hSetBuffering, stderr, stdout)
53+import System.FilePath
5254
5355data Backend backendRoute frontendRoute = Backend
5456 { _backend_routeEncoder :: Encoder (Either Text) Identity (R (FullRoute backendRoute frontendRoute)) PageName
@@ -140,7 +142,13 @@ serveObeliskApp urlEnc serveStaticAsset frontendApp config = \case
140142 ResourceRoute_Version :=> Identity () -> doNotCache >> serveFileIfExistsAs "text/plain" "version"
141143
142144serveStaticAssets :: MonadSnap m => StaticAssets -> [Text] -> m ()
143−serveStaticAssets assets pathSegments = serveAsset (_staticAssets_processed assets) (_staticAssets_unprocessed assets) $ T.unpack $ T.intercalate "/" pathSegments
145+serveStaticAssets = serveStaticAssetsFromDirectory "."
146+
147+-- | Serve static assets from a specific directory
148+serveStaticAssetsFromDirectory :: MonadSnap m => FilePath -> StaticAssets -> [Text] -> m ()
149+serveStaticAssetsFromDirectory dir assets pathSegments =
150+ serveAsset (normalise $ dir </> _staticAssets_processed assets) (normalise $ dir </> _staticAssets_unprocessed assets) $
151+ T.unpack $ T.intercalate "/" pathSegments
144152
145153data StaticAssets = StaticAssets
146154 { _staticAssets_processed :: !FilePath
@@ -170,7 +178,10 @@ serveGhcjsApp urlEnc app config = \case
170178 GhcjsAppRoute_Resource :=> Identity pathSegments -> serveStaticAssets (_ghcjsApp_compiled app) pathSegments
171179
172180runBackend :: Backend backendRoute frontendRoute -> Frontend (R frontendRoute) -> IO ()
173−runBackend backend frontend = case checkEncoder $ _backend_routeEncoder backend of
181+runBackend = runBackendWithAssetsFromDirectory "."
182+
183+runBackendWithAssetsFromDirectory :: FilePath -> Backend backendRoute frontendRoute -> Frontend (R frontendRoute) -> IO ()
184+runBackendWithAssetsFromDirectory assetDir backend frontend = case checkEncoder $ _backend_routeEncoder backend of
174185 Left e -> fail $ "backend error:\n" <> T.unpack e
175186 Right validFullEncoder -> do
176187 publicConfigs <- getPublicConfigs
@@ -180,7 +191,14 @@ runBackend backend frontend = case checkEncoder $ _backend_routeEncoder backend
180191 Identity r -> case r of
181192 FullRoute_Backend backendRoute :/ a -> serveRoute $ backendRoute :/ a
182193 FullRoute_Frontend obeliskRoute :/ a ->
183− serveDefaultObeliskApp (mkRouteToUrl validFullEncoder) (serveStaticAssets defaultStaticAssets) frontend publicConfigs $
194+ let frontendApp = GhcjsApp
195+ { _ghcjsApp_compiled = StaticAssets {
196+ _staticAssets_processed = (normalise $ assetDir </> _staticAssets_processed defaultFrontendGhcjsAssets)
197+ , _staticAssets_unprocessed = (normalise $ assetDir </> _staticAssets_unprocessed defaultFrontendGhcjsAssets)
198+ }
199+ , _ghcjsApp_value = frontend
200+ }
201+ in serveObeliskApp (mkRouteToUrl validFullEncoder) (serveStaticAssetsFromDirectory assetDir defaultStaticAssets) frontendApp publicConfigs $
184202 obeliskRoute :/ a
185203
186204mkRouteToUrl :: Encoder Identity parse (R (FullRoute br fr)) PageName -> R fr -> Text