Chapter 4 - GHCJS and the Client

By John Lenz. 2016.

The client code is responsible for creating the entire DOM. It interacts with the backend by sending requests to various servant endpoints. There are many technologies currently for building interactive client applications in the browser; you not only have to pick the language but also a display library/framework. For the language, I narrowed it down to Purescript or Haskell via GHCJS. What tipped the balance was the fact that my program has a significant chunk of business logic in the domain library that needs to be shared between the client and server. If it wasn't for this, I probably would have selected Purescript.

I selected react for the display framework. The other big options I investigated are angular and reflex. I used angular on a previous project and while it eventually worked fine, I feel that angular does not integrate well with Haskell or functional programming in general; there is too much state and stateful code in angular. (Also there are no good GHCJS angular bindings.) Both react and reflex integrate well with functional programming but I picked react because with the flux ideas it supports a simple but powerful design idealy suited to websites.

React+flux is based on the idea that no state is maintained at all in the DOM. Instead, business state is tracked in stores and then you write a pure function which transforms the business domain data to the entire DOM, creating the DOM from scratch. Of course, if this was implemented directly it would be wildly inefficient since each time a checkbox changed you change the domain data, throw away the entire DOM, and recreate it from scratch and this would occur for every user interaction. Therefore, internally react uses a tree-diff algorithm to determine what changed between the previous full render and the current DOM. But we view this as an optimization and like all optimizations we mostly ignore it when writing our code. In our mind, we are concerned with writing a pure function which transforms the domain data to an entire DOM for the entire page. This fits excellently with Haskell because this is pure data transformation. Another advantage of react is that we can use all the existing react components that are available. There is a large community around React and components like date pickers, drag and drop, animation, grids, and so on already exist and can be used directly (with suprisingly little GHCJS glue code).


Having selected GHCJS and react, the client uses react-flux. In particular, the overall design of the client is very similar to the todo example application.

I have several stores managing login, navigation, and domain data. The stores have actions which trigger network requests or other manipulation of the store data. I then organize the views into two subdirectories: a Components subdirectory and a Views subdirectory. They are all ReactViews, but the difference is that components don't access any store data directly while views are focused on domain/business specific concepts. For example, I have components for a credit card input, showing the menu bar, some re-usable wrappers around text boxes and combo boxes, and so on.

The remainder of this page describes a few design ideas above and beond the bare-bones design from the TODO example in the react-flux source code.

Material UI, FlexboxGrid, and other 3rd party components

To provide the layout and basic components, I initially started with bootstrap. But after a little bit of development, I found bootstrap does not fit very well with the react+flux design: there is too much state in the various components that the react-bootstrap bindings only somewhat paper over. I then tried PureCSS which worked very well but I found I was creating too many components such as cards, dialogs, chips, badges, etc. from scratch. I then moved to Material UI and that has worked excellently! I haven't really investigated any other component libraries since MaterialUI works for me, but I expect any component library designed with React in mind will also work in GHCJS.

MaterialUI is suprisingly easy to use from GHCJS and react-flux. I have a file Mui.hs which contains wrapper functions for the various MaterialUI components, such as

textField_ :: JSS.JSString -> [PropertyOrHandler handler] -> ReactElementM handler ()
textField_ k props = foreign_ "TextField" (["key" $= k, "data-key" $= k] ++ props) mempty

(the data-key attribute is used for webdriver testing, see Chapter 6). The metalsmith site contains JavaScript to get the MaterialUI TextField component to be stored at window.TextField where the call to foreign_ expects it to be.

Throughout my views, I can then use textField_ and pass properties as shown on the TextField documentation. It is possible to create a more type-safe wrapper by not passing properties directly but instead creating Haskell data types for the properties. I didn't do that mainly because I don't have enough time to devote to maintaining such a framework. While sometimes it is annoying passing the wrong property or misspelling a property, the acceptance tests catch these errors. This is one place where I would improve the design if I had time.

Since MaterialUI just provides the components, I also use flexboxgrid for layout of rows and columns. I have a file Grid.hs which contains code such as

row_ :: JSS.JSString -> ReactElementM handler () -> ReactElementM handler ()
row_ k = div_ [ "key" $= k, "data-key" $= k, "className" $= "row" ]

with similar helpers for columns.

I have found it is relatively easy to integrate with 3rd-party react components using foreign_, so I do take advantage of several more components in a similar way to the MaterialUI example above.


There is a heated debate in the React community around styling. (Styling is controlling how elements are displayed such as borders, background color, margins, hover color, font size, and so on.) One option is from the traditional design of CSS, where you put the CSS styling into separate files managed by SCSS, lesscss, or friends and then in the React code you can toggle class names on elements to control styling. The other option is to put the styling into the React code. Almost all styling can be directly inserted from JavaScript except for a handful of things like hover and media queries for which there are small projects such as react-responsive and others.

I use inline styles and avoid CSS for the React application. The main advantages of CSS in traditional web applications is the separation of content and presentation and consistent styling. In a React application, the content and presentation is already separated; the content lives as data structures in the stores and the presentation is the (conceptually) pure function from the store data to the virtual DOM. The advantage of using inline styles in the Haskell code is that then the style is intertwined with the code that is creating the DOM elements, making them easier to understand, easier to edit, and easier to refactor since everything is in one place. Finally, consistent styling can easily be obtained by making sure that any custom styling is part of a reusable view or Haskell function so that the components that make up the page are consistent. For example, I have a Haskell function for creating a button and this function contains the styling for buttons, so that all buttons are styled consistently.

There is a helper function style in the react-flux library that eases using inline styles on elements.


Routing is pretending that the application is made up of different pages. The application is in control of the entire DOM, so it can present a navigation or sidebar with links such that when the user clicks on a link the existing DOM is thrown away and a new DOM is created for a different "page". This makes it seem to the user like they navigated to a new page. The browser even has functions that can be called from JavaScript to edit the location bar and interact with the back/forward buttons to complete the illusion. Despite this, no actual page changes are taking place in the browser.

The main routing library for React is react-router. It is easy to integrate with react-router from Haskell and react-flux. First, use a navigation store to store the current page and then create a controller view which passes the current page into the react-router component, using callbackView or callbackViewWithProps to pass in the views for the various pages.

Instead of using react-router, I decided to just directly implement the router. Maybe it is too much NIH, but my routing needs were very simple (only a handful of pages) and felt that react-router was overkill. Instead, I directly interact with the browser API for controlling the location bar and back/forward buttons. The purecss-side-menu example shows the code and design for directly performing navigation.

Network Requests

The basic flux design is user interaction -> dispatcher -> store -> render virtual DOM. In this design, any asynchronous operation such as sending a request to the backend happens inside the store. For example, consider a button which when clicked loads some data from the backend. The button's onClick handler is an action which when dispatched to the store causes the store to start a request to the server. The store sets up this request so that when the response arrives, another action is dispatched to the store containing the response data. For example, something like the following:

data RequestStatus = NoActiveRequest
                   | RequestInFlight
                   | PreviousRequestHadError Text
  deriving (Generic, Typeable)

data TeamStore = TeamStore
  { _teams :: HashMap TeamKey Team
  , _requestStatus :: RequestStatus
  deriving (Generic, Typeable)

data TeamAction = LoadTeam TeamKey
                | LoadTeamResponse (Either Text (TeamKey, Team))
                | UpdateTeam TeamKey Team
                | UpdateTeamResponse (Either Text ())
    deriving (Generic, Typeable, NFData)

cfg :: React.Flux.Servant.ApiRequestConfig
cfg = React.Flux.Servant.ApiRequestConfig "" NoTimeout

instance StoreData TeamStore where
    type StoreAction TeamStore = TeamAction
    transform (LoadTeam k) ts = do
      -- start the request
      React.Flux.Servant.request cfg (Proxy :: Proxy GetTeamRoute) k $
          -- when the response arrives, send LoadTeamResponse action to the store
          \r -> case r of
            Left (_errCode, err) -> return [SomeStoreAction teamStore $ LoadTeamResponse $ Left err]
            Right team -> return [SomeStoreAction teamStore $ LoadTeamResponse $ Right (k, team) ]

      -- mark that a request is in-flight
      return $ ts & requestStatus .~ RequestInFlight

    transform (LoadTeamResponse (Left err)) ts =
      return $ ts & requestStatus .~ PreviousRequestHadError err

    transform (LoadTeamResponse (Right (k, t)) ts =
      return $ ts & teams %~ insert k t
                  & requestStatus .~ NoActiveRequest

This uses react-flux-servant to make the request, although you could also use React.Flux.Ajax to make requests since it also works by sending an action once the response arrives. Inside your controller-view, you can then show a spinner when RequestInFlight or show the previous error.

Action Creators

A more complicated design inserts an "action creator" into the flow so that events go user interaction -> action creator -> dispatcher -> store. The action creator either passes actions to the dispatcher unchanged for synchronous actions, or sets up the async operation such as a request to the backend and arranges so when the response arrives an action is sent to the dispatcher. See this article for details. This design is also present in Redux with thunks created by the action creator.

The primary advantage of using an action creator is to ease understanding of the action flow and store transitions. With an action creator, all actions pass through the dispatcher which assists with understanding how actions flow across time. For example, consider the team store example above: the response action LoadTeamResponse from the request is sent directly to the store and cannot be easily sent through the dispatcher. The reason for this is module import cycles; the dispatcher module must import the stores in order to send actions to the stores and the stores must import the dispatcher to be able to send response actions to the dispatcher. The disadvantage of sending LoadTeamResponse directly to the store and not through the dispatcher is twofold. First, if every single action goes through the dispatcher it eases understanding of the design of the entire application, since all transformations of the entire app are in a single place. Secondly, if the response must trigger actions from multiple stores it is easier to do this from the dispatcher.

I initially started writing my app without an action creater, and later briefly explored adding an action creator. I decided not to introduce an action creater, since I don't believe that the benefits outweigh the effort of rewriting my stores. On the other hand, if I start a new application I might investigate an action creator in more detail. In particular, there must be some way using some type-system wizardry to automatically convert a servant API definition to an action creator. You could then have an action creator for no extra effort.

In the meantime, not using an action creator isn't that bad in Haskell. I feel that to understand the state transition of the program you still need to look at the stores, so I am not that concerned that some actions are not going through the dispatcher. It is awkward when a response requires actions in multiple stores. For example, when the response arrives that the user is successfully logged in, we need to trigger several actions across the stores to start loading data. I solved this by having one store import another store. For example, LoginStore.hs imports TeamStore.hs and when a successful login response arrives, the transform of that action in LoginStore.hs has a call to alterStore to alter the team store to signal that data can be loaded. This is one place where an action creator would expose this store transition by sending the successful login response through the dispatcher. In my application at least, there were only a few responses where this was needed.


As described in Chapter 2 and Chapter 3, authentication is done via JSON web tokens. The web token is stored in local storage, and managed by a Login store. The login store keeps the state if the user is logged in or not and if so the UserCredentials of the logged in user, and has actions to log in and log out. Inside the transform functions of the store, a simple foreign import javascript is enough to access the token.

foreign import javascript unsafe
    js_getJwt :: IO JSVal

lookupJwtToken :: IO (Maybe Text)
lookupJwtToken = js_getJwt >>= GHCJS.Marshal.fromJSValUnchecked

foreign import javascript unsafe
    "window['localStorage']['setItem']('jwt', $1)"
    js_setJwt :: JSS.JSString -> IO ()

setJwtToken :: Text -> IO ()
setJwtToken t = js_setJwt $ Data.JSString.Text.textToJSString t

foreign import javascript unsafe
    clearJwtToken :: IO ()

We must protect the token against cross-site scripting attacks. Because the server is not generating HTML, a whole class of XSS attacks are eliminated (what the Wikipedia article calls reflected and persistent attacks). React has built-in protections for DOM-based XSS attacks. Everything inserted into the DOM by React is escaped to prevent script injection, unless you use the dangerouslySetInnerHtml property. In my application, I do not use dangerouslySetInnerHtml at all.

Per-Page State and Stores

One unanticipated issue to arise only deep into the development is that very occasionally I wanted some per-page state. For example, I had a dialog to edit a team and so had to store if the dialog is open and if so which team is being edited. In JavaScript, you might just put some state into the dialog view, breaking the flux design of a pure function from the stores to the DOM. As long as it isn't too frequent and is some state that if lost on a page reload isn't user-breaking, it isn't that bad. The react-flux types forbid this: any state in react-flux that isn't in the stores must be local to a view.

There are several approaches to implement this:

  1. Create a small JavaScript React class and then call it from Haskell using foreign_.
  2. Use rawJsRendering to inject arbitrary JavaScript into the rendering function.
  3. Create a new store which only keeps the per-page state.
  4. Move everything into a single ReactView, since react-flux does allow state in a single view.
  5. Rethink the need for the state, focusing on keeping a pure transformation from stores to the DOM.

Number 5 is of course the best, and in fact quite often this is what I did. For the small handful of places where this wasn't possible, I used Number 3. For example, in the dialog for editing a team, I have a small store which tracks if the dialog is open and if so the TeamKey to edit. All the team data itself is kept in the main store. Implicitly, I am also using Number 1 since several MaterialUI components do have some internal state. Number 4 is an option and I did use it for a couple very small dialogs: the dialog can be a single view which has state if the dialog is open or not.

While not critical, this is also one place where a 6th option might be better. I don't know exactly what it would look like, but creating a store as in Number 3 didn't feel like quite the right approach. You then have two kinds of stores: the "real" stores which are storing the model and business data, and some small one-off stores holding some UI state. This is one place where I feel the design can be improved, but since it was only a couple places in my code it didn't rise to the top of my priority list.

Isomorphic React

Isomorphic React is executing the JavaScript for the page on the server to perform the initial transformation of domain data to the DOM, sending the resulting HTML and JavaScript to the client, and then the client JavaScript execution picks up transforming the store data to the DOM. First, this makes your site visible to search engines which do not execute JavaScript (Google and Yahoo/Bing both execute JavaScript, so the focus is on smaller search engines). Second, it can speed up the initial page render in high latency environments, since typically the first thing the client application does is send a network request to the server to load some data and this step can be skipped.

Isomorphic React works perfectly fine with react-flux and GHCJS. The best design is to use exportViewToJavaScript to export your entire app as a single view to JavaScript, and then write a small JavaScript React class which calls your exported view. This JavaScript React class can then be integrated with all the usual isomorphic react tools to run the code on in the client browser and the server using node.

For my application, I do not use isomorphic react. All my react code is behind a user login so the search engine advantage is irrelevant, and the GHCJS code is cached by the browser so for returning users there is no latency issue, since the cached GHCJS code will directly issue requests to the servant backend.


The client has no direct testing. Coming from developing clients in JavaScript, I am still shocked at how once I get the client to compile and refresh the page in the browser, it works! When writing angular code in JavaScript for a previous project, the client had a large test suite just to make sure the code would actually execute without errors. Yes, sometimes I misspell a MaterialUI property (which could be mitigated with a more complex API for MaterialUI), but this is almost always caught by refreshing the page since React will output a warning to the console for unknown properties. In addition, sometimes there is some business logic mistake such as not displaying the correct data, but I find that testing and catching these business-logic mistakes are better as part of the acceptance tests. I haven't really felt the need for any direct testing of the client.