Rendering HTML

Once you have model and routes in place and constrained, the last piece of the puzzle is to write a function that takes both as arguments and returns file content (lazy bytestring, to be exact) to generate. This function can be as simple as the following:

render :: MyModel -> Route -> Asset ByteString
render model route =
  AssetGenerated Html "<b>Hello</b>, world!"

The AssetGenerated Html tells Ema that you are generating HTML content, which will be appropriately handled by the Hot Reload of the live server.

Of course we want it to be real, by using our model value, as well as generate the HTML based on the route. We will also use the blaze-html library to make writing HTML in Haskell palatable. A more realistic starting point (if not the finishing product) would be:

render :: MyModel -> Route -> Asset ByteString 
render model route = AssetGenerated Html . Blaze.renderHtml $ 
  H.html $ do 
    H.head $ do 
      H.title "My site"
      H.base ! A.href "/"  -- This is important
    H.body $ do 
      H.h1 "My site"
      case route of 
        Index -> 
          H.h1 "Welcome to my website!"
          H.p $ do 
            "Checkout the"
            H.a ! A.href (H.toValue $ Ema.routeUrl About) $ "About"
            " page."
        About ->
          H.div $ H.p "This website is managed by yours truly"
      H.footer $ do 
        A.a ! A.href "" $ "Source on GitHub"

Note that Ema provides a routeUrl helper function that serializes your route to the final URL (here, /about) for linking to. There is also a routeUrlWith function which allows you to disable pretty URLs, to get back the .html suffix for deployments to traditional web servers like Nginx, Gitlab, etc.

Spend a few moments trying to appreciate how this is much simpler to write than dealing with HTML template files spread across the disk as is the case with traditional static site generators. If you choose to go the DSL route, Haskell’s type-safety now applies to your HTML as well. On top of it, Ema’s hot reload will instantly update the dev server’s browser view whenever you change your HTML (or any of the Haskell source code).

Of course when using Ema nothing prevents you from choosing to use traditional HTML templates, and you can get hot reload on them too with a little bit of plumbing.

Next, you might want to peruse Howto.

Links to this page
  • Guide
    Rendering HTMLYou could use plain strings to build HTML, or use templates, or use one of the delightful Haskell DSLs
  • Defining your model

    A “model” in Ema represents the state to use to generate your site. It could be as simple as a variable, or it could be a list of parsed Markdown files (as in the case of a weblog). Ema’s model is also conceptually similar to Elm's model, in that - changing the model automatically changes the view.

  • Defining Ema instance
    render function that renders your route (usually to HTML); we’ll go over this in the next section.

    Next, with our model and routes in place constrained by Ema type class, we will define the HTML for our site using Ema.