Getting started with Fable and Webpack
Introduction
Fable is new F# to JavaScript compiler created by Alfonso Garcia-Caro. In this post I’ll go, step by step, through process of creating client-side (browser) applications using it.
This post is targeted at F# developers without lot of knowladge about Node.js and JS ecosystem and it should let any F# developer to get started with Fable.
Requirements
Fable requires having both F# 4 and node 4.4 or bigger installed in your computer.
Setting up project
The first thing we need to do is creating new directory and initializing node project:
mkdir fable-test
cd fable-test
npm init
Npm is is the package manager for JavaScript. It lets users to find, share, and reuse packages of code or install additional tools
npm init
will create package.json
file. This file is project file for any Node.js based project (both client and server side). At start it will contain only basic information about a project, something like that:
{
"name": "fable-test",
"version": "1.0.0",
"description": "",
"scripts": {
"test": "..."
},
"author": "",
"license": "MIT",
}
Installing development tools.
Next step is installing all development dependencies (tools) which we’ll be using for our project. To do so we are using npm install
command:
npm install --save-dev fable-compiler
npm install --save-dev webpack
npm install --save-dev source-map-loader
First line installs Fable compiler for our project. Second command installs Webpack. Webpack is a module bundler - it takes modules with dependencies and generates static assets representing those modules. In our case it would take generated by Fable files together with other JS libraries we will depend upon and create single file output which can be easily added to page. Last dependency is plugin to Webpack which will enable nice debugging story for our application (debugging F# files in the browser)
It’s also worth noticing that those commands modified package.json
file, now it contains also following block:
"devDependencies": {
"fable-compiler": "^0.2.12",
"source-map-loader": "^0.1.5",
"webpack": "^1.13.0"
},
Installing dependencies
Now we will install our code dependencies using also npm install
.
npm install --save core-js
npm install --save fable-core
core-js
is polyfill ensuring that code generated by Fable will run in any browser. fable-core
is standard Fable library.
Those commands again modified package.json
file, this time adding following information:
"dependencies": {
"core-js": "^2.4.0",
"fable-core": "0.0.21"
}
Creating F# script and HTML file
Fable supports both fsproj
and plain fsx
files. For simplicity in this example let’s use fsx
file. Create src\code.fsx
with follwing content:
#r "../node_modules/fable-core/Fable.Core.dll"
open Fable.Core
open Fable.Import
Node.require.Invoke("core-js") |> ignore
let element = Browser.document.getElementById "sample"
element.innerText <- "Hello, world !!"
This code should be pretty straightforward, only tricky part is Node.require.Invoke("core-js")
which is importing Node.js module (installed by npm
).
Let’s also create very simple HTML file public\index.html
( public
will be our output folder):
<!doctype html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
</head>
<body>
<div id='sample'></div>
<script src="bundle.js"></script>
</body>
</html>
Configuration
First step is creating configuration for Fable compiler. It’s done by creating fableconfig.json
file.
{
"module": "commonjs",
"sourceMaps": true,
"projFile": "./src/code.fsx",
"outDir": "temp",
"scripts": {
"prebuild": "npm install",
"postbuild": "webpack"
},
"targets": {
"watch": {
"scripts": {
"postbuild": "webpack --watch"
}
}
}
}
First we define module type - in our case it’s commonjs
(as it’s working well with Webpack
). Next we define that we want to use soruce maps (it allows F# file debugging), entry point of application, and output directory for compiled JS files.
Next step is defining some small scripts which will be run before and after every build - before we want to run npm install
to restore all dependencies, after build we run webpack
to create bundled output file. Last part defines additional target which will be executed in watch
mode. In such case we want to run webpack
also in watch
mode.
watch
mode will make Fable and Webpack to recompile project after every file save without need to execute any additional commands.
Webpack configuration
Second step is to create webpack
configuration. Let’s create webpack.config.js
file:
var path = require("path");
var webpack = require("webpack");
var cfg = {
devtool: "source-map",
entry: "./temp/code.js",
output: {
path: path.join(__dirname, "public"),
filename: "bundle.js"
},
module: {
preLoaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "source-map-loader"
}
]
}
};
module.exports = cfg;
In this file we define that we want to use source maps, entry point for webpack ( so file generated by Fable), output path, and usage of any additional plugins (in our case it will be source-map-loader
installed before)
Npm scripts
Easiest way to run tools installed by npm
is by using scripts section in package.json
file. Let’s put there following scripts:
"scripts": {
"build": "fable",
"watch": "fable -w --target watch"
},
build
just starts Fable. watch
, as name suggests, starts Fable in watch
mode, so code is regenerated every time we save F# file. We can run those scripts using npm run <script_name>
command.
VSCode configuration
Last, optional step is creating VSCode configuration. It’s fairly easy since editor has decent integration with npm
. All we need to do is create .vscode\tasks.json
file and put there following code:
{
"version": "0.1.0",
"command": "npm",
"isShellCommand": true,
"showOutput": "always",
"suppressTaskName": true,
"tasks": [
{
"taskName": "install",
"args": ["install"]
},
{
"taskName": "build",
"args": ["run", "build"],
"isBuildCommand": true
},
{
"taskName": "watch",
"args": ["run", "watch"],
"isWatching": true
}
]
}
Here we define that our tasks are using npm
and we define arguments send to npm
with every task.
We can run those task usign Tasks: Run Task
command (build
task can be also run using Tasks: Run Build Command
command or Ctrl + Shift + B
)
Summary
In this post we have shortly moved all steps necessary to create browser, client-side applications using F#, Fable and Webpack. Whole source code of this sample application is on GitHub - https://github.com/Krzysztof-Cieslak/fable-webpack-demo