on develop help sign in
Merge pull request #364 from reflex-frp/ts-hydration-attr
4e4d49aElliot Cameron
reflex-dom-core/ChangeLog.md+4
@@ -19,6 +19,10 @@
19
19
20* Fix bug in hydration when dealing with unexpected HTML ([#361](https://github.com/reflex-frp/reflex-dom/pull/361)).
20* Fix bug in hydration when dealing with unexpected HTML ([#361](https://github.com/reflex-frp/reflex-dom/pull/361)).
21
21
22+* Export attributes used for controlling hydration at the element level
23+ * "data-ssr" is now available as `Reflex.Dom.Builder.Immediate.hydratableAttribute`
24+ * "data-hydration-skip" is now available as `Reflex.Dom.Builder.Immediate.skipHydrationAttribute`
25+
22## 0.5.3
26## 0.5.3
23
27
24* Deprecate a number of old inflexible widget helpers in `Reflex.Dom.Widget.Basic`:
28* Deprecate a number of old inflexible widget helpers in `Reflex.Dom.Widget.Basic`:
reflex-dom-core/src/Reflex/Dom/Builder/Hydratable.hs+4−4
@@ -21,10 +21,10 @@ import GHCJS.DOM.Types (MonadJSM (..))
21#endif
21#endif
22import Reflex
22import Reflex
23import Reflex.Dom.Builder.Class
23import Reflex.Dom.Builder.Class
24−import Reflex.Dom.Builder.Immediate (HasDocument (..))
24+import Reflex.Dom.Builder.Immediate (HasDocument (..), hydratableAttribute)
25import Reflex.Host.Class
25import Reflex.Host.Class
26
26
27−-- | A DomBuilder transformer that adds "data-ssr" to all elements such that the
27+-- | A DomBuilder transformer that adds an attribute to all elements such that the
28-- hydration builder knows which bits of DOM were added by us, and which were
28-- hydration builder knows which bits of DOM were added by us, and which were
29-- added by external scripts.
29-- added by external scripts.
30newtype HydratableT m a = HydratableT { runHydratableT :: m a } deriving (Functor, Applicative, Monad, MonadAtomicRef, MonadFix, MonadIO)
30newtype HydratableT m a = HydratableT { runHydratableT :: m a } deriving (Functor, Applicative, Monad, MonadAtomicRef, MonadFix, MonadIO)
@@ -62,8 +62,8 @@ instance PrimMonad m => PrimMonad (HydratableT m) where
62
62
63makeHydratable :: Reflex t => ElementConfig er t m -> ElementConfig er t m
63makeHydratable :: Reflex t => ElementConfig er t m -> ElementConfig er t m
64makeHydratable cfg = cfg
64makeHydratable cfg = cfg
65− { _elementConfig_initialAttributes = Map.insert "data-ssr" "" $ _elementConfig_initialAttributes cfg
65+ { _elementConfig_initialAttributes = Map.insert hydratableAttribute "" $ _elementConfig_initialAttributes cfg
66− , _elementConfig_modifyAttributes = fmap (Map.delete "data-ssr") <$> _elementConfig_modifyAttributes cfg
66+ , _elementConfig_modifyAttributes = fmap (Map.delete hydratableAttribute) <$> _elementConfig_modifyAttributes cfg
67 }
67 }
68
68
69instance PostBuild t m => PostBuild t (HydratableT m) where
69instance PostBuild t m => PostBuild t (HydratableT m) where
reflex-dom-core/src/Reflex/Dom/Builder/Immediate.hs+20−6
@@ -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)
744 #-}
748 #-}
745
749
750+-- | An attribute which causes hydration to skip over an element completely.
751+skipHydrationAttribute :: IsString s => s
752+skipHydrationAttribute = "data-hydration-skip"
753+
754+-- | An attribute which signals that an element should be hydrated.
755+hydratableAttribute :: IsString s => s
756+hydratableAttribute = "data-ssr"
757+
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
764 }
776 }
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?