Photo by Kelvin Ang on Unsplash
Welcome back! This article is the last part of the “Getting started with Fable” series, so if you missed the previous articles please visit:
- Getting Started with Fable
- Getting Started with Fable. Scaffolding
- Getting Started with Fable. CSS
- Getting Started with Fable. Routing
- Getting Started with Fable. Node.js
The idea of this series is to create a fully functional application that can be used as a starting point for any enterprise application. In particular, I’m looking into a full-stack application written in F# which transpiles into JavaScript / React / Redux application on the front-end and Node.js / Express on the back-end. I know that it sounds a bit weird to transpile F# to JavaScript on the back-end instead of creating a .NET application.
In this last article, I want to share the migration experience from Fable v2 to v3, deployment experience, and some thoughts regarding Fable as a technology.
Fable 3
Frankly speaking, there were no major issues during migration from version 2 to version 3 of the Fable library. For me it was a bit strange decision to move from the npm
infrastructure to .NET
infrastructure, but it doesn’t make a huge difference.
What you need to do is to create a .NET
manifest file and install Fable
by running these commands:
dotnet new tool-manifest
dotnet tool install fable
The new manifest file will be generated. It should look something like this:
After that you can safely remove all fable dependencies from your node dependencies:
yarn remove fable-compiler fable-loader fable-splitter
Now, we need to take care of scripts in our package.json
, because they won’t work anymore:
"postinstall": "dotnet tool restore",
"build:server": "node server-prepare && dotnet fable src/api -o dist/api",
"start": "dotnet fable watch src/app.fsproj -o dist/app --run webpack serve",
Let’s go line by line. The first thing I’ve added is the postinstall
script. This script will ensure that we’ve restored our .NET
dependencies after restoring npm
dependencies. The second script is a bit more interesting. As far as now Fable
is a part of .NET
infrastructure and it should be executed via dotnet
runner we are no longer relying on webpack
as the main build tool. Yet, we still need to do some preparation tasks, like copying the package.json
file to our distribution directory. The file looks pretty simple right now, but of course, it can be extended with any additional tasks:
// server-prepare.js
const fs = require('fs');
fs.copyFileSync('src/api/package.json', 'dist/api/package.json');
The last script is using Fable
‘s ability to run any script after the execution of the Fable
script is finished. But to make this script working we need to update the webpack
configuration. The first thing we need to do is to remove the Fable
mentions from it because now Fable
build is a separate script. The second change is about switching the code from the source code to Fable
‘s build output. Here is the resulting configuration:
Basically, that’s all the changes you need to do to upgrade a small project from Fable
version 2 to version 3.
Hosting
Now let’s talk a bit about hosting the app. For this Proof of Concept, I’ve chosen the Heroku, but it doesn’t really matter.
The first thing you need to do is to create a new Pipeline:
Then you need to create 2 new applications inside this pipeline. The nice thing about Heroku is that now it supports the ability to link GitHub repository directly to the application for build and deployment automation.
Now let’s talk a bit about problems. The first problem is that Heroku still doesn’t have native support for the .NET
applications. Luckily it supports the Docker
containers so we can create one that we need:
The second problem is a bit more complicated and I was not able to find a good solution for it. The problem that Heroku still doesn’t support monorepo development. You can only have one heroku.yml
in your repository and it can only have one set of instructions for one application which is a bit problematic for our case. The only working solution I’ve found is to create a branch and change heroku.yml
in this branch. But I understand that this approach won’t work for anything other than PoC:
After adding these configurations you should be able to deploy both applications and make them work.
Conclusion
As I’ve mentioned earlier this is the last article in the “getting started with Fable” series. I’ve created a small Proof of Concept application using the stack of technologies I was interested in and was able to successfully deploy it to real servers. Unfortunately, I don’t want to continue this project due to a couple of reasons which I want to share with you.
The first important thing is that I was having hard times using Fable in a way a front-end developer wants to write a front-end application. I want to emphasize that it’s not about Fable being a bad technology it’s all about false expectations. I’m a big fan of JavaScript
and front-end development and I hate TypeScript
. Currently, I’m looking for technology that can replace TypeScript
in front-end development (at least partially). In my opinion, TypeScript
is a sort of workaround, it’s definitely not a well-designed modern language, yet it’s very flexible and covers most of the JavaScript
use cases (and in case it’s not supported you can just leave pure JavaScript
as is). That’s why it’s so popular. On the other hand, Fable
is more about doing one thing and doing it great. This technology works perfectly with the Elmish
architecture, there are plenty of samples and guides. But if you want to use your past front-end experience to build a Fable
application you are unlikely to succeed. There is no information about building Redux
-like applications using Fable
or building Node.js
applications using Fable
. And again, I’m not saying that this is bad. It’s really strange to expect a person who knows the .NET
to transpile .NET
code to JavaScript
to run it in the Node.js
environment. It’s what I want to do, it’s not what someone else expects.
The second thing is a personal one. I had issues with type definition files. Unfortunately, Fable
is missing a lot of type definitions. It’s a very common practice in front-end development to find some useful npm
package and add it to the application. And if you are using a TypeScript there is a huge chance that this package already has a type definition file available. If not it’s not a big deal, just cast the library to a special type called “any” and you are good to go. It’s not so simple in the Fable
world. I know that there is an automated tool for converting the TypeScript
type definition files into F#
. But I was not able to get it working, most of the time I was getting partially working type definitions with compilation errors and missing members. Taking into account that I’m relatively new to the F#
I was not able to quickly fix those issues. Of course, injecting JavaScript
directly into Fable
code is much harder than in TypeScript
.
So at some point, I’ve caught myself breaking through a lot of issues to write even a couple of lines of code. At this point, I’ve decided that the goal is achieved and I want to try something new.
Again, I’m not saying that the Fable technology is bad. It’s really great and if it fits your needs (.NET
back-end + React
front-end) you should definitely give it a try. It’s just not what I was looking for.
Thanks a lot for reading! I hope you enjoyed it. If you find this material useful, don’t forget to subscribe and share it with your colleagues and friends! Thanks!
One thought on “Getting Started with Fable. Fable 3 and deployment”