Hot Reload

Hot Reloading is a feature of Ema’s dev server wherein any changes to your Haskell source or data files (such as Markdown files or HTML templates) propagate instantly to the web browser without requiring any manual intervention like a full browser refresh. In practice, this is a such a delightful feature to work with. Imagine changing CSS style of an element, and see it reflect on your site in a split second.

How Ema implements hot reload


The Ema dev server uses websockets to keep a bi-directional connection open between the web browser and the backend server. When you click on a link or when something changes in the backend, they are communicated via this connection. In a statically generated site, however, no such activity happens - and a link click behaves like a normal link, in that the browser makes a full HTTP request to the linked page.

DOM patching

When switching to a new route or when receiving the new HTML, Ema uses morphdom to patch the existing DOM tree rather than replace it in its entirety. This, in addition to use of websockets, makes it possible to support instant hot reload with nary a delay.

Haskell reload

Finally, hot reload on code changes are supported via ghcid. The template repo's `bin/run` script uses ghcid underneath. Any HTML DSL (like blaze-html) or CSS DSL automatically gets supported for hot-reload. If you choose to use a file-based HTML template language, you can enable hot-reload on template change using the `unionmount` library.

Note that if your application makes use of threads, it is important to setup cleanup handlers so that ghcid doesn’t leave ghost processes behind. Helpers like race_ will do this automatically (incidentally it is used by runEma for running the user IO action).

Data reload

For anything outside of the Haskell code, your code becomes responsible for monitoring and updating the model LVar. The `unionmount` library already provides utilities to facilitate this for monitoring changes to files and directories.

Handling errors

If your code throws a Haskell exception, they will be gracefully handled and displayed in the browser, allowing you to recover without breaking hot-reload flow.

Links to this page
  • Working with files

    For monitoring local files on disk you would typically use something like fsnotify in place of observeFileSystem. What is the point of doing this? To support hot reload on data change. Imagine that your static site is generated based on Markdown files as well as HTML templates on disk. If either the Markdown file, or a HTML template file is modified, we want the web browser to hot reload the updated HTML instantly. This is enabled by storing both these kinds of files in the application model and using LVar to update it over time.

  • Using Markdown

    Note that with Ema you can get hot reload support for your Markdown files using the `unionmount` package.

  • Tutorial

    The runEma function is explained here, but in brief: it takes a render function (see below) as well as an IO action that allows us to create and update the model lvar. Note that threadDelay maxBound here? That is because our IO action must not exit; in the dev server mode of real-world websites, you would continue to monitor the external world (such as Markdown files) and update the model, to facilitate hot reload of data used by your site.

    This is the minimum amount of code necessary to run an Ema site. Notice that as you replace and save this file, your browser (which is at http://locahost:9001) will hot reload to display “Hello, Ema”. Congratulations, you just created your first website!

  • Rendering HTML

    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 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.

    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).

  • LVar

    If you are familiar with Haskell’s stm package, a LVar is essentially a TMVar but with an extra ability for other threads to observe changes. Ema uses it for hot reload, and your application code is expected to set and update its model through the LVar.

  • Getting Started

    That should start the Ema dev server displaying a simple website. Go ahead and try modifying either the Markdown content in ./content or the Haskell source in ./src/Main.hs, and observe how the web view updates instantly.

  • 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.

    Ema’s dev server supports hot reload; it will observe changes to your model, in addition to code. To facilitate this you will manage your model as a LVar. The runEma function (described here) takes an IO action that gets LVar model as an argument.

    In this contrived example (full code here), we are using UTCTime as the model. We set the initial value using LVar.set, and then continually update the current time every second. Every time the model gets updated, the web browser will hot reload to display the up to date value. For the BlogPosts model, you would typically use fsnotify to monitor changes to the underlying Markdown files, or even better use the `unionmount` library.

  • Concepts