Using Fable as part of your node applications
You can install the fable-compiler
package from npm
either locally or globally. Here we'll assume it's been installed globally so the fable
command is available from any directory.
The simplest way to compile a F# project (.fsproj
) or script (.fsx
) is
to pass its path as an argument to fable
:
1: 2: 3: |
|
Besides the default argument (--projFile
), the following options are available:
Option |
Short |
Description |
---|---|---|
|
|
Where to put compiled JS files. Defaults to project directory. |
|
|
Specify module code generation: |
|
|
Generate source maps: |
|
|
Recompile project much faster on file modifications. |
|
Specify ECMAScript target version: |
|
|
F# symbols for conditional compilation, like |
|
|
Paths to Fable plugins. |
|
|
Additional Babel plugins (without |
|
|
Specify project references in |
|
|
Compile unsigned byte arrays as Uint8ClampedArray. |
|
|
Copy external files into a |
|
|
|
Use options from a specific target in |
|
|
Shortcut for |
|
|
Shortcut for |
|
Pass a string of code directly to Fable. |
|
|
|
Display usage guide. |
You can use --refs
argument to link referenced projects with the JS import path that must be used, using the following format: [Project name without extension]=[JS import path]
.
Example:
1: 2: 3: 4: 5: 6: |
|
Rather than passing all the options to the CLI, it may be more convenient to put them
in JSON format in a file named fableconfig.json
and let the compiler read them for you.
You can combine options from the CLI and fableconfig.json
, when this happens the former will have preference.
To use fableconfig.json
just pass the directory where the JSON file resides to Fable.
If you omit the path, the compiler will assume it's in the current directory.
1:
|
|
Project references can be passed using a plain object:
1: 2: 3: 4: 5: 6: |
|
There are some options exclusive to fableconfig.json
.
prebuild
, postbuild
and onwatch
are accepted. For example, if you want
to run tests defined in the npm package.json
file after the build you can write.
1: 2: 3: 4: 5: |
|
fable --target production
.
1: 2: 3: 4: 5: 6: 7: 8: |
|
When using a node package.json
file, it's also possible to specify the minimum
version of Fable required to compile the project.
1: 2: 3: 4: 5: |
|
Fable's core library must be included in the project. When targeting node or using a module bundler you only need to add the dependency:
1:
|
|
If targeting the browser and using AMD instead, you can load Fable's core lib with require.js as follows:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: |
|
When not using --ecma es2015
or --module es2015
(see below), after going through Babel pipeline
the code won't include any syntax foreign to ES5. However several ES2015 classes (like Symbol
)
are used so it's advisable to include a polyfill like core-js
to make sure the code works fine in any browser.
You can include the polyfill in a script
tag in your HTML file before loading
the generated JS code like:
1:
|
|
Or you can import it directly in your F# code if you're using a bundler like Webpack or Browserify right before the entry point of your app.
1:
|
|
The polyfill is not necessary when targeting node 4.4 or above. Babel includes its own polyfill with a lazy-sequence generator, but this is not needed as one is already included in [fable-core.js]https://github.com/fsprojects/Fable/blob/master/import/core/fable-core.js).
The compiler will keep the file structure of the F# project, wrapping each file in a ES2015 module.
According to the --module
argument (see above), these modules can be transformed again by Babel to
umd (the default), amd, commonjs, or not at all.
In the browser, when not using a bundler like Webpack or Browserify, you'll need a module loader like require.js to start up the app.
When a F# file makes a reference to another, the compiler will create an import statement in the generated Javascript code. You can also generate imports by using the Import attribute.
As JS must import external modules with an alias, there's no risk of namespace collision so, for convenience, the compiler will use the minimum route to access external objects. Meaning that if you have a F# file with one root module:
1: 2: 3: |
|
To access myProperty
the generated code will import the file with an alias, say $import0
,
and directly access the property from it: $import0.myProperty
. The route has been eluded
as it's not necessary to prevent name conflicts. In the same way, if you have a file
with two modules:
1: 2: 3: 4: 5: 6: 7: |
|
This time the compiler will omit the namespace but keep the F# module names, as they're necessary to prevent name conflicts in the same file:
1:
|
|
You can debug the generated JS code normally. Also, if you pass the sourceMaps
option to the compiler, it'll be possible to debug the F# code (with some limitations).
This is automatic for browser apps. For node, you'll need a tool like node-inspector
or a capable IDE. In the case of Visual Studio Code, you can find instructions here
(see Node Debugging > JavaScript Source Maps).
You can use any JS testing library to write tests for your project, but to make it easier to share code across platforms, a plugin is available to make NUnit tests compatible with Mocha and this is what Fable uses for its own tests. The tests are compiled and run automatically when building the project:
1: 2: |
|
The most commonly used attributes (TestFixture
and Test
) and their respective
SetUp
/TearDown
counterparts are implemented. For assertions, however, only
Assert.AreEqual
is available. But more features will be available soon.
Note: As attributes are only read by name, it's possible to use custom-defined attributes without the
NUnit
dependency if needed.
For Visual Studio users, there's a similar plugin to convert Visual Studio Unit Tests to Mocha.
There are some samples available in the repository and you can also download them from here.
Every sample includes a fableconfig.json
file so they can be compiled just by running
the fable
command in the sample directory. Just be sure to install the npm dependencies
the first time.
1: 2: |
|
Now it's your turn to build a great app with Fable and show it to the world! Check Compatibility and Interacting with JavaScript to learn what you need to take into account when diving into JS.