@@ -107,6 +107,9 @@ module Reflex.Dom.Builder.Immediate
107 , WindowConfig (..)
107 , WindowConfig (..)
108 , Window (..)
108 , Window (..)
109 , wrapWindow
109 , wrapWindow
110+ -- * Attributes for controlling hydration
111+ , hydratableAttribute
112+ , skipHydrationAttribute
110 -- * Internal
113 -- * Internal
111 , traverseDMapWithKeyWithAdjust'
114 , traverseDMapWithKeyWithAdjust'
112 , hoistTraverseWithKeyWithAdjust
115 , hoistTraverseWithKeyWithAdjust
@@ -137,6 +140,7 @@ import Data.IntMap.Strict (IntMap)
137import Data.Maybe
140import Data.Maybe
138import Data.Monoid ((<>))
141import Data.Monoid ((<>))
139import Data.Some (Some(..))
142import Data.Some (Some(..))
143+import Data.String (IsString)
140import Data.Text (Text)
144import Data.Text (Text)
141import Foreign.JavaScript.Internal.Utils
145import Foreign.JavaScript.Internal.Utils
142import Foreign.JavaScript.TH
146import Foreign.JavaScript.TH
@@ -743,6 +747,14 @@ elementInternal elementTag cfg child = getHydrationMode >>= \case
743 -> HydrationDomBuilderT HydrationDomSpace DomTimeline HydrationM (Element er HydrationDomSpace DomTimeline, a)
747 -> HydrationDomBuilderT HydrationDomSpace DomTimeline HydrationM (Element er HydrationDomSpace DomTimeline, a)
750+-- | An attribute which causes hydration to skip over an element completely.
751+skipHydrationAttribute :: IsString s => s
752+skipHydrationAttribute = "data-hydration-skip"
754+-- | An attribute which signals that an element should be hydrated.
755+hydratableAttribute :: IsString s => s
756+hydratableAttribute = "data-ssr"
746{-# INLINE hydrateElement #-}
758{-# INLINE hydrateElement #-}
747hydrateElement
759hydrateElement
748 :: forall er t m a. (MonadJSM m, Reflex t, MonadReflexCreateTrigger t m, MonadFix m)
760 :: forall er t m a. (MonadJSM m, Reflex t, MonadReflexCreateTrigger t m, MonadFix m)
@@ -764,13 +776,15 @@ hydrateElement elementTag cfg child = do
765 result <- HydrationDomBuilderT $ lift $ runReaderT (unHydrationDomBuilderT child) env'
777 result <- HydrationDomBuilderT $ lift $ runReaderT (unHydrationDomBuilderT child) env'
766 wrapResult <- liftIO newEmptyMVar
778 wrapResult <- liftIO newEmptyMVar
767− let skipAttr = "data-hydration-skip" :: DOM.JSString
779+ let -- Determine if we should skip an element. We currently skip elements for
768− ssrAttr = "data-ssr" :: DOM.JSString
780+ -- two reasons:
781+ -- 1) it was not produced by a static builder which supports hydration
782+ -- 2) it is explicitly marked to be skipped
769 shouldSkip :: DOM.Element -> HydrationRunnerT t m Bool
783 shouldSkip :: DOM.Element -> HydrationRunnerT t m Bool
770 shouldSkip e = do
784 shouldSkip e = do
771− skip <- hasAttribute e skipAttr
785+ skip <- hasAttribute e (skipHydrationAttribute :: DOM.JSString)
772− ssr <- hasAttribute e ssrAttr
786+ hydratable <- hasAttribute e (hydratableAttribute :: DOM.JSString)
773− pure $ skip || not ssr
787+ pure $ skip || not hydratable
774 childDom <- liftIO $ readIORef childDelayedRef
788 childDom <- liftIO $ readIORef childDelayedRef
775 let rawCfg = extractRawElementConfig cfg
789 let rawCfg = extractRawElementConfig cfg
776 doc <- askDocument
790 doc <- askDocument
@@ -786,7 +800,7 @@ hydrateElement elementTag cfg child = do
786 Just node -> DOM.castTo DOM.Element node >>= \case
800 Just node -> DOM.castTo DOM.Element node >>= \case
787 Nothing -> go (Just node) -- this node is not an element, skip
801 Nothing -> go (Just node) -- this node is not an element, skip
788 Just e -> shouldSkip e >>= \case
802 Just e -> shouldSkip e >>= \case
789− True -> go (Just node) -- this element is explicitly marked for being skipped by hydration
803+ True -> go (Just node) -- this element should be skipped by hydration
790 False -> do
804 False -> do
791 t <- Element.getTagName e
805 t <- Element.getTagName e
792 -- TODO: check attributes?
806 -- TODO: check attributes?