on develop help sign in
Merge branch 'develop' into clarify-view-docs
commiteabf7600dde23be99a724676fac5523faf8b658d authorJohn Ericson <John.Ericson@Obsidian.Systems> dateTue 10 Dec 2019, 14:12 (7 years ago) parentb1a854dc89302c
23 files changed+325−274
CONTRIBUTING.md+5 default.nix+51−5 dep/reflex-platform/default.nix+7 dep/reflex-platform/github.json+7 hydra.json−29 jobsets.nix−70 reflex-dom-core/ChangeLog.md+10−1 reflex-dom-core/default.nix−63 reflex-dom-core/reflex-dom-core.cabal+19−5 reflex-dom-core/src/Reflex/Dom/Builder/Hydratable.hs+116 reflex-dom-core/src/Reflex/Dom/Builder/Immediate.hs+12−5 reflex-dom-core/src/Reflex/Dom/Builder/InputDisabled.hs+6 reflex-dom-core/src/Reflex/Dom/Builder/Static.hs+1−1 reflex-dom-core/src/Reflex/Dom/Core.hs+1 reflex-dom-core/src/Reflex/Dom/Prerender.hs+9−4 reflex-dom-core/src/Reflex/Dom/Widget/Basic.hs+5−4 reflex-dom-core/src/Reflex/Dom/Widget/Resize.hs+4 reflex-dom-core/test/hlint.hs+2 reflex-dom-core/test/hydration.hs+34−23 reflex-dom/default.nix−38 reflex-dom/reflex-dom.cabal+4−9 reflex-platform.nix−8 release.nix+32−9
CONTRIBUTING.md+5
@@ -5,6 +5,7 @@ Contributions and issue reports are encouraged and appreciated!
55- [Opening Issues](#opening-issues)
66- [Submitting Changes](#submitting-changes)
77 - [Guidelines for Commit Messages](#guidelines-for-commit-messages)
8+ - [Guidelines for Pull Requests](#guidelines-for-pull-requests)
89 - [Code Quality](#code-quality)
910 - [Documentation](#documentation)
1011
@@ -30,6 +31,10 @@ One way to think about it is that your commit message should be able to complete
3031#### Body
3132For breaking changes, new features, refactors, or other major changes, the body of the commit message should describe the motivation behind the change in greater detail and may include references to the issue tracker. The body shouldn't repeat code/comments from the diff.
3233
34+### Guidelines for Pull Requests
35+
36+Wherever possible, pull requests should add a single feature or fix a single bug. Pull requests should not bundle several unrelated changes.
37+
3338### Code Quality
3439
3540#### Warnings
default.nix+51−5
@@ -1,7 +1,53 @@
1−haskellPackages: nixpkgs: {
2− reflex-dom = haskellPackages.callPackage ./reflex-dom {};
3− reflex-dom-core = haskellPackages.callPackage ./reflex-dom-core {
4− inherit (nixpkgs) iproute chromium;
5− };
1+haskellPackages: let
2+ pkgs = haskellPackages.callPackage ({ pkgs }: pkgs) {};
3+ inherit (pkgs) stdenv;
4+ haskellLib = pkgs.haskell.lib;
5+in {
6+ reflex-dom-core = let
7+ inherit (haskellPackages) ghc;
8+ noGcTest = stdenv.hostPlatform.system != "x86_64-linux"
9+ || stdenv.hostPlatform != stdenv.buildPlatform
10+ || (ghc.isGhcjs or false);
11+ in haskellLib.overrideCabal
12+ (haskellPackages.callCabal2nix "reflex-dom-core" ./reflex-dom-core { })
13+ (drv: {
14+ #TODO: Get hlint working for cross-compilation
15+ doCheck = stdenv.hostPlatform == stdenv.buildPlatform && !(ghc.isGhcjs or false);
16+
17+ # The headless browser run as part of the tests will exit without this
18+ preBuild = ''
19+ export HOME="$PWD"
20+ '';
21+
22+ # Show some output while running tests, so we might notice what's wrong
23+ testTarget = "--show-details=streaming";
24+
25+ testHaskellDepends = with haskellPackages; (drv.testHaskellDepends or []) ++ stdenv.lib.optionals (!noGcTest) [
26+ temporary
27+ jsaddle-warp
28+ process
29+ chrome-test-utils
30+ ];
31+
32+ testSystemDepends = with pkgs; (drv.testSystemDepends or []) ++ [
33+ selenium-server-standalone which
34+ ] ++ stdenv.lib.optionals (!noGcTest) [
35+ chromium
36+ pkgs.iproute
37+ ];
38+ } // stdenv.lib.optionalAttrs (!noGcTest) {
39+ # The headless browser run as part of gc tests would hang/crash without this
40+ preCheck = ''
41+ export FONTCONFIG_PATH=${pkgs.fontconfig.out}/etc/fonts
42+ '';
43+ });
44+ reflex-dom = haskellLib.overrideCabal
45+ (haskellPackages.callCabal2nix "reflex-dom" ./reflex-dom { })
46+ (drv: {
47+ # Hack until https://github.com/NixOS/cabal2nix/pull/432 lands
48+ libraryHaskellDepends = (drv.libraryHaskellDepends or []) ++ stdenv.lib.optionals (with stdenv.hostPlatform; isAndroid && is32bit) [
49+ haskellPackages.android-activity
50+ ];
51+ });
652 chrome-test-utils = haskellPackages.callCabal2nix "chrome-test-utils" ./chrome-test-utils {};
753}
dep/reflex-platform/default.nixnew file+7
@@ -0,0 +1,7 @@
1+# DO NOT HAND-EDIT THIS FILE
2+import ((import <nixpkgs> {}).fetchFromGitHub (
3+ let json = builtins.fromJSON (builtins.readFile ./github.json);
4+ in { inherit (json) owner repo rev sha256;
5+ private = json.private or false;
6+ }
7+))
dep/reflex-platform/github.jsonnew file+7
@@ -0,0 +1,7 @@
1+{
2+ "owner": "reflex-frp",
3+ "repo": "reflex-platform",
4+ "branch": "develop",
5+ "rev": "338fc907e37d70e6469c529456f33221fb05ca1f",
6+ "sha256": "08gfhpp0pkvvi1wnlpcn6wmpzdjvy5z7dy1h66gp2w8b5cx8hx5h"
7+}
hydra.jsondeleted−29
@@ -1,29 +0,0 @@
1−{
2− "enabled": 1,
3− "hidden": true,
4− "description": "Jobsets",
5− "nixexprinput": "src",
6− "nixexprpath": "jobsets.nix",
7− "checkinterval": 300,
8− "schedulingshares": 100,
9− "enableemail": false,
10− "emailoverride": "",
11− "keepnr": 10,
12− "inputs": {
13− "src": {
14− "type": "git",
15− "value": "https://github.com/reflex-frp/reflex-dom.git develop",
16− "emailresponsible": false
17− },
18− "nixpkgs": {
19− "type": "git",
20− "value": "https://github.com/NixOS/nixpkgs-channels nixos-unstable",
21− "emailresponsible": false
22− },
23− "prs": {
24− "type": "githubpulls",
25− "value": "reflex-frp reflex-dom",
26− "emailresponsible": false
27− }
28− }
29−}
jobsets.nixdeleted−70
@@ -1,70 +0,0 @@
1−{ prs }:
2−
3−let
4− pkgs = (import ./reflex-platform.nix {}).nixpkgs;
5− mkFetchGithub = value: {
6− inherit value;
7− type = "git";
8− emailresponsible = false;
9− };
10−in
11−with pkgs.lib;
12−let
13− defaults = jobs: {
14− inherit (jobs) description;
15− enabled = 1;
16− hidden = false;
17− keepnr = 10;
18− schedulingshares = 100;
19− checkinterval = 120;
20− enableemail = false;
21− emailoverride = "";
22− nixexprinput = "reflex-dom";
23− nixexprpath = "release.nix";
24− inputs = jobs.inputs // {
25− nixpkgs = {
26− type = "git";
27− value = "https://github.com/NixOS/nixpkgs-channels nixos-unstable";
28− emailresponsible = false;
29− };
30− config = {
31− type = "nix";
32− value = "{ android_sdk.accept_license = true; }";
33− emailresponsible = false;
34− };
35− };
36− };
37− branchJobset = branch: defaults {
38− description = "reflex-dom-${branch}";
39− inputs = {
40− reflex-dom = {
41− value = "https://github.com/reflex-frp/reflex-dom ${branch}";
42− type = "git";
43− emailresponsible = false;
44− };
45− };
46− };
47− makePr = num: info: {
48− name = "reflex-dom-pr-${num}";
49− value = defaults {
50− description = "#${num}: ${info.title}";
51− inputs = {
52− reflex-dom = {
53− #NOTE: This should really use "pull/${num}/merge"; however, GitHub's
54− #status checks only operate on PR heads. This creates a race
55− #condition, which can currently only be solved by requiring PRs to be
56− #up to date before they're merged. See
57− #https://github.com/isaacs/github/issues/1002
58− value = "https://github.com/reflex-frp/reflex-dom pull/${num}/head";
59− type = "git";
60− emailresponsible = false;
61− };
62− };
63− };
64− };
65− processedPrs = mapAttrs' makePr (builtins.fromJSON (builtins.readFile prs));
66− jobsetsAttrs = processedPrs //
67− genAttrs ["develop"] branchJobset;
68−in {
69− jobsets = pkgs.writeText "spec.json" (builtins.toJSON jobsetsAttrs);
70−}
reflex-dom-core/ChangeLog.md+10−1
@@ -1,13 +1,22 @@
11# Revision history for reflex-dom-core
22
3+## Unreleased
4+
35## 0.5.2
46
57* Update to use new dependent-sum/map packages and drop dependency on `*Tag` classes (e.g., `ShowTag`).
8+* Update version bounds of base, containers, and stm
9+* Update to use the newly split `these`/`semialign` packages. To use the pre-split `these` package, set the `split-these` flag to false.
10+* Reintroduce "data-ssr": elements without this attribute are skipped during
11+ hydration.
12+* Fix an issue in the hydration tests that prevented the test from finding the chromium executable
13+* Relax constraints on `dyn` and `widgetHold` to match the ones in `networkView` and `networkHold` respectively
14+* Fix prerender for RequesterT so that it doesn't accidentally discard a request that is made at the same moment as getPostBuild's Event fires
615
716## 0.5.1
817
918* Added support for marking elements with a "data-skip-hydration" attribute, which will cause hydration to ignore and skip over them.
10−* Removed "data-ssr" attributes from statically rendered output.:q
19+* Removed "data-ssr" attributes from statically rendered output.
1120
1221## 0.5
1322
reflex-dom-core/default.nixdeleted−63
@@ -1,63 +0,0 @@
1−{ mkDerivation, aeson, base, bifunctors, bimap, blaze-builder
2−, bytestring, chrome-test-utils, constraints, constraints-extras, containers
3−, contravariant, data-default, dependent-map, dependent-sum
4−, dependent-sum-template, directory, exception-transformers
5−, exceptions, filepath, ghcjs-dom, hlint, hspec, hspec-webdriver, http-types, HUnit
6−, jsaddle, jsaddle-warp, keycode, lens, lifted-base
7−, monad-control, mtl, network, network-uri, primitive, process
8−, random, ref-tf, reflex, semigroups, silently, stdenv, stm
9−, template-haskell, temporary, text, these, transformers, unix, wai
10−, wai-websockets, warp, webdriver, websockets, zenc
11−, ghc, iproute, chromium, hashable, selenium-server-standalone, which, fontconfig
12−}:
13−let addGcTestDepends = drv: if (stdenv.system != "x86_64-linux" || stdenv.hostPlatform != stdenv.buildPlatform || (ghc.isGhcjs or false)) then drv else drv // {
14− # The headless browser run as part of gc tests would hang/crash without this
15− preCheck = ''
16− export FONTCONFIG_PATH=${fontconfig.out}/etc/fonts
17− '';
18− testHaskellDepends = (drv.testHaskellDepends or []) ++ [
19− temporary
20− jsaddle-warp
21− process
22− chrome-test-utils
23− ];
24− testSystemDepends = (drv.testSystemDepends or []) ++ [ chromium iproute ];
25− };
26−in mkDerivation (addGcTestDepends {
27− pname = "reflex-dom-core";
28− version = "0.5.2";
29− src = ./.;
30− libraryHaskellDepends = [
31− aeson base bifunctors bimap blaze-builder bytestring constraints
32− containers contravariant data-default dependent-map dependent-sum
33− dependent-sum-template directory exception-transformers ghcjs-dom
34− jsaddle keycode lens monad-control mtl network-uri primitive random
35− ref-tf reflex semigroups stm template-haskell text these
36− transformers unix zenc
37− ] ++ (if ghc.isGhcjs or false then [
38− hashable
39− ] else []);
40−
41− #TODO: Get hlint working for cross-compilation
42− doCheck = stdenv.hostPlatform == stdenv.buildPlatform && !(ghc.isGhcjs or false);
43−
44− # The headless browser run as part of the tests will exit without this
45− preBuild = ''
46− export HOME="$PWD"
47− '';
48−
49− # Show some output while running tests, so we might notice what's wrong
50− testTarget = "--show-details=streaming";
51−
52− testSystemDepends = [ selenium-server-standalone which ];
53− testHaskellDepends = [
54− aeson base bytestring constraints constraints-extras containers
55− dependent-map dependent-sum dependent-sum-template directory
56− exceptions filepath ghcjs-dom hlint hspec hspec-webdriver http-types HUnit jsaddle
57− jsaddle-warp lens lifted-base network process random reflex
58− silently temporary text unix wai wai-websockets warp webdriver
59− websockets
60− ];
61− description = "Functional Reactive Web Apps with Reflex";
62− license = stdenv.lib.licenses.bsd3;
63−})
reflex-dom-core/reflex-dom-core.cabal+19−5
@@ -39,17 +39,22 @@ flag profile-reflex
3939 default: False
4040 manual: True
4141
42+flag split-these
43+ description: Use split these/semialign packages
44+ manual: False
45+ default: True
46+
4247library
4348 hs-source-dirs: src
4449 build-depends:
4550 aeson >= 0.8 && < 1.5,
46− base >= 4.7 && < 4.12,
51+ base >= 4.7 && < 4.13,
4752 bifunctors >= 4.2 && < 6,
4853 bimap >= 0.3 && < 0.4,
4954 blaze-builder,
5055 bytestring == 0.10.*,
51− containers == 0.5.*,
52− constraints >= 0.9 && < 0.11,
56+ containers >= 0.6 && < 0.7,
57+ constraints >= 0.9 && < 0.12,
5358 contravariant >= 1.4 && < 1.6,
5459 data-default >= 0.5 && < 0.8,
5560 dependent-map >= 0.3 && < 0.4,
@@ -69,9 +74,8 @@ library
6974 ref-tf == 0.4.*,
7075 reflex >= 0.6.2,
7176 semigroups >= 0.16 && < 0.19,
72− stm == 2.4.*,
77+ stm >= 2.4 && < 2.6,
7378 text == 1.2.*,
74− these >= 0.4 && < 0.8,
7579 transformers >= 0.3 && < 0.6,
7680 network-uri >= 2.6.1 && < 2.7,
7781 zenc == 0.1.*
@@ -86,6 +90,14 @@ library
8690 if !os(windows)
8791 build-depends: unix == 2.7.*
8892
93+ if flag(split-these)
94+ build-depends:
95+ semialign >= 1 && < 1.1,
96+ these >= 1 && < 1.1
97+ else
98+ build-depends:
99+ these >= 0.4 && < 0.9
100+
89101 exposed-modules:
90102 Foreign.JavaScript.TH
91103 Foreign.JavaScript.Orphans
@@ -94,6 +106,7 @@ library
94106 Reflex.Dom.Builder.Class.Events
95107 Reflex.Dom.Builder.Immediate
96108 Reflex.Dom.Builder.InputDisabled
109+ Reflex.Dom.Builder.Hydratable
97110 Reflex.Dom.Builder.Static
98111 Reflex.Dom.Class
99112 Reflex.Dom.Core
@@ -188,6 +201,7 @@ test-suite hydration
188201 , warp
189202 , webdriver
190203 , websockets
204+ , which
191205 hs-source-dirs: test
192206 ghc-options: -rtsopts -with-rtsopts=-T -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans
193207 ghc-prof-options: -fprof-auto -optP-DPROFILING
reflex-dom-core/src/Reflex/Dom/Builder/Hydratable.hsnew file+116
@@ -0,0 +1,116 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE StandaloneDeriving #-}
7+{-# LANGUAGE TypeFamilies #-}
8+{-# LANGUAGE UndecidableInstances #-}
9+module Reflex.Dom.Builder.Hydratable where
10+
11+import Control.Monad.Fix
12+import Control.Monad.Primitive
13+import Control.Monad.Ref
14+import Control.Monad.Trans
15+import Control.Monad.Trans.Control
16+import Data.Coerce
17+import qualified Data.Map as Map
18+import Foreign.JavaScript.TH
19+#ifndef ghcjs_HOST_OS
20+import GHCJS.DOM.Types (MonadJSM (..))
21+#endif
22+import Reflex
23+import Reflex.Dom.Builder.Class
24+import Reflex.Dom.Builder.Immediate (HasDocument (..))
25+import Reflex.Host.Class
26+
27+-- | A DomBuilder transformer that adds "data-ssr" to all elements such that the
28+-- hydration builder knows which bits of DOM were added by us, and which were
29+-- added by external scripts.
30+newtype HydratableT m a = HydratableT { runHydratableT :: m a } deriving (Functor, Applicative, Monad, MonadAtomicRef, MonadFix, MonadIO)
31+
32+#ifndef ghcjs_HOST_OS
33+instance MonadJSM m => MonadJSM (HydratableT m) where
34+ liftJSM' = HydratableT . liftJSM'
35+#endif
36+
37+deriving instance MonadSample t m => MonadSample t (HydratableT m)
38+deriving instance MonadHold t m => MonadHold t (HydratableT m)
39+
40+instance MonadTrans HydratableT where
41+ lift = HydratableT
42+
43+instance MonadTransControl HydratableT where
44+ type StT HydratableT a = a
45+ liftWith f = HydratableT $ f runHydratableT
46+ restoreT = HydratableT
47+
48+instance MonadRef m => MonadRef (HydratableT m) where
49+ type Ref (HydratableT m) = Ref m
50+ newRef = lift . newRef
51+ readRef = lift . readRef
52+ writeRef ref = lift . writeRef ref
53+
54+instance PerformEvent t m => PerformEvent t (HydratableT m) where
55+ type Performable (HydratableT m) = Performable m
56+ performEvent_ = lift . performEvent_
57+ performEvent = lift . performEvent
58+
59+instance PrimMonad m => PrimMonad (HydratableT m) where
60+ type PrimState (HydratableT m) = PrimState m
61+ primitive = lift . primitive
62+
63+makeHydratable :: Reflex t => ElementConfig er t m -> ElementConfig er t m
64+makeHydratable cfg = cfg
65+ { _elementConfig_initialAttributes = Map.insert "data-ssr" "" $ _elementConfig_initialAttributes cfg
66+ , _elementConfig_modifyAttributes = fmap (Map.delete "data-ssr") <$> _elementConfig_modifyAttributes cfg
67+ }
68+
69+instance PostBuild t m => PostBuild t (HydratableT m) where
70+ getPostBuild = lift getPostBuild
71+
72+deriving instance TriggerEvent t m => TriggerEvent t (HydratableT m)
73+
74+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (HydratableT m) where
75+ newEventWithTrigger = lift . newEventWithTrigger
76+ newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
77+
78+instance Adjustable t m => Adjustable t (HydratableT m) where
79+ runWithReplace a0 a' = HydratableT $ runWithReplace (coerce a0) (coerceEvent a')
80+ traverseDMapWithKeyWithAdjust f dm0 dm' = HydratableT $ traverseDMapWithKeyWithAdjust (\k v -> runHydratableT $ f k v) (coerce dm0) (coerceEvent dm')
81+ traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = HydratableT $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runHydratableT $ f k v) (coerce dm0) (coerceEvent dm')
82+ traverseIntMapWithKeyWithAdjust f m0 m' = HydratableT $ traverseIntMapWithKeyWithAdjust (\k v -> runHydratableT $ f k v) (coerce m0) (coerceEvent m')
83+
84+instance NotReady t m => NotReady t (HydratableT m) where
85+ notReadyUntil = lift . notReadyUntil
86+ notReady = lift notReady
87+
88+instance DomBuilder t m => DomBuilder t (HydratableT m) where
89+ type DomBuilderSpace (HydratableT m) = DomBuilderSpace m
90+ element t cfg = lift . element t (makeHydratable cfg) . runHydratableT
91+ inputElement cfg = lift $ inputElement $ cfg
92+ { _inputElementConfig_elementConfig = makeHydratable $ _inputElementConfig_elementConfig cfg
93+ }
94+ textAreaElement cfg = lift $ textAreaElement $ cfg
95+ { _textAreaElementConfig_elementConfig = makeHydratable $ _textAreaElementConfig_elementConfig cfg
96+ }
97+ selectElement cfg child = do
98+ let cfg' = cfg
99+ { _selectElementConfig_elementConfig = makeHydratable $ _selectElementConfig_elementConfig cfg
100+ }
101+ lift $ selectElement cfg' $ runHydratableT child
102+
103+instance HasDocument m => HasDocument (HydratableT m)
104+
105+instance HasJSContext m => HasJSContext (HydratableT m) where
106+ type JSContextPhantom (HydratableT m) = JSContextPhantom m
107+ askJSContext = lift askJSContext
108+
109+instance HasJS js m => HasJS js (HydratableT m) where
110+ type JSX (HydratableT m) = JSX m
111+ liftJS = lift . liftJS
112+
113+instance DomRenderHook t m => DomRenderHook t (HydratableT m) where
114+ withRenderHook f = HydratableT . withRenderHook f . runHydratableT
115+ requestDomAction = HydratableT . requestDomAction
116+ requestDomAction_ = HydratableT . requestDomAction_
reflex-dom-core/src/Reflex/Dom/Builder/Immediate.hs+12−5
@@ -765,10 +765,17 @@ hydrateElement elementTag cfg child = do
765765 result <- HydrationDomBuilderT $ lift $ runReaderT (unHydrationDomBuilderT child) env'
766766 wrapResult <- liftIO newEmptyMVar
767767 let skipAttr = "data-hydration-skip" :: DOM.JSString
768− hasSkipAttribute :: DOM.Element -> HydrationRunnerT t m Bool
769− hasSkipAttribute e = case cfg ^. namespace of
770− Nothing -> hasAttribute e skipAttr
771− Just ns -> hasAttributeNS e (Just ns) skipAttr
768+ ssrAttr = "data-ssr" :: DOM.JSString
769+ shouldSkip :: DOM.Element -> HydrationRunnerT t m Bool
770+ shouldSkip e = case cfg ^. namespace of
771+ Nothing -> do
772+ skip <- hasAttribute e skipAttr
773+ ssr <- hasAttribute e ssrAttr
774+ pure $ skip || not ssr
775+ Just ns -> do
776+ skip <- hasAttributeNS e (Just ns) skipAttr
777+ ssr <- hasAttributeNS e (Just ns) ssrAttr
778+ pure $ skip || not ssr
772779 childDom <- liftIO $ readIORef childDelayedRef
773780 let rawCfg = extractRawElementConfig cfg
774781 doc <- askDocument
@@ -783,7 +790,7 @@ hydrateElement elementTag cfg child = do
783790 pure e
784791 Just node -> DOM.castTo DOM.Element node >>= \case
785792 Nothing -> go (Just node) -- this node is not an element, skip
786− Just e -> hasSkipAttribute e >>= \case
793+ Just e -> shouldSkip e >>= \case
787794 True -> go (Just node) -- this element is explicitly marked for being skipped by hydration
788795 False -> do
789796 t <- Element.getTagName e
reflex-dom-core/src/Reflex/Dom/Builder/InputDisabled.hs+6
@@ -80,6 +80,7 @@ instance Adjustable t m => Adjustable t (InputDisabledT m) where
8080 runWithReplace a0 a' = InputDisabledT $ runWithReplace (coerce a0) (coerceEvent a')
8181 traverseDMapWithKeyWithAdjust f dm0 dm' = InputDisabledT $ traverseDMapWithKeyWithAdjust (\k v -> runInputDisabledT $ f k v) (coerce dm0) (coerceEvent dm')
8282 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = InputDisabledT $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runInputDisabledT $ f k v) (coerce dm0) (coerceEvent dm')
83+ traverseIntMapWithKeyWithAdjust f m0 m' = InputDisabledT $ traverseIntMapWithKeyWithAdjust (\k v -> runInputDisabledT $ f k v) (coerce m0) (coerceEvent m')
8384
8485instance NotReady t m => NotReady t (InputDisabledT m) where
8586 notReadyUntil = lift . notReadyUntil
@@ -108,3 +109,8 @@ instance HasJSContext m => HasJSContext (InputDisabledT m) where
108109instance HasJS js m => HasJS js (InputDisabledT m) where
109110 type JSX (InputDisabledT m) = JSX m
110111 liftJS = lift . liftJS
112+
113+instance DomRenderHook t m => DomRenderHook t (InputDisabledT m) where
114+ withRenderHook f = InputDisabledT . withRenderHook f . runInputDisabledT
115+ requestDomAction = InputDisabledT . requestDomAction
116+ requestDomAction_ = InputDisabledT . requestDomAction_
reflex-dom-core/src/Reflex/Dom/Builder/Static.hs+1−1
@@ -288,7 +288,7 @@ instance SupportsStaticDomBuilder t m => DomBuilder t (StaticDomBuilderT t m) wh
288288 StaticDomBuilderT $ do
289289 let shouldEscape = elementTag `Set.notMember` noEscapeElements
290290 (result, innerHtml) <- lift $ lift $ runStaticDomBuilderT child $ StaticDomBuilderEnv shouldEscape Nothing
291− attrs0 <- foldDyn applyMap (Map.insert "data-ssr" "" $ cfg ^. initialAttributes) (cfg ^. modifyAttributes)
291+ attrs0 <- foldDyn applyMap (cfg ^. initialAttributes) (cfg ^. modifyAttributes)
292292 selectValue <- asks _staticDomBuilderEnv_selectValue
293293 let addSelectedAttr attrs sel = case Map.lookup "value" attrs of
294294 Just v | v == sel -> attrs <> Map.singleton "selected" ""
reflex-dom-core/src/Reflex/Dom/Core.hs+1
@@ -6,6 +6,7 @@ module Reflex.Dom.Core (module X) where
66
77import Reflex as X hiding (askEvents)
88import Reflex.Dom.Builder.Class as X
9+import Reflex.Dom.Builder.Hydratable as X
910import Reflex.Dom.Builder.Immediate as X
1011import Reflex.Dom.Builder.InputDisabled as X
1112import Reflex.Dom.Builder.Static as X
reflex-dom-core/src/Reflex/Dom/Prerender.hs+9−4
@@ -33,6 +33,7 @@ import Foreign.JavaScript.TH
3333import GHCJS.DOM.Types (MonadJSM)
3434import Reflex hiding (askEvents)
3535import Reflex.Dom.Builder.Class
36+import Reflex.Dom.Builder.Hydratable
3637import Reflex.Dom.Builder.Immediate
3738import Reflex.Dom.Builder.InputDisabled
3839import Reflex.Dom.Builder.Static
@@ -270,8 +271,8 @@ instance (Prerender js t m, MonadFix m, Reflex t) => Prerender js t (RequesterT
270271 (x, e) <- runRequesterT w (selectInt fannedResponses selector)
271272 pure (x, fmapCheap (IntMap.singleton selector) e)
272273 (result, requestsDyn) <- fmap splitDynPure $ lift $ prerender (withFannedResponses server 0) (withFannedResponses client 1)
273− responses <- fmap (fmapCheap unMultiEntry) $ requesting' $ fmapCheap multiEntry $ switch $ current requestsDyn
274− pure result
274+ responses <- fmap (fmapCheap unMultiEntry) $ requesting' $ fmapCheap multiEntry $ switchPromptlyDyn requestsDyn
275+ return result
275276
276277instance (Prerender js t m, Monad m, Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q) => Prerender js t (QueryT t q m) where
277278 type Client (QueryT t q m) = QueryT t q (Client m)
@@ -283,8 +284,12 @@ instance (Prerender js t m, Monad m, Reflex t, MonadFix m, Group q, Additive q,
283284 pure a
284285
285286instance (Prerender js t m, Monad m) => Prerender js t (InputDisabledT m) where
286− type Client (InputDisabledT m) = Client m
287− prerender (InputDisabledT server) client = InputDisabledT $ prerender server client
287+ type Client (InputDisabledT m) = InputDisabledT (Client m)
288+ prerender (InputDisabledT server) (InputDisabledT client) = InputDisabledT $ prerender server client
289+
290+instance (Prerender js t m, Monad m) => Prerender js t (HydratableT m) where
291+ type Client (HydratableT m) = HydratableT (Client m)
292+ prerender (HydratableT server) (HydratableT client) = HydratableT $ prerender server client
288293
289294instance (Prerender js t m, Monad m, ReflexHost t) => Prerender js t (PostBuildT t m) where
290295 type Client (PostBuildT t m) = PostBuildT t (Client m)
reflex-dom-core/src/Reflex/Dom/Widget/Basic.hs+5−4
@@ -60,6 +60,7 @@ module Reflex.Dom.Widget.Basic
6060 , partitionMapBySetLT
6161 ) where
6262
63+import Reflex.Adjustable.Class
6364import Reflex.Class
6465import Reflex.Collection
6566import Reflex.Dom.Builder.Class
@@ -148,21 +149,21 @@ button t = do
148149-- at post-build in addition to the times at which the input Dynamic is
149150-- updated, and its value is the result of running the widget.
150151-- Note: Often, the type @a@ is an 'Event', in which case the return value is an Event-of-Events that would typically be flattened (via 'switchHold').
151−dyn :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
152+dyn :: (Adjustable t m, NotReady t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
152153dyn = networkView
153154
154155-- | Like 'dyn' but discards result.
155−dyn_ :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m ()
156+dyn_ :: (Adjustable t m, NotReady t m, PostBuild t m) => Dynamic t (m a) -> m ()
156157dyn_ = void . dyn
157158
158159-- | Given an initial widget and an Event of widget-creating actions, create a widget that is recreated whenever the Event fires.
159160-- The returned Dynamic of widget results occurs when the Event does.
160161-- Note: Often, the type 'a' is an Event, in which case the return value is a Dynamic-of-Events that would typically be flattened (via 'switchDyn').
161−widgetHold :: (DomBuilder t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
162+widgetHold :: (Adjustable t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
162163widgetHold = networkHold
163164
164165-- | Like 'widgetHold' but discards result.
165−widgetHold_ :: (DomBuilder t m, MonadHold t m) => m a -> Event t (m a) -> m ()
166+widgetHold_ :: (Adjustable t m, MonadHold t m) => m a -> Event t (m a) -> m ()
166167widgetHold_ z = void . widgetHold z
167168
168169-- | Create a DOM element
reflex-dom-core/src/Reflex/Dom/Widget/Resize.hs+4
@@ -33,6 +33,10 @@ import qualified GHCJS.DOM.Types as DOM
3333
3434-- | A widget that wraps the given widget in a div and fires an event when resized.
3535-- Adapted from @github.com\/marcj\/css-element-queries@
36+--
37+-- This function can cause strange scrollbars to appear in some circumstances.
38+-- These can be hidden with pseudo selectors, for example, in webkit browsers:
39+-- .wrapper *::-webkit-scrollbar { width: 0px; background: transparent; }
3640resizeDetector :: (MonadJSM m, DomBuilder t m, PostBuild t m, TriggerEvent t m, PerformEvent t m, MonadHold t m, DomBuilderSpace m ~ GhcjsDomSpace, MonadJSM (Performable m), MonadFix m) => m a -> m (Event t (), a)
3741resizeDetector = resizeDetectorWithStyle ""
3842
reflex-dom-core/test/hlint.hs+2
@@ -16,9 +16,11 @@ main = do
1616 , "--ignore=Use unless"
1717 , "--ignore=Use if"
1818 , "--ignore=Use fewer imports"
19+ , "--ignore=Use list comprehension"
1920 , "--ignore=Unnecessary hiding" -- Interferes with cross-version compatibility
2021 , "--ignore=Use <$>"
2122 , "--ignore=Reduce duplication" --TODO: Re-enable this test
23+ , "--ignore=Use list comprehension"
2224 , "--cpp-define=USE_TEMPLATE_HASKELL"
2325 ]
2426 if null ideas then exitSuccess else exitFailure
reflex-dom-core/test/hydration.hs+34−23
@@ -20,9 +20,11 @@
2020{-# LANGUAGE TypeApplications #-}
2121{-# LANGUAGE TypeFamilies #-}
2222
23+import Prelude hiding (fail)
2324import Control.Concurrent
24−import Control.Monad
25+import Control.Monad hiding (fail)
2526import Control.Monad.Catch
27+import Control.Monad.Fail
2628import Control.Monad.Fix
2729import Control.Monad.IO.Class
2830import Control.Monad.Ref
@@ -52,6 +54,7 @@ import System.IO (stderr)
5254import System.IO.Silently
5355import System.IO.Temp
5456import System.Process
57+import System.Which (staticWhich)
5558import qualified Test.HUnit as HUnit (assertEqual, assertFailure)
5659import qualified Test.Hspec as H
5760import qualified Test.Hspec.Core.Spec as H
@@ -59,6 +62,7 @@ import Test.Hspec (xit)
5962import Test.Hspec.WebDriver hiding (runWD, click, uploadFile, WD)
6063import qualified Test.Hspec.WebDriver as WD
6164import Test.WebDriver (WD(..))
65+import Test.WebDriver.Exceptions (ServerError(..))
6266
6367import qualified Data.ByteString.Lazy as LBS
6468import qualified Data.Dependent.Map as DMap
@@ -74,6 +78,9 @@ import qualified Test.WebDriver.Capabilities as WD
7478import Test.Util.ChromeFlags
7579import Test.Util.UnshareNetwork
7680
81+chromium :: FilePath
82+chromium = $(staticWhich "chromium")
83+
7784seleniumPort, jsaddlePort :: PortNumber
7885seleniumPort = 8000
7986jsaddlePort = 8001
@@ -117,13 +124,15 @@ deriveGEq ''DKey
117124deriveGCompare ''DKey
118125deriveGShow ''DKey
119126
127+deriving instance MonadFail WD
128+
120129main :: IO ()
121130main = do
122131 unshareNetork
123132 isHeadless <- (== Nothing) <$> lookupEnv "NO_HEADLESS"
124133 withSandboxedChromeFlags isHeadless $ \chromeFlags -> do
125134 withSeleniumServer $ \selenium -> do
126− browserPath <- liftIO $ T.strip . T.pack <$> readProcess "which" [ "chromium" ] ""
135+ let browserPath = T.strip $ T.pack chromium
127136 when (T.null browserPath) $ fail "No browser found"
128137 withDebugging <- isNothing <$> lookupEnv "NO_DEBUG"
129138 let wdConfig = WD.defaultConfig { WD.wdPort = fromIntegral $ _selenium_portNumber selenium }
@@ -737,9 +746,9 @@ tests withDebugging wdConfig caps _selenium = do
737746 pb <- getPostBuild
738747 performEvent_ $ liftIO (putMVar lock ()) <$ pb
739748 it "result Dynamic is updated *after* switchover" $ runWD $ do
740− let static = checkBodyText "PostBuild"
749+ let preSwitchover = checkBodyText "PostBuild"
741750 check = checkBodyText "Client"
742− testWidget static check $ void $ do
751+ testWidget preSwitchover check $ void $ do
743752 d <- prerender (pure "Initial") (pure "Client")
744753 pb <- getPostBuild
745754 initial <- sample $ current d
@@ -747,16 +756,16 @@ tests withDebugging wdConfig caps _selenium = do
747756 -- This essentially checks that the client IO runs *after* switchover/postBuild,
748757 -- thus can't create conflicting DOM
749758 it "can't exploit IO to break hydration" $ runWD $ do
750− let static = checkBodyText "Initial"
751− testWidgetStatic static $ void $ do
759+ let preSwitchover = checkBodyText "Initial"
760+ testWidgetStatic preSwitchover $ void $ do
752761 ref <- liftIO $ newRef "Initial"
753762 prerender_ (pure ()) (liftIO $ writeRef ref "Client")
754763 text <=< liftIO $ readRef ref
755764 -- As above, so below
756765 it "can't exploit triggerEvent to break hydration" $ runWD $ do
757− let static = checkBodyText "Initial"
766+ let preSwitchover = checkBodyText "Initial"
758767 check = checkBodyText "Client"
759− testWidget static check $ void $ do
768+ testWidget preSwitchover check $ void $ do
760769 (e, trigger) <- newTriggerEvent
761770 prerender_ (pure ()) (liftIO $ trigger "Client")
762771 textNode $ TextNodeConfig "Initial" $ Just e
@@ -945,26 +954,26 @@ tests withDebugging wdConfig caps _selenium = do
945954 postBuildPatch = PatchDMap $ DMap.fromList [Key_Char :=> ComposeMaybe Nothing, Key_Bool :=> ComposeMaybe (Just $ Identity True)]
946955 it "doesn't replace elements at switchover, can delete/update/insert" $ runWD $ do
947956 chan <- liftIO newChan
948− let static :: WD [WD.Element]
949− static = getAndCheckInitialItems keyMap
957+ let preSwitchover :: WD [WD.Element]
958+ preSwitchover = getAndCheckInitialItems keyMap
950959 check :: [WD.Element] -> WD ()
951960 check xs = do
952961 checkInitialItems keyMap xs
953962 checkRemoval chan Key_Int
954963 checkReplace chan Key_Char 'B'
955964 checkInsert chan Key_Bool True
956− testWidget' static check $ do
965+ testWidget' preSwitchover check $ do
957966 (dmap, _evt) <- traverseDMapWithKeyWithAdjust widget keyMap =<< triggerEventWithChan chan
958967 liftIO $ dmap `H.shouldBe` keyMap
959968 it "handles postBuild correctly" $ runWD $ do
960969 chan <- liftIO newChan
961− let static = getAndCheckInitialItems $ applyAlways postBuildPatch keyMap
970+ let preSwitchover = getAndCheckInitialItems $ applyAlways postBuildPatch keyMap
962971 check xs = do
963972 withRetry $ checkInitialItems (applyAlways postBuildPatch keyMap) xs
964973 checkRemoval chan Key_Int
965974 checkInsert chan Key_Char 'B'
966975 checkReplace chan Key_Bool True
967− testWidget' static check $ void $ do
976+ testWidget' preSwitchover check $ void $ do
968977 pb <- getPostBuild
969978 replace <- triggerEventWithChan chan
970979 (dmap, _evt) <- traverseDMapWithKeyWithAdjust widget keyMap $ leftmost [postBuildPatch <$ pb, replace]
@@ -1054,24 +1063,24 @@ tests withDebugging wdConfig caps _selenium = do
10541063 postBuildPatch = PatchIntMap $ IntMap.fromList [(2, Nothing), (3, Just "trois"), (4, Just "four")]
10551064 xit "doesn't replace elements at switchover, can delete/update/insert" $ runWD $ do
10561065 chan <- liftIO newChan
1057− let static = getAndCheckInitialItems intMap
1066+ let preSwitchover = getAndCheckInitialItems intMap
10581067 check xs = do
10591068 checkInitialItems intMap xs
10601069 checkRemoval chan 1
10611070 checkReplace chan 2 "deux"
10621071 checkInsert chan 4 "four"
1063− testWidget' static check $ void $ do
1072+ testWidget' preSwitchover check $ void $ do
10641073 (im, _evt) <- traverseIntMapWithKeyWithAdjust widget intMap =<< triggerEventWithChan chan
10651074 liftIO $ im `H.shouldBe` intMap
10661075 xit "handles postBuild correctly" $ runWD $ do
10671076 chan <- liftIO newChan
1068− let static = getAndCheckInitialItems $ applyAlways postBuildPatch intMap
1077+ let preSwitchover = getAndCheckInitialItems $ applyAlways postBuildPatch intMap
10691078 check xs = do
10701079 withRetry $ checkInitialItems (applyAlways postBuildPatch intMap) xs
10711080 checkRemoval chan 1
10721081 checkInsert chan 2 "deux"
10731082 checkReplace chan 3 "trois"
1074− testWidget' static check $ void $ do
1083+ testWidget' preSwitchover check $ void $ do
10751084 pb <- getPostBuild
10761085 replace <- triggerEventWithChan chan
10771086 (dmap, _evt) <- traverseIntMapWithKeyWithAdjust widget intMap $ leftmost [postBuildPatch <$ pb, replace]
@@ -1166,12 +1175,12 @@ tests withDebugging wdConfig caps _selenium = do
11661175
11671176 describe "hydration" $ moveSpec $ \initMap test -> do
11681177 chan <- liftIO newChan
1169− let static = getAndCheckInitialItems initMap
1178+ let preSwitchover = getAndCheckInitialItems initMap
11701179 check xs = do
11711180 checkInitialItems initMap xs
11721181 body <- getBody
11731182 test body chan
1174− testWidget' static check $ void $ do
1183+ testWidget' preSwitchover check $ void $ do
11751184 (dmap, _evt) <- traverseDMapWithKeyWithAdjustWithMove widget initMap =<< triggerEventWithChan chan
11761185 liftIO $ assertEqual "DMap" initMap dmap
11771186
@@ -1197,10 +1206,12 @@ tests withDebugging wdConfig caps _selenium = do
11971206
11981207 describe "hydrating invalid HTML" $ session' $ do
11991208 it "can hydrate list in paragraph" $ runWD $ do
1200− let static = do
1209+ let preSwitchover = do
12011210 checkBodyText "before\ninner\nafter"
12021211 -- Two <p> tags should be present
1203− [p1, p2] <- WD.findElems (WD.ByTag "p")
1212+ (p1, p2) <- WD.findElems (WD.ByTag "p") >>= \case
1213+ [p1, p2] -> pure (p1, p2)
1214+ _ -> error "Unexpected number of `p` tags (expected 2)"
12041215 ol <- findElemWithRetry (WD.ByTag "ol")
12051216 shouldContainText "before" p1
12061217 shouldContainText "inner" ol
@@ -1211,7 +1222,7 @@ tests withDebugging wdConfig caps _selenium = do
12111222 shouldContainText "before\ninner\nafter" p1
12121223 elementShouldBeRemoved ol
12131224 elementShouldBeRemoved p2
1214− testWidget' static check $ do
1225+ testWidget' preSwitchover check $ do
12151226 -- This is deliberately invalid HTML, the browser will interpret it as
12161227 -- <p>before</p><ol>inner</ol>after<p></p>
12171228 el "p" $ do
@@ -1345,7 +1356,7 @@ testWidgetDebug' withDebugging beforeJS afterSwitchover bodyWidget = do
13451356 bodyWidget
13461357 el "script" $ text $ TE.decodeUtf8 $ LBS.toStrict $ jsaddleJs False
13471358 putStrLnDebug "rendering static"
1348− ((), html) <- liftIO $ renderStatic staticApp
1359+ ((), html) <- liftIO $ renderStatic $ runHydratableT staticApp
13491360 putStrLnDebug "rendered static"
13501361 waitBeforeJS <- liftIO newEmptyMVar -- Empty until JS should be run
13511362 waitUntilSwitchover <- liftIO newEmptyMVar -- Empty until switchover
reflex-dom/default.nixdeleted−38
@@ -1,38 +0,0 @@
1−{ mkDerivation, base, bytestring, jsaddle-webkit2gtk, jsaddle-wkwebview, jsaddle-warp, reflex
2−, reflex-dom-core, stdenv, text, ghc, hostPlatform, jsaddle-clib, android-activity ? null
3−, ghcBackend ? if hostPlatform.isDarwin then "wkwebview" else "webkit2gtk"
4−}:
5−assert (builtins.elem ghcBackend [ "warp" "webkit2gtk" "wkwebview" ]);
6−let isAndroid = hostPlatform.libc == "bionic";
7− ghcBackendPackage = {
8− webkit2gtk = jsaddle-webkit2gtk;
9− warp = jsaddle-warp;
10− wkwebview = jsaddle-wkwebview;
11− }.${ghcBackend};
12−in mkDerivation {
13− pname = "reflex-dom";
14− version = "0.5.2";
15− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
16− libraryHaskellDepends = [
17− base bytestring reflex reflex-dom-core text
18− ] ++ (if ghc.isGhcjs or false then [
19− ] else if hostPlatform.isiOS then [
20− jsaddle-wkwebview
21− ] else if isAndroid then [
22− jsaddle-clib
23− android-activity
24− ] else if hostPlatform.isMacOS then [
25− jsaddle-wkwebview
26− ghcBackendPackage
27− ] else [
28− ghcBackendPackage
29− ]);
30− configureFlags = if isAndroid then [
31− "-fandroid"
32− ] else if ghcBackend == "warp" then [
33− "-fuse-warp"
34− ] else [
35− ];
36− description = "Functional Reactive Web Apps with Reflex";
37− license = stdenv.lib.licenses.bsd3;
38−}
reflex-dom/reflex-dom.cabal+4−9
@@ -1,5 +1,5 @@
11Name: reflex-dom
2−Version: 0.5.2
2+Version: 0.5.2.0
33Synopsis: Functional Reactive Web Apps with Reflex
44Description:
55 Reflex-DOM is a Functional Reactive web framework based on the Reflex FRP engine.
@@ -41,14 +41,9 @@ flag build-examples
4141 default: False
4242 manual: True
4343
44−flag android
45− description: Build an Android app
46− default: False
47− manual: True
48−
4944library
5045 hs-source-dirs: src
51− if flag(android)
46+ if os(android)
5247 hs-source-dirs: src-android
5348 other-modules: Reflex.Dom.Android.MainWidget
5449 build-depends:
@@ -62,7 +57,7 @@ library
6257 cpp-options: -DANDROID
6358 build-tools: hsc2hs
6459 build-depends:
65− base >= 4.7 && < 4.12,
60+ base >= 4.7 && < 4.13,
6661 bytestring == 0.10.*,
6762 reflex >= 0.6.2,
6863 reflex-dom-core >=0.5.2 && <0.6,
@@ -83,7 +78,7 @@ library
8378 build-depends:
8479 jsaddle-webkit2gtk
8580 else
86− if !flag(android)
81+ if !os(android)
8782 build-depends:
8883 jsaddle-webkit2gtk
8984
reflex-platform.nixdeleted−8
@@ -1,8 +0,0 @@
1−let
2− reflex-platform-src = (import <nixpkgs> {}).fetchFromGitHub {
3− owner = "reflex-frp";
4− repo = "reflex-platform";
5− rev = "384cd850f3adf1d404bced2424b5f6efb0f415f2";
6− sha256 = "1ws77prqx8khmp8j6br1ij4k2v4dlgv170r9fmg0p1jivfbn8y9d";
7− };
8−in import reflex-platform-src
release.nix+32−9
@@ -1,12 +1,35 @@
1−{ rp ? import ./reflex-platform.nix {}
1+{ reflex-platform-fun ? import ./dep/reflex-platform
22}:
3+
34let
4− inherit (rp.nixpkgs) lib;
5+ native-reflex-platform = reflex-platform-fun {};
6+ inherit (native-reflex-platform.nixpkgs) lib;
57 systems = ["x86_64-linux" "x86_64-darwin"];
6− compilers = ["ghc8_4" "ghc8_0" "ghcjs8_4" "ghcjs8_0"];
7−in lib.genAttrs systems (system:
8− lib.genAttrs compilers (ghc: let
9− reflex-platform = import ./reflex-platform.nix { inherit system; };
10− hsPkgs = reflex-platform.${ghc};
11− in { inherit (import ./. hsPkgs reflex-platform.nixpkgs) reflex-dom reflex-dom-core; })
12−)
8+
9+ perPlatform = lib.genAttrs systems (system: let
10+ reflex-platform = reflex-platform-fun { inherit system; };
11+ compilers = [
12+ "ghc"
13+ "ghcjs"
14+ ] ++ lib.optionals (reflex-platform.androidSupport) [
15+ "ghcAndroidAarch64"
16+ "ghcAndroidAarch32"
17+ ] ++ lib.optionals (reflex-platform.iosSupport) [
18+ "ghcIosAarch64"
19+ ];
20+ hsPkgs = lib.genAttrs compilers (ghc: let
21+ ghc' = reflex-platform.${ghc}.override {
22+ overrides = self: super: import ./. self;
23+ };
24+ in {
25+ inherit (ghc') reflex-dom reflex-dom-core;
26+ });
27+ in hsPkgs // {
28+ cache = reflex-platform.pinBuildInputs "reflex-dom-${system}"
29+ (lib.concatLists (map builtins.attrValues (builtins.attrValues hsPkgs)));
30+ });
31+
32+ metaCache = native-reflex-platform.pinBuildInputs "reflex-dom-everywhere"
33+ (map (a: a.cache) (builtins.attrValues perPlatform));
34+
35+in perPlatform // { inherit metaCache; }