Skip to content

Support for custom index HTML for live reload / runJSorWarp

Athan Clark requested to merge jsaddle-custom-index-20210801 into master

This MR adds functionality to both jsaddle and shpadoinkle - specifically, the feature of having a custom index.html file be supplied for the live reload / runJSorWarp functionality. The fundamental purpose for this is to give users more consistency when developing their app - maybe their app relies on a CDN for bootstrap, for instance. Rather than needing to use a hack to add that <link rel=... /> tag at runtime, you can just supply your own index for live reload development.

Note: There will be a MR soon for a new tutorial consolidating this specific development oriented index.html, and likewise supplying your own index.html in the result/bin/foo.jsexe/ symlink result from nix.

Previously, JSaddle would only allow the following index to be supplied in run and debug:

indexHtml :: ByteString
indexHtml =
    "<!DOCTYPE html>\n\
    \<html>\n\
    \<head>\n\
    \<title>JSaddle</title>\n\
    \</head>\n\
    \<body>\n\
    \</body>\n\
    \<script src=\"/jsaddle.js\"></script>\n\
    \</html>"

You can see this definition in Langugage.Javascript.JSaddle.Run.Files here.

My modification to JSaddle simply allows for a parameter for each function that uses this definition - namely in Language.Javascript.JSaddle.Websockets - you can see the definitions here, under the names similar to fooWithIndex.

The changes to Shpadoinkle are just as simple - allow that index parameter to be supplied in runJSorWarpWithIndex, and likewise liveWithIndex:

-- | Serve jsaddle warp frontend.
-- This is useful for live reloads for development purposes.
-- For example:
-- @
--   ghcid -c "cabal repl" -W -T "Main.dev"
-- @
live
  :: Port
  -- ^ Port to serve the live server
  -> JSM ()
  -- ^ Frontend application
  -> IO ()
live = debug


-- | Identical to 'live', but with a custom @index.html@ file.
liveWithIndex
  :: ByteString
  -- ^ Custom @index.html@
  -> Port
  -- ^ Port to serve the live server
  -> JSM ()
  -- ^ Frontend application
  -> IO ()
liveWithIndex = debugWithIndex

Now, we can supply a index file like this:

indexHtml :: Env -> Html m a
indexHtml env =
  html_
  [ head_
    [ link' [rel "stylesheet", href "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"]
    , meta' [charset "UTF-8"]
    , script' [src $ entrypoint env]
    ]
  , body'_
  ]


indexHtmlUtf8 :: Env -> ByteString
indexHtmlUtf8 = encodeUtf8 . fromStrict . renderStatic . indexHtml


view :: () -> Html m ()
view _ = div_ [ "hello world" ]


app :: JSM ()
app = simple runSnabbdom () view stage


dev :: IO ()
dev = liveWithIndex (indexHtmlUtf8 Dev) 8080 app


main :: IO ()
main = do
  putStrLn "\nhi, my name is foobar"
  putStrLn "happy point of view on https://localhost:8080\n"
  runWithIndex (indexHtmlUtf8 Prod) 8080 app

Merge request reports