on develop help sign in
Allow prerender to change type of client widget

- Added HydrationDomSpace So that we no longer need to use GhcjsDomSpace, and can return () instead of _|_ for element/node types. - Prerender changed to allow changing type of client widget The core reason is because we need DomSpace ~ GhcjsDomSpace in the client widget, but with HydrationDomBuilderT we now have HydrationDomSpace. We also return `Dynamic a` instead of just `a`: the hydration builder runs both server and client, returning server `a` until switchover, at which point it runs the client and updates the dynamic with the resultant `a`. This ensures that any expected DOM at switchover time is exactly the same as was generated by the static builder, e.g. for the previously broken case of text =<< prerender (pure "A") (pure "B") we'd now have the (fixed and hydrateable) behaviour with dynText =<< prerender (pure "A") (pure "B") - RawFile has gone in favour of just concretely using GHCJS File Reason: We should be able to use the file input in HydrationDomBuilder and actually use those files after switchover, but because we don't know the DomSpace outside of prerender, we can't know RawFile ~ DOM.File and thus can't use the returned files. Justification: We don't have the problem of having to return some concrete values (in the static builder), because we only ever use it in a list.

commitf1cf26f0c755aa042ab8b4d4f4f92a79da67ffa0 authorTom Smalley <tfsmalley@gmail.com> dateThu 13 Dec 2018, 13:43 (8 years ago) parent42d55e3
5 files changed+188−114
reflex-dom-core/src/Reflex/Dom/Builder/Class.hs+2−2 reflex-dom-core/src/Reflex/Dom/Builder/Hydration.hs+52−25 reflex-dom-core/src/Reflex/Dom/Builder/Immediate.hs−1 reflex-dom-core/src/Reflex/Dom/Builder/Static.hs+2−1 reflex-dom-core/src/Reflex/Dom/Prerender.hs+132−85
reflex-dom-core/src/Reflex/Dom/Builder/Class.hs+2−2
@@ -61,6 +61,7 @@ import Data.String
6161import Data.Text (Text)
6262import Data.Type.Coercion
6363import GHCJS.DOM.Types (JSM)
64+import qualified GHCJS.DOM.Types as DOM
6465
6566class Default (EventSpec d EventResult) => DomSpace d where
6667 type EventSpec d :: (EventTag -> *) -> *
@@ -68,7 +69,6 @@ class Default (EventSpec d EventResult) => DomSpace d where
6869 type RawTextNode d :: *
6970 type RawCommentNode d :: *
7071 type RawElement d :: *
71− type RawFile d :: *
7272 type RawInputElement d :: *
7373 type RawTextAreaElement d :: *
7474 type RawSelectElement d :: *
@@ -323,7 +323,7 @@ data InputElement er d t
323323 , _inputElement_hasFocus :: Dynamic t Bool
324324 , _inputElement_element :: Element er d t
325325 , _inputElement_raw :: RawInputElement d
326− , _inputElement_files :: Dynamic t [RawFile d]
326+ , _inputElement_files :: Dynamic t [DOM.File]
327327 }
328328
329329data TextAreaElementConfig er t m
reflex-dom-core/src/Reflex/Dom/Builder/Hydration.hs+52−25
@@ -4,6 +4,7 @@
44{-# LANGUAGE DataKinds #-}
55{-# LANGUAGE DeriveFunctor #-}
66{-# LANGUAGE DeriveTraversable #-}
7+{-# LANGUAGE EmptyDataDecls #-}
78{-# LANGUAGE FlexibleContexts #-}
89{-# LANGUAGE FlexibleInstances #-}
910{-# LANGUAGE GADTs #-}
@@ -59,7 +60,6 @@ import Control.Monad.Primitive
5960import Control.Monad.Reader
6061import Control.Monad.Ref
6162import Control.Monad.State.Strict
62−import Data.Default
6363import Data.Dependent.Map (DMap)
6464import Data.Dependent.Sum
6565import Data.FastMutableIntMap (PatchIntMap (..))
@@ -122,10 +122,10 @@ import Data.Functor.Contravariant (phantom)
122122#ifndef ghcjs_HOST_OS
123123import GHCJS.DOM.Types (MonadJSM (..))
124124
125−instance MonadJSM m => MonadJSM (HydrationDomBuilderT t m) where
125+instance MonadJSM m => MonadJSM (HydrationRunnerT t m) where
126126 liftJSM' = lift . liftJSM'
127127
128−instance MonadJSM m => MonadJSM (HydrationRunnerT t m) where
128+instance MonadJSM m => MonadJSM (HydrationDomBuilderT t m) where
129129 liftJSM' = lift . liftJSM'
130130
131131instance MonadJSM m => MonadJSM (DomRenderHookT t m) where
@@ -366,8 +366,8 @@ type SupportsHydrationDomBuilder t m = (Reflex t, MonadJSM m, MonadHold t m, Mon
366366wrap
367367 :: forall m er t. (Reflex t, MonadJSM m, MonadReflexCreateTrigger t m, DomRenderHook t m)
368368 => Chan [DSum (EventTriggerRef t) TriggerInvocation]
369− -> RawElement GhcjsDomSpace
370− -> RawElementConfig er t GhcjsDomSpace
369+ -> DOM.Element
370+ -> RawElementConfig er t HydrationDomSpace
371371 -> m (DMap EventName (EventFilterTriggerRef t er))
372372wrap events e cfg = do
373373 forM_ (_rawElementConfig_modifyAttributes cfg) $ \modifyAttrs -> requestDomAction_ $ ffor modifyAttrs $ imapM_ $ \(AttributeName mAttrNamespace n) mv -> case mAttrNamespace of
@@ -390,7 +390,7 @@ wrap events e cfg = do
390390
391391triggerBody
392392 :: forall er t x. DOM.JSContextRef
393− -> ElementConfig er t GhcjsDomSpace
393+ -> ElementConfig er t HydrationDomSpace
394394 -> Chan [DSum (EventTriggerRef t) TriggerInvocation]
395395 -> DMap EventName (EventFilterTriggerRef t er)
396396 -> DOM.Element
@@ -421,9 +421,9 @@ triggerBody ctx cfg events eventTriggerRefs e (WrapArg en) t = case DMap.lookup
421421makeElement
422422 :: forall er t m a. (MonadJSM m, MonadHold t m, MonadFix m, MonadReflexCreateTrigger t m, Adjustable t m, Ref m ~ IORef, PerformEvent t m, MonadJSM (Performable m), MonadRef m)
423423 => Text
424− -> ElementConfig er t GhcjsDomSpace
424+ -> ElementConfig er t HydrationDomSpace
425425 -> HydrationDomBuilderT t m a
426− -> HydrationDomBuilderT t m ((Element er GhcjsDomSpace t, a), IORef DOM.Element)
426+ -> HydrationDomBuilderT t m ((Element er HydrationDomSpace t, a), IORef DOM.Element)
427427makeElement elementTag cfg child = do
428428 doc <- askDocument
429429 ctx <- askJSM
@@ -452,7 +452,7 @@ makeElement elementTag cfg child = do
452452 eventTriggerRefs <- wrap events e $ extractRawElementConfig cfg
453453 es <- newFanEventWithTrigger $ triggerBody ctx cfg events eventTriggerRefs e
454454 e' <- liftIO $ newIORef e
455− return ((Element es e, result), e')
455+ return ((Element es (), result), e')
456456 HydrationMode_Hydrating -> do
457457 -- Schedule everything for after postBuild, except for getting the result itself
458458 parent <- liftIO $ newIORef $ error "Parent not yet initialized"
@@ -620,16 +620,41 @@ instance SupportsHydrationDomBuilder t m => NotReady t (HydrationDomBuilderT t m
620620 unreadyChildren <- askUnreadyChildren
621621 liftIO $ modifyIORef' unreadyChildren succ
622622
623+data HydrationDomSpace
624+
625+instance DomSpace HydrationDomSpace where
626+ type EventSpec HydrationDomSpace = GhcjsEventSpec
627+ type RawDocument HydrationDomSpace = DOM.Document
628+ type RawTextNode HydrationDomSpace = ()
629+ type RawCommentNode HydrationDomSpace = ()
630+ type RawElement HydrationDomSpace = ()
631+ type RawInputElement HydrationDomSpace = ()
632+ type RawTextAreaElement HydrationDomSpace = ()
633+ type RawSelectElement HydrationDomSpace = ()
634+ addEventSpecFlags _ en f es = es
635+ { _ghcjsEventSpec_filters =
636+ let f' = Just . GhcjsEventFilter . \case
637+ Nothing -> \evt -> do
638+ mEventResult <- unGhcjsEventHandler (_ghcjsEventSpec_handler es) (en, evt)
639+ return (f mEventResult, return mEventResult)
640+ Just (GhcjsEventFilter oldFilter) -> \evt -> do
641+ (oldFlags, oldContinuation) <- oldFilter evt
642+ mEventResult <- oldContinuation
643+ let newFlags = oldFlags <> f mEventResult
644+ return (newFlags, return mEventResult)
645+ in DMap.alter f' en $ _ghcjsEventSpec_filters es
646+ }
647+
623648instance (SupportsHydrationDomBuilder t m) => DomBuilder t (HydrationDomBuilderT t m) where
624− type DomBuilderSpace (HydrationDomBuilderT t m) = GhcjsDomSpace
649+ type DomBuilderSpace (HydrationDomBuilderT t m) = HydrationDomSpace
625650 {-# INLINABLE textNode #-}
626651 textNode (TextNodeConfig initialContents mSetContents) = do
627652 t <- textNodeInternal initialContents mSetContents
628− return $ TextNode t
653+ return $ TextNode ()
629654 {-# INLINABLE commentNode #-}
630655 commentNode (CommentNodeConfig initialContents mSetContents) = do
631656 c <- commentNodeInternal initialContents mSetContents
632− return $ CommentNode c
657+ return $ CommentNode ()
633658 {-# INLINABLE element #-}
634659 element elementTag cfg child = do
635660 fst <$> makeElement elementTag cfg child
@@ -833,19 +858,21 @@ instance (SupportsHydrationDomBuilder t m) => DomBuilder t (HydrationDomBuilderT
833858 , _selectElement_raw = undefined -- TODO domSelectElement
834859 }
835860
836− placeRawElement e = getHydrationMode >>= \case
837− HydrationMode_Immediate -> append $ toNode e
838− HydrationMode_Hydrating -> addHydrationStep $ insertAfterPreviousNode e
839− wrapRawElement e rawCfg = do
840− ctx <- askJSM
841− events <- askEvents
842− let cfg = (def :: ElementConfig EventResult t GhcjsDomSpace)
843− { _elementConfig_modifyAttributes = _rawElementConfig_modifyAttributes rawCfg
844− , _elementConfig_eventSpec = _rawElementConfig_eventSpec rawCfg
845− }
846− eventTriggerRefs <- wrap events e rawCfg
847− es <- newFanEventWithTrigger $ triggerBody ctx cfg events eventTriggerRefs e
848− return $ Element es e
861+ placeRawElement () = pure () -- TODO
862+-- placeRawElement e = getHydrationMode >>= \case
863+-- HydrationMode_Immediate -> append $ toNode e
864+-- HydrationMode_Hydrating -> addHydrationStep $ insertAfterPreviousNode e
865+ wrapRawElement () _cfg = pure $ Element (EventSelector $ const never) () -- TODO
866+-- wrapRawElement e rawCfg = do
867+-- ctx <- askJSM
868+-- events <- askEvents
869+-- let cfg = (def :: ElementConfig EventResult t HydrationDomSpace)
870+-- { _elementConfig_modifyAttributes = _rawElementConfig_modifyAttributes rawCfg
871+-- , _elementConfig_eventSpec = _rawElementConfig_eventSpec rawCfg
872+-- }
873+-- eventTriggerRefs <- wrap events e rawCfg
874+-- es <- newFanEventWithTrigger $ triggerBody ctx cfg events eventTriggerRefs e
875+-- return $ Element es e
849876
850877data FragmentState
851878 = FragmentState_Unmounted
reflex-dom-core/src/Reflex/Dom/Builder/Immediate.hs−1
@@ -394,7 +394,6 @@ instance DomSpace GhcjsDomSpace where
394394 type RawTextNode GhcjsDomSpace = DOM.Text
395395 type RawCommentNode GhcjsDomSpace = DOM.Comment
396396 type RawElement GhcjsDomSpace = DOM.Element
397− type RawFile GhcjsDomSpace = DOM.File
398397 type RawInputElement GhcjsDomSpace = DOM.HTMLInputElement
399398 type RawTextAreaElement GhcjsDomSpace = DOM.HTMLTextAreaElement
400399 type RawSelectElement GhcjsDomSpace = DOM.HTMLSelectElement
reflex-dom-core/src/Reflex/Dom/Builder/Static.hs+2−1
@@ -56,6 +56,8 @@ import Reflex.PostBuild.Class
5656import Reflex.TriggerEvent.Class
5757import System.Random (randomRIO)
5858
59+import qualified GHCJS.DOM.Types as DOM
60+
5961data StaticDomBuilderEnv t = StaticDomBuilderEnv
6062 { _staticDomBuilderEnv_shouldEscape :: Bool
6163 , _staticDomBuilderEnv_selectValue :: Maybe (Behavior t Text)
@@ -152,7 +154,6 @@ instance DomSpace StaticDomSpace where
152154 type RawTextNode StaticDomSpace = ()
153155 type RawCommentNode StaticDomSpace = ()
154156 type RawElement StaticDomSpace = ()
155− type RawFile StaticDomSpace = ()
156157 type RawInputElement StaticDomSpace = ()
157158 type RawTextAreaElement StaticDomSpace = ()
158159 type RawSelectElement StaticDomSpace = ()
reflex-dom-core/src/Reflex/Dom/Prerender.hs+132−85
@@ -9,20 +9,27 @@
99{-# LANGUAGE MultiParamTypeClasses #-}
1010{-# LANGUAGE Rank2Types #-}
1111{-# LANGUAGE ScopedTypeVariables #-}
12+{-# LANGUAGE TypeApplications #-}
1213{-# LANGUAGE TypeFamilies #-}
1314{-# LANGUAGE TypeSynonymInstances #-}
1415{-# LANGUAGE UndecidableInstances #-}
16+
17+-- | Render the first widget on the server, and the second on the client.
1518module Reflex.Dom.Prerender
1619 ( Prerender (..)
1720 , prerender
21+ , prerender_
1822 , PrerenderClientConstraint
1923 ) where
2024
2125import Control.Lens ((&), (.~))
26+import Control.Monad.Primitive (PrimMonad)
2227import Control.Monad.Reader
23−import Data.Constraint
28+import Control.Monad.Ref (MonadRef(..))
29+import Control.Monad.State.Strict
2430import Data.Default
25−import Data.IORef (modifyIORef', readIORef, newIORef, writeIORef)
31+import Data.Foldable (traverse_)
32+import Data.IORef (IORef, modifyIORef', readIORef, newIORef)
2633import Data.String (IsString)
2734import qualified GHCJS.DOM.Element as Element
2835import qualified GHCJS.DOM.Types as DOM
@@ -33,67 +40,137 @@ import GHCJS.DOM.Types (MonadJSM)
3340import Reflex hiding (askEvents)
3441import Reflex.Dom.Builder.Class
3542import Reflex.Dom.Builder.InputDisabled
36−import Reflex.Dom.Builder.Immediate (GhcjsDomSpace, ImmediateDomBuilderT, SupportsImmediateDomBuilder, insertBefore, deleteBetweenExclusive)
43+import Reflex.Dom.Builder.Immediate (ImmediateDomBuilderT, SupportsImmediateDomBuilder, insertBefore, deleteBetweenExclusive, runImmediateDomBuilderT, ImmediateDomBuilderEnv(..), GhcjsDomSpace)
3744import Reflex.Dom.Builder.Hydration
3845import Reflex.Dom.Builder.Static
3946import Reflex.Host.Class
4047
41−type PrerenderClientConstraint' js m =
42− ( HasJS js m
43− , HasJS js (Performable m)
44− , MonadJSM m
45− , MonadJSM (Performable m)
46− , HasJSContext m
47− , HasJSContext (Performable m)
48− , MonadFix m
49− , MonadFix (Performable m)
48+type PrerenderClientConstraint t m =
49+ ( DomBuilder t m
50+ , DomBuilderSpace m ~ GhcjsDomSpace
51+ , HasDocument m
52+ , TriggerEvent t m
53+ , Prerender t m
54+ , PrerenderBaseConstraints t m
5055 )
5156
52−type PrerenderClientConstraint js m =
53− ( PrerenderClientConstraint' js m
54− , DomBuilderSpace m ~ GhcjsDomSpace
57+type PrerenderBaseConstraints t m =
58+ ( HasJSContext (Performable m)
59+ , HasJSContext m
60+ , MonadFix m
61+ , MonadHold t m
62+ , MonadJSM (Performable m)
63+ , MonadJSM m
64+ , MonadRef (Performable m)
65+ , MonadRef m
66+ , MonadReflexCreateTrigger t m
67+ , MonadSample t (Performable m)
68+ , PerformEvent t m
69+ , PostBuild t m
70+ , PrimMonad m
71+ , Ref (Performable m) ~ IORef
72+ , Ref m ~ IORef
5573 )
5674
57−class Prerender js m | m -> js where
58− prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m))
59− prerenderWrapper :: m (m ())
60− default prerenderWrapper :: (MonadTrans t, Monad n, m ~ t n, Prerender js n) => m (m ())
61− prerenderWrapper = lift $ lift <$> prerenderWrapper
62−
63−-- | Draw one widget when prerendering (e.g. server-side) and another when the
64−-- widget is fully instantiated. In a given execution of this function, there
65−-- will be exactly one invocation of exactly one of the arguments.
66−prerender :: forall js m a. (Prerender js m, Monad m) => m a -> (PrerenderClientConstraint js m => m a) -> m a
67−prerender server client = do
68− finalize <- prerenderWrapper
69− a <- case prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)) of
70− Nothing -> server
71− Just Dict -> client
72− finalize
73− pure a
74−
75−instance (PrerenderClientConstraint' js m, ReflexHost t) => Prerender js (ImmediateDomBuilderT t m) where
76− prerenderClientDict = Just Dict
77− prerenderWrapper = pure (pure ())
78−
79−instance (PrerenderClientConstraint' js m, SupportsImmediateDomBuilder t m, ReflexHost t, PerformEvent t m) => Prerender js (HydrationDomBuilderT t m) where
80− prerenderClientDict = Just Dict
81− prerenderWrapper = getHydrationMode >>= \case
82− HydrationMode_Immediate -> pure (pure ())
83− HydrationMode_Hydrating -> do
84− parent <- HydrationDomBuilderT $ asks _hydrationDomBuilderEnv_parent
85− hydrationMode <- HydrationDomBuilderT $ asks _hydrationDomBuilderEnv_hydrationMode
86− df <- Document.createDocumentFragment =<< askDocument
87− initialParent <- liftIO $ readIORef parent
88− liftIO $ writeIORef parent $ DOM.toNode df
89− liftIO $ writeIORef hydrationMode HydrationMode_Immediate
90− pure $ do
91− liftIO $ writeIORef parent initialParent
92− liftIO $ writeIORef hydrationMode HydrationMode_Hydrating
93− addHydrationStep $ do
94− -- Delete up to the end marker
95− after <- deleteToPrerenderEnd
96− insertBefore df after
75+-- | Render the first widget on the server, and the second on the client. The
76+-- hydration builder will run *both* widgets, updating the result dynamic at
77+-- switchover time.
78+prerender
79+ :: (Functor m, Prerender t m)
80+ => m a -> ((PrerenderClientConstraint t (Client m)) => Client m a) -> m (Dynamic t a)
81+prerender server client = snd <$> prerenderImpl ((,) () <$> server) client
82+
83+-- | Render the first widget on the server, and the second on the client. The
84+-- hydration builder will run *both* widgets.
85+prerender_
86+ :: (Functor m, Reflex t, Prerender t m)
87+ => m () -> ((PrerenderClientConstraint t (Client m)) => Client m ()) -> m ()
88+prerender_ server client = void $ prerenderImpl ((,) () <$> server) client
89+
90+class Prerender t m | m -> t where
91+ -- | Monad in which the client widget is built
92+ type Client m :: * -> *
93+ -- | This function should be considered internal: it should only be used where
94+ -- the resultant 'Maybe' isn't used to change what is built in the DOM, or
95+ -- hydration will fail.
96+ prerenderImpl :: m (a, b) -> ((PrerenderClientConstraint t (Client m)) => Client m b) -> m (Maybe a, Dynamic t b)
97+
98+instance (Adjustable t m, PrerenderBaseConstraints t m) => Prerender t (ImmediateDomBuilderT t m) where
99+ type Client (ImmediateDomBuilderT t m) = ImmediateDomBuilderT t m
100+ prerenderImpl _ client = (,) Nothing . pure <$> client
101+
102+instance (Adjustable t m, PrerenderBaseConstraints t m, ReflexHost t) => Prerender t (HydrationDomBuilderT t m) where
103+ -- | PostBuildT is needed here because we delay running the immediate builder
104+ -- until after switchover, at which point the postBuild of @m@ has already fired
105+ type Client (HydrationDomBuilderT t m) = PostBuildT t (ImmediateDomBuilderT t m)
106+ -- | Runs the server widget up until switchover, then replaces it with the
107+ -- client widget.
108+ prerenderImpl server client = do
109+ env <- HydrationDomBuilderT ask
110+ events <- askEvents
111+ doc <- askDocument
112+ df <- Document.createDocumentFragment doc
113+ unreadyChildren <- HydrationDomBuilderT $ asks _hydrationDomBuilderEnv_unreadyChildren
114+ let immediateEnv = ImmediateDomBuilderEnv
115+ { _immediateDomBuilderEnv_document = doc
116+ , _immediateDomBuilderEnv_parent = DOM.toNode df
117+ , _immediateDomBuilderEnv_unreadyChildren = unreadyChildren
118+ , _immediateDomBuilderEnv_commitAction = pure ()
119+ }
120+ (b', trigger) <- newTriggerEvent
121+ addHydrationStep $ do
122+ liftIO . trigger <=< lift $ runImmediateDomBuilderT (runPostBuildT client $ void b') immediateEnv events
123+ insertBefore df =<< deleteToPrerenderEnd
124+ ((a, b0), _) <- lift $ runHydrationDomBuilderT server env events
125+ (,) (Just a) <$> holdDyn b0 b'
126+
127+instance SupportsStaticDomBuilder t m => Prerender t (StaticDomBuilderT t m) where
128+ type Client (StaticDomBuilderT t m) = ImmediateDomBuilderT t m
129+ prerenderImpl server _ = do
130+ _ <- element "script" (def & initialAttributes .~ Map.singleton "type" startMarker) $ pure ()
131+ (a, b) <- server
132+ _ <- element "script" (def & initialAttributes .~ Map.singleton "type" endMarker) $ pure ()
133+ pure (Just a, pure b)
134+
135+instance (Prerender t m, Monad m) => Prerender t (ReaderT r m) where
136+ type Client (ReaderT r m) = Client m
137+ prerenderImpl server client = do
138+ r <- ask
139+ lift $ prerenderImpl (runReaderT server r) client
140+
141+instance (Prerender t m, Monad m, Functor (Client m)) => Prerender t (StateT s m) where
142+ type Client (StateT s m) = Client m
143+ prerenderImpl server client = do
144+ s <- get
145+ (ma, evt) <- lift $ prerenderImpl
146+ (do ((a, b), s') <- runStateT server s; pure ((a, s'), b))
147+ client
148+ traverse_ (put . snd) ma
149+ pure (fst <$> ma, evt)
150+
151+instance (Prerender t m, Monad m, Functor (Client m)) => Prerender t (DynamicWriterT t w m) where
152+ type Client (DynamicWriterT t w m) = Client m
153+ prerenderImpl (DynamicWriterT server) client = DynamicWriterT $ prerenderImpl server client
154+
155+instance (Prerender t m, Monad m, Functor (Client m)) => Prerender t (EventWriterT t w m) where
156+ type Client (EventWriterT t w m) = Client m
157+ prerenderImpl (EventWriterT server) client = EventWriterT $ prerenderImpl server client
158+
159+instance (Prerender t m, Monad m, Functor (Client m)) => Prerender t (RequesterT t request response m) where
160+ type Client (RequesterT t request response m) = Client m
161+ prerenderImpl (RequesterT server) client = RequesterT $ prerenderImpl server client
162+
163+instance (Prerender t m, Monad m, Functor (Client m)) => Prerender t (QueryT t q m) where
164+ type Client (QueryT t q m) = Client m
165+ prerenderImpl (QueryT server) client = QueryT $ prerenderImpl server client
166+
167+instance (Prerender t m, Monad m) => Prerender t (InputDisabledT m) where
168+ type Client (InputDisabledT m) = Client m
169+ prerenderImpl (InputDisabledT server) client = InputDisabledT $ prerenderImpl server client
170+
171+instance (Prerender t m, Monad m) => Prerender t (PostBuildT t m) where
172+ type Client (PostBuildT t m) = Client m
173+ prerenderImpl (PostBuildT server) client = PostBuildT $ prerenderImpl server client
97174
98175startMarker, endMarker :: IsString s => s
99176startMarker = "prerender/start"
@@ -125,33 +202,3 @@ deleteToPrerenderEnd = do
125202 deleteBetweenExclusive startNode endNode
126203 setPreviousNode $ Just $ DOM.toNode endNode -- TODO probably not necessary
127204 pure endNode
128−
129−data NoJavascript -- This type should never have a HasJS instance
130−
131−instance (js ~ NoJavascript, SupportsStaticDomBuilder t m) => Prerender js (StaticDomBuilderT t m) where
132− prerenderClientDict = Nothing
133− prerenderWrapper = do
134− _ <- element "script" (def & initialAttributes .~ Map.singleton "type" startMarker) $ pure ()
135− pure $ void $ element "script" (def & initialAttributes .~ Map.singleton "type" endMarker) $ pure ()
136−
137−instance (Prerender js m, Monad m, ReflexHost t) => Prerender js (PostBuildT t m) where
138− prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
139−
140−instance (Prerender js m, Monad m) => Prerender js (DynamicWriterT t w m) where
141− prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
142−
143−instance (Prerender js m, Monad m) => Prerender js (EventWriterT t w m) where
144− prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
145−
146−instance (Prerender js m, Monad m) => Prerender js (ReaderT w m) where
147− prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
148−
149−instance (Prerender js m, Monad m) => Prerender js (RequesterT t request response m) where
150− prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
151−
152−instance (Prerender js m, Monad m) => Prerender js (QueryT t q m) where
153− prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
154−
155−instance (Prerender js m, Monad m) => Prerender js (InputDisabledT m) where
156− prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
157−