on master help sign in
Merge branch 'master' into is-obelisk-unset-lang-fix
commitebcdfe97e07249a2a1c8a41eb2791078e5547718 authorKen Micklas <ken.micklas@obsidian.systems> dateFri 22 Mar 2019, 14:37 (8 years ago) parentcd8aba1c1fa9c9
17 files changed+146−48
FAQ.md+31 default.nix+1 dep/reflex-platform/github.json+2−2 lib/backend/obelisk-backend.cabal−1 lib/backend/src/Obelisk/Backend.hs+2−4 lib/cliapp/src/Obelisk/CliApp/Process.hs+4−3 lib/cliapp/src/Obelisk/CliApp/Spinner.hs+2−14 lib/command/src/Obelisk/Command.hs+3−3 lib/command/src/Obelisk/Command/Deploy.hs+15−10 lib/command/src/Obelisk/Command/Run.hs+20−5 lib/frontend/obelisk-frontend.cabal+1 lib/frontend/src/Obelisk/Frontend.hs+5−1 lib/route/src/Obelisk/Route.hs+55 lib/route/src/Obelisk/Route/Frontend.hs+1−1 lib/run/obelisk-run.cabal−1 lib/run/src/Obelisk/Run.hs+1−2 skeleton/common/common.cabal+3−1
FAQ.md+31
@@ -1,6 +1,7 @@
11# Frequently Asked Questions
22
331. [How do I fix invalid entitlements? ](#how-do-i-fix-invalid-entitlements)
4+1. [`ob thunk update` or `ob deploy update` fails](#ob-thunk-update-or-ob-deploy-update-fails)
45
56### How do I fix invalid entitlements?
67
@@ -13,3 +14,33 @@ When this happens you'll see an error something like this:
1314
1415Fixing the value of `ios.bundleIdentifier` should fix the error.
1516
17+### `ob thunk update` or `ob deploy update` fails
18+Whenever an `ob` command fails, try re-running it with `-v`.
19+
20+If you're using a private repo, and you get a failure in nix-prefetch-url, you may need to unpack and repack the thunk. Here's some example output that shows this issue:
21+
22+```
23+Starting Obelisk </nix/store/j8wls8a89xr6s1a47lg6g83gnbdrfd0l-obelisk-command-0.1/bin/.ob-wrapped> args=["deploy","update","-v"] logging-level=Debug
24+Creating process: 'nix-build' './.obelisk/impl' '-A' 'command' '--no-out-link'
25+✔ Built on ./.obelisk/impl [command]
26+Handing off to /nix/store/j8wls8a89xr6s1a47lg6g83gnbdrfd0l-obelisk-command-0.1/bin/ob
27+Starting Obelisk </nix/store/j8wls8a89xr6s1a47lg6g83gnbdrfd0l-obelisk-command-0.1/bin/.ob-wrapped> args=["--no-handoff","deploy","update","-v"] logging-level=Debug
28+Creating process: 'git' 'ls-remote' '--exit-code' '--symref' 'https://github.com/obsidiansystems/some-private-repo.git' 'refs/heads/master'
29+git ls-remote maps: (fromList [],fromList [(GitRef_Branch "master","8546dfc8be9653f20bb26214e0991dbb957cb290")])
30+Latest commit in branch master from remote repo https://github.com/obsidiansystems/some-private-repo.git is 8546dfc8be9653f20bb26214e0991dbb957cb290
31+Creating process: 'nix-prefetch-url' '--unpack' '--type' 'sha256' 'https://github.com/obsidiansystems/some-private-repo/archive/8546dfc8be9653f20bb26214e0991dbb957cb290.tar.gz'
32+error: unable to download 'https://github.com/obsidiansystems/some-private-repo/archive/8546dfc8be9653f20bb26214e0991dbb957cb290.tar.gz': HTTP error 404
33+Process exited with code 1; 'nix-prefetch-url' '--unpack' '--type' 'sha256' 'https://github.com/obsidiansystems/some-private-repo/archive/8546dfc8be9653f20bb26214e0991dbb957cb290.tar.gz'
34+nix-prefetch-url: Failed to determine sha256 hash of URL https://github.com/obsidiansystems/some-private-repo/archive/8546dfc8be9653f20bb26214e0991dbb957cb290.tar.gz
35+✖ Updating thunk ./src to latest
36+```
37+
38+And here's how you can fix it:
39+
40+```
41+ob thunk unpack $SOME_THUNK
42+ob thunk pack $SOME_THUNK
43+```
44+Substitute the directory of your thunk for `$SOME_THUNK`. In the case of `ob deploy update`, `$SOME_THUNK` will be `src` in the deployment directory.
45+
46+(Based on issue #351).
default.nix+1
@@ -206,6 +206,7 @@ in rec {
206206 forceSSL = enableHttps;
207207 locations.${baseUrl} = {
208208 proxyPass = "http://localhost:" + toString internalPort;
209+ proxyWebsockets = true;
209210 };
210211 };
211212 };
dep/reflex-platform/github.json+2−2
@@ -2,6 +2,6 @@
22 "owner": "reflex-frp",
33 "repo": "reflex-platform",
44 "branch": "develop",
5− "rev": "a7cd9a23e7faa9c2545a4c111229e28208e42351",
6− "sha256": "0y52rfrhk4zszgprpyni51l0pgq18dg695k5bmpd62c3zxar5mvm"
5+ "rev": "d5b662e220a73e9d711aff0133265b6aafda89d8",
6+ "sha256": "1ri7khnxid8365s3vkgyny5ncgk1as86fjyznx3qj157mxgh3f3n"
77}
lib/backend/obelisk-backend.cabal−1
@@ -14,7 +14,6 @@ library
1414 lens,
1515 mtl,
1616 obelisk-asset-serve-snap,
17− obelisk-executable-config-inject,
1817 obelisk-frontend,
1918 obelisk-route,
2019 obelisk-snap-extras,
lib/backend/src/Obelisk/Backend.hs+2−4
@@ -37,7 +37,6 @@ import Data.Text (Text)
3737import qualified Data.Text as T
3838import Data.Text.Encoding
3939import Obelisk.Asset.Serve.Snap (serveAsset)
40−import Obelisk.ExecutableConfig.Inject (injectExecutableConfigs)
4140import Obelisk.Frontend
4241import Obelisk.Route
4342import Obelisk.Snap.Extras (doNotCache, serveFileIfExistsAs)
@@ -167,9 +166,8 @@ mkRouteToUrl validFullEncoder =
167166
168167renderGhcjsFrontend :: MonadIO m => (route -> Text) -> route -> Frontend route -> m ByteString
169168renderGhcjsFrontend urlEnc route f = do
170− let baseTag = elAttr "base" ("href" =: "/") blank --TODO: Figure out the base URL from the routes
171− ghcjsPreload = elAttr "link" ("rel" =: "preload" <> "as" =: "script" <> "href" =: "ghcjs/all.js") blank
169+ let ghcjsPreload = elAttr "link" ("rel" =: "preload" <> "as" =: "script" <> "href" =: "ghcjs/all.js") blank
172170 ghcjsScript = elAttr "script" ("language" =: "javascript" <> "src" =: "ghcjs/all.js" <> "defer" =: "defer") blank
173171 liftIO $ renderFrontendHtml urlEnc route
174− (_frontend_head f >> injectExecutableConfigs >> baseTag >> ghcjsPreload)
172+ (_frontend_head f >> ghcjsPreload)
175173 (_frontend_body f >> ghcjsScript)
lib/cliapp/src/Obelisk/CliApp/Process.hs+4−3
@@ -33,6 +33,7 @@ import Data.Monoid ((<>))
3333import Data.Text (Text)
3434import qualified Data.Text as T
3535import qualified Data.Text.Encoding as T
36+import Data.Text.Encoding.Error (lenientDecode)
3637import System.Exit (ExitCode (..))
3738import System.IO (Handle)
3839import System.IO.Streams (InputStream, handleToInputStream)
@@ -64,7 +65,7 @@ readProcessAndLogStderr
6465readProcessAndLogStderr sev process = do
6566 (out, _err) <- withProcess process $ \_out err -> do
6667 streamToLog =<< liftIO (streamHandle sev err)
67− liftIO $ T.decodeUtf8 <$> BS.hGetContents out
68+ liftIO $ T.decodeUtf8With lenientDecode <$> BS.hGetContents out
6869
6970readCreateProcessWithExitCode
7071 :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e)
@@ -89,7 +90,7 @@ readProcessAndLogOutput (sev_out, sev_err) process = do
8990
9091 -- TODO interleave stdout and stderr in log correctly
9192 streamToLog =<< liftIO (streamHandle sev_err err)
92− outText <- liftIO $ T.decodeUtf8 <$> BS.hGetContents out
93+ outText <- liftIO $ T.decodeUtf8With lenientDecode <$> BS.hGetContents out
9394 putLogRaw sev_out outText
9495
9596 liftIO (waitForProcess p) >>= \case
@@ -173,7 +174,7 @@ streamToLog
173174streamToLog stream = fix $ \loop -> do
174175 liftIO (Streams.read stream) >>= \case
175176 Nothing -> return ()
176− Just (sev, line) -> putLogRaw sev (T.decodeUtf8 line) >> loop
177+ Just (sev, line) -> putLogRaw sev (T.decodeUtf8With lenientDecode line) >> loop
177178
178179-- | Pretty print a 'CmdSpec'
179180reconstructCommand :: Process.CmdSpec -> Text
lib/cliapp/src/Obelisk/CliApp/Spinner.hs+2−14
@@ -163,23 +163,11 @@ runSpinner spinner f = forM_ spinner $ f >=> const delay
163163type SpinnerTheme = [Text]
164164
165165-- Find more spinners at https://github.com/sindresorhus/cli-spinners/blob/master/spinners.json
166−_spinnerSticks :: SpinnerTheme
167−_spinnerSticks = ["|", "/", "-", "\\"]
168−
169−spinnerStick :: SpinnerTheme
170−spinnerStick = ["|", "/", "-", "\\"]
171−
172−_spinnerCircleHalves :: SpinnerTheme
173−_spinnerCircleHalves = ["◐", "◓", "◑", "◒"]
174−
175−spinnerMoon :: SpinnerTheme
176−spinnerMoon = ["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"]
177−
178166minimalSpinnerTheme :: SpinnerTheme
179−minimalSpinnerTheme = spinnerStick
167+minimalSpinnerTheme = ["|", "/", "-", "\\"]
180168
181169defaultSpinnerTheme :: SpinnerTheme
182−defaultSpinnerTheme = spinnerMoon
170+defaultSpinnerTheme = ["◐", "◓", "◑", "◒"]
183171
184172-- | Like `bracket` but the `release` function can know whether an exception was raised
185173bracket' :: MonadMask m => m a -> (a -> Maybe c -> m b) -> (a -> m c) -> m c
lib/command/src/Obelisk/Command.hs+3−3
@@ -17,6 +17,7 @@ import Data.List
1717import Data.Maybe (catMaybes)
1818import qualified Data.Text as T
1919import Data.Text.Encoding
20+import Data.Text.Encoding.Error (lenientDecode)
2021import GHC.StaticPtr
2122import Options.Applicative
2223import System.Directory
@@ -330,8 +331,7 @@ ob = \case
330331 route = _deployInitOpts_route deployOpts
331332 adminEmail = _deployInitOpts_adminEmail deployOpts
332333 enableHttps = _deployInitOpts_enableHttps deployOpts
333− deployInit thunkPtr (root </> "config") deployDir
334− sshKeyPath hostname route adminEmail enableHttps
334+ deployInit thunkPtr deployDir sshKeyPath hostname route adminEmail enableHttps
335335 DeployCommand_Push remoteBuilder -> do
336336 deployPath <- liftIO $ canonicalizePath "."
337337 deployPush deployPath $ case remoteBuilder of
@@ -361,7 +361,7 @@ getArgsConfig :: IO ArgsConfig
361361getArgsConfig = pure $ ArgsConfig { _argsConfig_enableVmBuilderByDefault = System.Info.os == "darwin" }
362362
363363encodeStaticKey :: StaticKey -> String
364−encodeStaticKey = T.unpack . decodeUtf8 . Base16.encode . LBS.toStrict . Binary.encode
364+encodeStaticKey = T.unpack . decodeUtf8With lenientDecode . Base16.encode . LBS.toStrict . Binary.encode
365365
366366-- TODO: Use failWith in place of fail to be consistent.
367367decodeStaticKey :: String -> Either String StaticKey
lib/command/src/Obelisk/Command/Deploy.hs+15−10
@@ -47,33 +47,38 @@ deployInit
4747 => ThunkPtr
4848 -> FilePath
4949 -> FilePath
50− -> FilePath
5150 -> [String] -- ^ hostnames
5251 -> String -- ^ route
5352 -> String -- ^ admin email
5453 -> Bool -- ^ enable https
5554 -> m ()
56−deployInit thunkPtr configDir deployDir sshKeyPath hostnames route adminEmail enableHttps = do
57− (hasConfigDir, localKey) <- withSpinner ("Preparing " <> T.pack deployDir) $ do
58− hasConfigDir <- liftIO $ do
59− createDirectoryIfMissing True deployDir
60− doesDirectoryExist configDir
55+deployInit thunkPtr deployDir sshKeyPath hostnames route adminEmail enableHttps = do
56+ localKey <- withSpinner ("Preparing " <> T.pack deployDir) $ do
6157 localKey <- liftIO (doesFileExist sshKeyPath) >>= \case
6258 False -> failWith $ T.pack $ "ob deploy init: file does not exist: " <> sshKeyPath
6359 True -> pure $ deployDir </> "ssh_key"
6460 callProcessAndLogOutput (Notice, Error) $
6561 proc "cp" [sshKeyPath, localKey]
6662 liftIO $ setFileMode localKey $ ownerReadMode .|. ownerWriteMode
67− return $ (hasConfigDir, localKey)
63+ return localKey
6864 withSpinner "Validating configuration" $ do
6965 void $ getHostFromRoute enableHttps route -- make sure that hostname is present
7066 forM_ hostnames $ \hostname -> do
7167 putLog Notice $ "Verifying host keys (" <> T.pack hostname <> ")"
7268 -- Note: we can't use a spinner here as this function will prompt the user.
7369 verifyHostKey (deployDir </> "backend_known_hosts") localKey hostname
74− when hasConfigDir $ withSpinner "Importing project configuration" $ do
70+ --IMPORTANT: We cannot copy config directory from the development project to
71+ --the deployment directory. If we do, it's very likely someone will
72+ --accidentally create a production deployment that uses development
73+ --credentials to connect to some resources. This could result in, e.g.,
74+ --production data backed up to a dev environment.
75+ withSpinner "Creating project configuration directories" $ do
7576 callProcessAndLogOutput (Notice, Error) $
76− proc "cp" [ "-r" , "-T" , configDir , deployDir </> "config"]
77+ proc "mkdir" [ "-p"
78+ , deployDir </> "config" </> "backend"
79+ , deployDir </> "config" </> "common"
80+ , deployDir </> "config" </> "frontend"
81+ ]
7782 withSpinner "Writing deployment configuration" $ do
7883 writeDeployConfig deployDir "backend_hosts" $ unlines hostnames
7984 writeDeployConfig deployDir "enable_https" $ show enableHttps
@@ -131,7 +136,7 @@ deployPush deployPath getNixBuilders = do
131136 withSpinner "Uploading closures" $ ifor_ buildOutputByHost $ \host outputPath -> do
132137 callProcess'
133138 (Map.fromList [("NIX_SSHOPTS", unwords sshOpts)])
134− "nix-copy-closure" ["-v", "--to", "root@" <> host, "--gzip", outputPath]
139+ "nix-copy-closure" ["-v", "--to", "--use-substitutes", "root@" <> host, "--gzip", outputPath]
135140 withSpinner "Uploading config" $ ifor_ buildOutputByHost $ \host _ -> do
136141 callProcessAndLogOutput (Notice, Warning) $
137142 proc "rsync"
lib/command/src/Obelisk/Command/Run.hs+20−5
@@ -54,11 +54,26 @@ run = do
5454 pkgs <- getLocalPkgs
5555 withGhciScript pkgs $ \dotGhciPath -> do
5656 freePort <- getFreePort
57− assets <- withProjectRoot "." $ \root ->
58− -- `--raw` is not available with old nix-instantiate. It drops quotation
59− -- marks and trailing newline, so is very convenient for shelling out.
60− readProcessAndLogStderr Debug $
61− proc "nix" ["eval", "-f", root, "passthru.staticFilesImpure", "--raw"]
57+ assets <- withProjectRoot "." $ \root -> do
58+ let importableRoot = if "/" `isInfixOf` root
59+ then root
60+ else "./" <> root
61+ isDerivation <- readProcessAndLogStderr Debug $
62+ proc "nix"
63+ [ "eval"
64+ , "-f"
65+ , root
66+ , "(let a = import " <> importableRoot <> " {}; in toString (a.reflex.nixpkgs.lib.isDerivation a.passthru.staticFilesImpure))"
67+ , "--raw"
68+ -- `--raw` is not available with old nix-instantiate. It drops quotation
69+ -- marks and trailing newline, so is very convenient for shelling out.
70+ ]
71+ -- Check whether the impure static files are a derivation (and so must be built)
72+ if isDerivation == "1"
73+ then fmap T.strip $ readProcessAndLogStderr Debug $ -- Strip whitespace here because nix-build has no --raw option
74+ proc "nix-build" ["-E", "(import " <> importableRoot <> "{}).passthru.staticFilesImpure"]
75+ else readProcessAndLogStderr Debug $
76+ proc "nix" ["eval", "-f", root, "passthru.staticFilesImpure", "--raw"]
6277 putLog Debug $ "Assets impurely loaded from: " <> assets
6378 runGhcid dotGhciPath $ Just $ unwords
6479 [ "run"
lib/frontend/obelisk-frontend.cabal+1
@@ -11,6 +11,7 @@ library
1111 ghcjs-dom,
1212 jsaddle,
1313 lens,
14+ obelisk-executable-config-inject,
1415 obelisk-route,
1516 primitive,
1617 ref-tf,
lib/frontend/src/Obelisk/Frontend.hs+5−1
@@ -42,6 +42,7 @@ import Obelisk.Route.Frontend
4242import Reflex.Dom.Core
4343import Reflex.Host.Class
4444import qualified Reflex.TriggerEvent.Base as TriggerEvent
45+import Obelisk.ExecutableConfig.Inject (injectExecutableConfigs)
4546
4647makePrisms ''Sum
4748
@@ -163,6 +164,9 @@ renderFrontendHtml urlEnc route headWidget bodyWidget = do
163164 --TODO: We should probably have a "NullEventWriterT" or a frozen reflex timeline
164165 html <- fmap snd $ renderStatic $ fmap fst $ flip runRouteToUrlT urlEnc $ runSetRouteT $ flip runRoutedT (pure route) $
165166 el "html" $ do
166− el "head" headWidget
167+ el "head" $ do
168+ let baseTag = elAttr "base" ("href" =: "/") blank --TODO: Figure out the base URL from the routes
169+ -- The order here is important - baseTag has to be before headWidget!
170+ baseTag >> injectExecutableConfigs >> headWidget
167171 el "body" bodyWidget
168172 return $ "<!DOCTYPE html>" <> html
lib/route/src/Obelisk/Route.hs+55
@@ -19,6 +19,7 @@
1919module Obelisk.Route
2020 ( R
2121 , pattern (:/)
22+ , hoistR
2223 , PageName
2324 , PathQuery
2425 , Encoder
@@ -78,6 +79,12 @@ module Obelisk.Route
7879 , void1Encoder
7980 , pathSegmentsTextEncoder
8081 , queryParametersTextEncoder
82+ , renderObeliskRoute
83+ , renderBackendRoute
84+ , renderFrontendRoute
85+ , readShowEncoder
86+ , integralEncoder
87+ , pathSegmentEncoder
8188 ) where
8289
8390import Prelude hiding ((.), id)
@@ -114,6 +121,7 @@ import qualified Data.Text as T
114121import Data.Text.Encoding
115122import Data.Universe
116123import Network.HTTP.Types.URI
124+import qualified Numeric.Lens
117125import Obelisk.Route.TH
118126import Text.Read (readMaybe)
119127
@@ -149,6 +157,9 @@ pattern a :/ b = a :=> Identity b
149157mapSome :: (forall a. f a -> g a) -> Some f -> Some g
150158mapSome f (Some.This a) = Some.This $ f a
151159
160+hoistR :: (forall x. f x -> g x) -> R f -> R g
161+hoistR f (x :=> Identity y) = f x :/ y
162+
152163--------------------------------------------------------------------------------
153164-- Encoder fundamentals
154165--------------------------------------------------------------------------------
@@ -824,4 +835,48 @@ makePrisms ''ObeliskRoute
824835deriveGEq ''Void1
825836deriveGCompare ''Void1
826837
838+-- | Given a backend route and a checked route encoder, render the route (path
839+-- and query string). See 'checkEncoder' for how to produce a checked encoder.
840+renderBackendRoute
841+ :: forall br a.
842+ Encoder Identity Identity (R (Sum br a)) PageName
843+ -> R br
844+ -> Text
845+renderBackendRoute enc = renderObeliskRoute enc . hoistR InL
846+
847+-- | Renders a frontend route with the supplied checked encoder
848+renderFrontendRoute
849+ :: forall a fr.
850+ Encoder Identity Identity (R (Sum a (ObeliskRoute fr))) PageName
851+ -> R fr
852+ -> Text
853+renderFrontendRoute enc = renderObeliskRoute enc . hoistR (InR . ObeliskRoute_App)
854+
855+-- | Renders a route of the form typically found in an Obelisk project
856+renderObeliskRoute
857+ :: forall a b.
858+ Encoder Identity Identity (R (Sum a b)) PageName
859+ -> R (Sum a b)
860+ -> Text
861+renderObeliskRoute e r =
862+ let enc :: Encoder Identity (Either Text) (R (Sum a b)) PathQuery
863+ enc = (pageNameEncoder . hoistParse (pure . runIdentity) e)
864+ in (T.pack . uncurry (<>)) $ encode enc r
865+
866+readShowEncoder :: (MonadError Text parse, Read a, Show a, Applicative check) => Encoder check parse a PageName
867+readShowEncoder = singlePathSegmentEncoder . unsafeTshowEncoder
868+
869+
870+integralEncoder :: (MonadError Text parse, Applicative check, Integral a) => Encoder check parse a Integer
871+integralEncoder = prismEncoder (Numeric.Lens.integral)
872+
873+pathSegmentEncoder :: (MonadError Text parse, Applicative check) =>
874+ Encoder check parse (Text, PageName) PageName
875+pathSegmentEncoder = unsafeMkEncoder EncoderImpl
876+ { _encoderImpl_encode = \(x, (y, z)) -> (x:y, z)
877+ , _encoderImpl_decode = \(xss, y) -> case xss of
878+ [] -> throwError "not enough path segments"
879+ (x:xs) -> pure (x, (xs, y))
880+ }
881+
827882--TODO: decodeURIComponent as appropriate
lib/route/src/Obelisk/Route/Frontend.hs+1−1
@@ -171,7 +171,7 @@ instance (Monad m, SetRoute t r m) => SetRoute t r (QueryT t q m) where
171171runRoutedT :: RoutedT t r m a -> Dynamic t r -> m a
172172runRoutedT = runReaderT . unRoutedT
173173
174−mapRoutedT :: (m a -> n a) -> RoutedT t r m a -> RoutedT t r n a
174+mapRoutedT :: (m a -> n b) -> RoutedT t r m a -> RoutedT t r n b
175175mapRoutedT f = RoutedT . mapReaderT f . unRoutedT
176176
177177withRoutedT :: (Dynamic t r -> Dynamic t r') -> RoutedT t r' m a -> RoutedT t r m a
lib/run/obelisk-run.cabal−1
@@ -25,7 +25,6 @@ library
2525 , obelisk-asset-serve-snap
2626 , obelisk-backend
2727 , obelisk-executable-config
28− , obelisk-executable-config-inject
2928 , obelisk-frontend
3029 , obelisk-route
3130 , process
lib/run/src/Obelisk/Run.hs+1−2
@@ -50,7 +50,6 @@ import Network.WebSockets (ConnectionOptions)
5050import Network.WebSockets.Connection (defaultConnectionOptions)
5151import qualified Obelisk.Asset.Serve.Snap as Snap
5252import Obelisk.ExecutableConfig (get)
53−import Obelisk.ExecutableConfig.Inject (injectExecutableConfigs)
5453import Obelisk.Frontend
5554import Obelisk.Route.Frontend
5655import Reflex.Dom.Core
@@ -152,7 +151,7 @@ renderJsaddleFrontend :: (route -> Text) -> route -> Frontend route -> IO ByteSt
152151renderJsaddleFrontend urlEnc r f =
153152 let jsaddleScript = elAttr "script" ("src" =: "/jsaddle/jsaddle.js") blank
154153 jsaddlePreload = elAttr "link" ("rel" =: "preload" <> "as" =: "script" <> "href" =: "/jsaddle/jsaddle.js") blank
155− in renderFrontendHtml urlEnc r (_frontend_head f >> injectExecutableConfigs >> jsaddlePreload) (_frontend_body f >> jsaddleScript)
154+ in renderFrontendHtml urlEnc r (_frontend_head f >> jsaddlePreload) (_frontend_body f >> jsaddleScript)
156155
157156-- | like 'bindPortTCP' but reconnects on exception
158157bindPortTCPRetry :: Settings
skeleton/common/common.cabal+3−1
@@ -9,7 +9,9 @@ library
99 , obelisk-route
1010 , mtl
1111 , text
12−
12+ default-extensions:
13+ TypeFamilies
14+ PolyKinds
1315 exposed-modules:
1416 Common.Api
1517 Common.Route