@@ -32,13 +32,16 @@ import Control.Monad.Primitive
3232import Control.Monad.Reader
3333import Control.Monad.Ref
3434import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
35+import qualified Data.Aeson as Aeson
3536import Data.ByteString (ByteString)
37+import qualified Data.ByteString.Lazy as LBS
3638import Data.Foldable (for_)
3739import Data.Functor.Sum
3840import Data.Map (Map)
3941import Data.Maybe (catMaybes)
4042import Data.Monoid ((<>))
4143import Data.Text (Text)
44+import qualified Data.Text.Encoding as T
4245import qualified GHCJS.DOM as DOM
4346import qualified GHCJS.DOM.Types as DOM
4447import qualified GHCJS.DOM.History as DOM
@@ -94,9 +97,9 @@ type PrebuildAgnostic t route m =
9497 , HasConfigs (Performable m)
9598 )
9699
97−data Frontend route = Frontend
98− { _frontend_head :: !(forall js t m. ObeliskWidget js t route m => RoutedT t route m ())
99− , _frontend_body :: !(forall js t m. ObeliskWidget js t route m => RoutedT t route m ())
100+data Frontend route result = Frontend
101+ { _frontend_head :: !(forall js t m. ObeliskWidget js t route m => RoutedT t route m result)
102+ , _frontend_body :: !(forall js t m. ObeliskWidget js t route m => RoutedT t route m result)
100103 }
101104
102105baseTag :: forall route js t m. ObeliskWidget js t route m => RoutedT t route m ()
@@ -144,9 +147,10 @@ data FrontendMode = FrontendMode
144147-- route exists ambiently in the context (e.g. anything but web).
145148-- Selects FrontendMode based on platform; this doesn't work for jsaddle-warp
146149runFrontend
147− :: forall backendRoute route
148− . Encoder Identity Identity (R (FullRoute backendRoute route)) PageName
149− -> Frontend (R route)
150+ :: forall backendRoute route result
151+ . (Semigroup result, Aeson.ToJSON result)
152+ => Encoder Identity Identity (R (FullRoute backendRoute route)) PageName
153+ -> Frontend (R route) result
150154 -> JSM ()
151155runFrontend validFullEncoder frontend = do
152156 let mode = FrontendMode
@@ -173,11 +177,12 @@ runFrontend validFullEncoder frontend = do
173177 runFrontendWithConfigsAndCurrentRoute mode configs validFullEncoder frontend
174178
175179runFrontendWithConfigsAndCurrentRoute
176− :: forall backendRoute frontendRoute
177− . FrontendMode
180+ :: forall backendRoute frontendRoute result
181+ . (Semigroup result, Aeson.ToJSON result)
182+ => FrontendMode
178183 -> Map Text ByteString
179184 -> Encoder Identity Identity (R (FullRoute backendRoute frontendRoute)) PageName
180− -> Frontend (R frontendRoute)
185+ -> Frontend (R frontendRoute) result
181186 -> JSM ()
182187runFrontendWithConfigsAndCurrentRoute mode configs validFullEncoder frontend = do
183188 let ve = validFullEncoder . hoistParse errorLeft (prismEncoder (rPrism $ _FullRoute_Frontend . _ObeliskRoute_App))
@@ -210,12 +215,14 @@ runFrontendWithConfigsAndCurrentRoute mode configs validFullEncoder frontend = d
210215 w appendHead appendBody = do
211216 rec switchover <- runRouteViewT ve switchover (_frontendMode_adjustRoute mode) $ do
212217 (switchover'', fire) <- newTriggerEvent
213− mapRoutedT (mapSetRouteT (mapRouteToUrlT (appendHead . runConfigsT configs))) $ do
218+ headResult <- mapRoutedT (mapSetRouteT (mapRouteToUrlT (appendHead . runConfigsT configs))) $ do
214219 -- The order here is important - baseTag has to be before headWidget!
215220 baseTag
216221 _frontend_head frontend
217222 mapRoutedT (mapSetRouteT (mapRouteToUrlT (appendBody . runConfigsT configs))) $ do
218− _frontend_body frontend
223+ bodyResult <- _frontend_body frontend
224+ elAttr "script" ("type"=:"text/plain" <> "data-initial-data"=:"") $
225+ text $ T.decodeUtf8 $ LBS.toStrict $ Aeson.encode $ headResult <> bodyResult
219226 switchover' <- case _frontendMode_hydrate mode of
220227 True -> lift $ lift $ lift $ lift $ HydrationDomBuilderT $ asks _hydrationDomBuilderEnv_switchover
221228 False -> getPostBuild
@@ -230,12 +237,13 @@ renderFrontendHtml
230237 :: ( t ~ DomTimeline
231238 , MonadIO m
232239 , widget ~ RoutedT t r (SetRouteT t r (RouteToUrlT r (ConfigsT (CookiesT (HydratableT (PostBuildT t (StaticDomBuilderT t (PerformEventT t DomHost))))))))
240+ , Semigroup result, Aeson.ToJSON result
233241 )
234242 => Map Text ByteString
235243 -> Cookies
236244 -> (r -> Text)
237245 -> r
238− -> Frontend r
246+ -> Frontend r result
239247 -> widget ()
240248 -> widget ()
241249 -> m ByteString
@@ -243,12 +251,15 @@ renderFrontendHtml configs cookies urlEnc route frontend headExtra bodyExtra = d
243251 --TODO: We should probably have a "NullEventWriterT" or a frozen reflex timeline
244252 html <- fmap snd $ liftIO $ renderStatic $ runHydratableT $ fmap fst $ runCookiesT cookies $ runConfigsT configs $ flip runRouteToUrlT urlEnc $ runSetRouteT $ flip runRoutedT (pure route) $
245253 el "html" $ do
246− el "head" $ do
254+ headResult <- el "head" $ do
247255 baseTag
248256 injectExecutableConfigs configs
249− _frontend_head frontend
257+ headResult <- _frontend_head frontend
250258 headExtra
259+ pure headResult
251260 el "body" $ do
252− _frontend_body frontend
261+ bodyResult <- _frontend_body frontend
253262 bodyExtra
263+ elAttr "script" ("type"=:"text/plain" <> "data-initial-data"=:"") $
264+ text $ T.decodeUtf8 $ LBS.toStrict $ Aeson.encode $ headResult <> bodyResult
254265 return $ "<!DOCTYPE html>" <> html