Fable F# — Why and How
It’s also evolved quite rapidly and continues to do so, which means that quite a lot of what’s out there about it is out of date to some degree, and it is, in my view unfortunate that the project name is a normal English word, making it hard to construct online searches which avoid multiple false positives.
But, having got through that learning curve, in my opinion Fable offers more than enough benefit to justify the investment in time and effort required. This article is intended to help reduce that time and effort — and indeed to help remind me of things I may forget.
Everything below relates to what at the time of writing is the current version of Fable v1.3.11 and the current version of F# v4.3
The main reason why Fable can be confusing to start is that it relies on two, normally separate, technology stacks.
On the other hand, the infrastructure to support the F# language itself, the compilation environment, and the build process, rely on Microsoft’s .NET, which itself has multiple sub-variants, including the traditional .NET framework bundled with all Windows systems, the mono workalike for Linux/Unix, and the .NET core framework, which is Microsoft’s opensource implementation of much of the .NET framework.
Getting Started — prerequisites
Our first step is to make sure that we can actually create a basic Fable application. I’m going to recommend you follow the official docs to ensure you have the various prerequisites, but once you’ve installed all the tooling you need, come back here before you run any other commands.
The link you need is: http://fable.io/docs/getting-started.html ( first section only ).
Our first Fable app
OK, so we’ve installed .net sdk, node, yarn &c and some kind of editor ( I recommend VS code at this point, but it’s up to you ).
The next stage is to create a minimal Fable app, and take a look at the result. So:
dotnet new -i Fable.Template
will install the basic Fable Template in your environment. Now you can say
dotnet new fable -n FableApp -lang F#
and if all goes well, you will have a brand new directory containing all sorts of stuff.
Before we continue, let’s look around. At the time of writing ( 2018–03–15 ), FableApp contains:
- A README.md file which gives more detail than I do about how to build and run the application, but less detail about the structure of some of the key files.
- Files called .gitattributes and .gitignore and a directory called .vscode which I won’t say more about as they are not directly relevant.
- A FableApp.sln file which allows the dotnet restore command to know where to find the various projects for which to restore missing packages.
- A file Nuget.Config which is there to make sure that Microsoft’s nuget tooling doesn’t interfere with the use of paket to manage .net side dependencies
- A public directory containing an icon. This directory is where one would put the files served by our web browser — more later on this.
- top level files paket.dependencies and paket.lock. paket.dependencies is where we tell paket which NuGet packages we need in our project. paket.lock tells paket the precise versions of those packages we have used, and allows us to ensure that future builds from source are repeatable even if downstream packages change to new versions. (See the paket docs for the full explanation )
- a tools directory from which the fable compiler, webpack &c are configured and run
- and last, but definitely not least, a package.json file.
Now, before we look at some of the details, lets just run the app. The latest template makes that very easy. Just say:
The .net equivalent of yarn install is
but you won’t need to do this separately as the latest template arranges for yarn install to call it for you thanks to a line in package.json.
BTW, note that dotnet restore calls paket under the hood thanks to the configuration in the .sln and .fsproj files.
At this point, our directory has been supplemented with everything we need to build and run. So first try:
This will call the build script defined in package.json, which changes to the tools directory and runs the dotnet fable command with webpack. This does several things:
- It looks in the fsproj and paket.references files in the current directory (tools) to find out how to interpret dotnet fable as a call to a package called dotnet-fable
- dotnet-fable then creates a daemon which listens on a socket for instructions to run the fable transpiler
- It then runs webpack with command parameters which cause it to read the webpack.config.prod.js file for instructions.
- That in turn uses the fable-loader package for webpack which can read the project file, identify the f# sources to compile, and send them to the fable daemon
At this point we could simply send index.html to our favourite browser, and see the result.
But the template also provides us with
which allows us to run in development mode. This uses the webpack-dev-server to build the application in development mode and then publish it on a small webserver at port 8080. It also monitors the source for changes, and automatically rebuids the application when necessary.
webpack-dev-server has lots of clever features, and is well-documented in its own right. But the following may be useful if you’re not already familiar with it
In addition to simply serving the static files and bundle needed for a browser-client, as in the current template, webpack and webpack-dev-server can
- Produce a bundle suitable for running as a node application rather than as a browser client.
- Have the webpack-dev-server act as a passthrough-proxy to a separate webserver. This allows us to coexist our browser-app with a server-backend written for example in F# for .net core using Giraffe or indeed any backend we like, not just one written using node.
At this point, I encourage you to do the following
- Look at the code in the src directory, make some small changes, and check that you can run the result.
- Look at the package.json and webpack…js files and refer to the documentation for yarn and webpack to make sure you understand them and what they do. ( This is the only way to get comfortable with these key tools in my opinion, and without that knowledge, sooner or later you will get unstuck as your projects increase in complexity )
Once you are happy that you can extend the project, you have several places to go next
- You can look at the SAFE-Bookstore sample which will show you a structure for a Fable application with an F# .NET backend and an F# Fable client.
- You can look at the fableconf-workshops repo, and in particular the Elmish app, which will show you the structure for a Fable application with a node backend written in F# and a web frontend, also written in F#