End to End F# with the Elm Architecture
The Elm Architecture is a simple pattern for building web apps with the ML derived language Elm. Of course, F# is also an ML derived language, and so the Elm Architecture is a natural fit for building web apps with F#.
We’ll be using a few old friends to implement the architecture, Suave for the backend server, Fable for the transpiler, a new friend Arch for the front end client, and good ol’ F# as the language on both the server and the client!
Add to that an engaged, passionate community, willing to do the grunt work late into the wee hours of the night, and we getting community driven, cutting edge framworks like Suave, Fable, and Arch that solve problems in a completely different light.
Usually I’ll go through the steps of setting everything up from scratch, but that gets tedious to write and even more tedious to follow. So this time we’ll start with a project that’s already set up and explain the different files, how they relate to each other, and how we can move forward building more complex web apps.
You can find the project we’ll be looking at here on github.
If you don’t have npm installed on your system then you can find the installer here.
And run a build from the bash shell
bash-3.2$ sh build.sh
Now start up the Suave.io server
bash-3.2$ cd build
bash-3.2$ mono server.exe
[I] 2016–12–29T18:39:56.5503400Z: listener started in 227.271 ms with binding 127.0.0.1:8083 [Suave.Tcp.tcpIpServer]
Browse to the page and start typing in your name
A Rundown of the Pieces and the Parts
When you ran the build script, you probably realized there is quite a lot going on, so let’s take a look at the important files to get a better understanding of how our Suave server and Fable client get built and talk with each other at runtime.
The Server Pieces
Building the server is pretty straightforward, our build.fsx file simply calls msbuild on our server.fsproj file in the src/server folder.
And what does our server do at runtime? Let’s open up the server.fs file and take a look.
The documentation on Suave.io is a little dated and so we’ve had to make a few minor tweaks to serve up our index.html page. Be aware that we’ve had to add a handler for a /*.* path that serves up any requested file in our home directory.
This is necessary in order to serve up our bundle.js file which contains our client side application.
In a real app we would have additional routes handling REST calls for various backend resources. See one of my other articles on how easy Suave makes this routing.
The Client Pieces
The server is relatively straightforward, but the client takes a little more explanation, as it’s built with technologies foreign to most .Net programmers.
In our build.fsx file, we added a simple call to run
npm install to install and update our node.js packages, then run the build command from our package.json file.
That’s right, we’re not using Nuget here, but the node package manger instead as the Fable transcompiler is distributed as a node package and not a nuget package.
The build command from our package.json file simply runs the Fable transpiler.
The Fable transpiler reads the fableconfig.json file where we define our project file, tell it to run
npm install before the build, and run webpack afterwards.
Nearly there! Finally our webpack.config.js file tells webpack to package the client.js output file from Fable as bundle.js. If you remember, this is the file our index.html is asking for when it gets served up to the browser.
Webpack can be used to not only bundle js files, but images, css, json, and the rest of the kit and kaboodle we need to run moder web apps.
Phew! So the configuration order to remember when building our client.fsproj web app is
build.fsx -> package.json -> fableconfig.json -> webpack.config.js
Like I said, there are a lot of files that you may not be familiar with, but I can attest after playing around with Redux and React, this is trivial in comparison!
Take a look at some of the “starter” templates for Redux and be prepared for your head to explode. Kapowee!
End to End F#
Now that we understand the build, all that’s left to do is take a look at our client.fs file to see how Arch implements the Elm Architecture.
Arch is an emerging technology, it doesn’t even have a stable npm package yet, so we’ve simply compiled the master branch and added it to the my_modules directory for the time being. I’m sure there will be an npm package once it stabalizes and matures.
A quick note about the client.fsproj file. In order for Fable to transcompile your client.fs files correctly, the individual Arch .fs must be added to the project.
It is not enough to simply add a reference to Arch. This will work when compiling the .fsproj but Fable will not be able to transcompile your client.fs file.
And now the magic client.fs file itself.
If you know anything about Elm, you will notice how similar this is straight away.
- Model — a simple string in this case
- Update — the actions we pattern match on to update the state of our model
- View — simple f# functions we know and love to generate the html.
We just scratched the service of what we can do with Elm and we’ll build a more complete application next time.
For now, just wrap your head around using F# end to end for web applications.
We get a fully functional back end, all the functionality of the .Net runtime wrapped in the “server as a function” paradigm of Suave.
Now combine the two using the natural functional web architecture of Elm and we’ve got a cutting edge web stack for the future.
Yeah, take that Asp.net and C#!