Home

Awesome

Single page isomorphic example

This is a minimal example of Miso's Isomorphic feature. This example is focused on answering the questions:

There's a more expanded example available here, it uses stack to build the project instead of nix, and it shows how to set up a developer environment.

About isomorphism

Chances are that you happen to know what the mathematical definition of isomorphism is. If you do, forget that definition right now and treat it as a new term altogether. That'll be easier.

Isomorphic Javascript is the idea of having a web application "run" on both client and the server. The goal is to make single page javascript applications load faster. In frameworks without isomorphism, the server sends an html page with a mostly empty body, along with a big javascript file that fills in the body upon loading. This means that the app user won't see the app until the big javascript file is downloaded and run.

In applications with isomorphism, the body of the html page is rendered on the server, by running a minimal part of the app serverside. This way, app users will see a page even before the big javascript file loads. The big javascript file, once loaded, takes over the rendering and adds interactivity.

Required reading

The example explained

This example consists of a server, running the app on port 3003, and a ghcjs client. Three Haskell files define both:

For quick overview, here's which parts of the application are defined where:

ServerClientCommon
Top level HtmlUpdate function(s)Model data type
Servant routessubscriptionsInitial model
Action data type
View functions
Servant routes

Many important parts of the application are common to both client and server. It's more interesting, though, to look at what isn't common: The update function(s) and subscriptions live clientside only. This means that the server cannot add interactivity to the app. It can only render the actual Html page, using the initial model and the View functions. Any Actions referred to in the View functions are ignored by the server.

So basically it renders the initial Html page, sends it off to the client which then adds interactivity.

Note that "Servant routes" is listed both in Common and in Server. The routes in Common are linked to pages in the app itself, in this example just the top level / home route. The routes in Server include those defined in Common, but also define other routes, in our case the /static/ route which serves the all.js of the clientside app.

Running the example

Using nix:

cd $(nix-build) && bin/server

Note: The current working directory is important when running the server. The server won't be able to find the clientside part of the app when running the server from some place other than the folder with bin and static. This will prevent the javascript from loading and make the buttons not work. In other news, that's a great way of looking at the part of the app sent by the server.

Developing the project

You can work on the different sub-projects (client, common and server) using nix-shell and cabal.

common:

cd common
nix-shell
cabal build
...
exit

client:

cd client
nix-shell
cabal build --ghcjs
...
exit

After the client has been built, you can make a reference to it in the server. The server will need to know where to find the compiled client in order to serve it:

cd server
mkdir static
ln -sf ../$(find ../client -name all.js) static/

Lastly, building and running the server:

cd server
nix-shell
cabal build
cabal run server
...
exit