Fable Loader is a Webpack loader that enables seamless integration of F# code compilation through the Fable compiler into JavaScript build pipelines. It serves as a bridge between Webpack's module loading system and the Fable F#-to-JavaScript compiler, allowing developers to include F# source files (.fs, .fsx, .fsproj) in their Webpack builds.
npm install fable-loader fable-compiler @babel/coreThe loader is configured through Webpack configuration rather than direct imports:
// webpack.config.js
module.exports = {
module: {
rules: [{
test: /\.fs(x|proj)?$/,
use: "fable-loader"
}]
}
};Create a webpack.config.js file to configure the loader:
var path = require("path");
module.exports = {
mode: "production",
entry: "./src/App.fsproj",
output: {
path: path.join(__dirname, "./public"),
filename: "bundle.js",
},
devServer: {
contentBase: "./public",
port: 8080,
},
module: {
rules: [{
test: /\.fs(x|proj)?$/,
use: "fable-loader"
}]
}
};With loader options:
module.exports = {
module: {
rules: [{
test: /\.fs(x|proj)?$/,
use: {
loader: "fable-loader",
options: {
babel: {
presets: ["@babel/preset-env"]
},
define: ["PRODUCTION"],
typedArrays: true,
clampByteArrays: false
}
}
}]
}
};Fable Loader operates as a standard Webpack loader with the following key components:
The main loader function that processes F# files and returns compiled JavaScript.
/**
* Main webpack loader function for processing F# files
* @param {Buffer} buffer - File content as buffer (raw loader)
* @returns {void} - Result passed via async callback
*/
function Loader(buffer) {
// Implementation handles compilation and returns via this.async() callback
}
// Loader configuration
Loader.raw = true; // Indicates binary input handlingOptions passed through Webpack loader configuration:
interface LoaderOptions {
/** Babel transformation options applied to compiled F# code */
babel?: BabelOptions;
/** Compilation constants passed to F# compiler */
define?: string[];
/** Translate numeric arrays as JS Typed Arrays (default: true) */
typedArrays?: boolean;
/** Translate byte arrays as Uint8ClampedArray (default: false) */
clampByteArrays?: boolean;
/** Additional options passed to compiler */
extra?: Record<string, any>;
/** CLI options for fable-compiler */
cli?: CliOptions;
}
interface BabelOptions {
/** Babel presets to apply */
presets?: string[];
/** Babel plugins to apply (merged with built-in plugins) */
plugins?: any[];
/** Source map configuration */
sourceMaps?: boolean;
/** Source file name for source maps */
sourceFileName?: string;
}
interface CliOptions {
/** Additional CLI arguments for fable-compiler */
[key: string]: any;
}Usage Examples:
// Basic configuration
{
test: /\.fs(x|proj)?$/,
use: "fable-loader"
}
// With options
{
test: /\.fs(x|proj)?$/,
use: {
loader: "fable-loader",
options: {
babel: {
presets: ["@babel/preset-env"],
plugins: ["@babel/plugin-proposal-class-properties"]
},
define: ["DEBUG", "BROWSER"],
typedArrays: true,
clampByteArrays: false,
extra: {
optimizeFSharpAst: true
}
}
}
}Supported F# file extensions:
/** Supported file extensions pattern */
const SUPPORTED_EXTENSIONS = /\.fs(x|proj)?$/;
/** File types processed by the loader */
type SupportedFileTypes =
| ".fs" // F# source files
| ".fsx" // F# script files
| ".fsproj" // F# project filesThe loader processes files through the following pipeline:
interface CompilationMessage {
/** Source file path */
path: string;
/** Project root directory */
rootDir: string;
/** Compilation constants */
define: string[];
/** Enable typed arrays translation */
typedArrays: boolean;
/** Enable clamped byte arrays */
clampByteArrays: boolean;
/** Additional compilation options */
extra: Record<string, any>;
}
interface CompilationResult {
/** Compiled JavaScript AST or error message */
error?: string;
/** File dependencies for Webpack tracking */
dependencies?: string[];
/** Compilation logs by severity */
logs?: {
error?: string[];
warning?: string[];
info?: string[];
};
/** Source file name for source maps */
fileName?: string;
}The loader handles various error conditions:
/** Error types handled by the loader */
type LoaderError =
| "FABLE_SERVER_PORT_ERROR" // Incompatible with dotnet-fable CLI
| "COMPILATION_ERROR" // F# compilation failed
| "BABEL_TRANSFORM_ERROR" // Babel transformation failed
| "DEPENDENCY_ERROR" // File dependency resolution failed
/** Error reporting through Webpack */
interface ErrorReporting {
/** Emit compilation error */
emitError(error: Error): void;
/** Emit compilation warning */
emitWarning(error: Error): void;
/** Enable/disable caching based on error state */
cacheable(cacheable: boolean): void;
}The loader automatically applies Fable-specific Babel plugins:
/** Built-in Babel plugins for Fable transformations */
const CUSTOM_PLUGINS = [
"fable-babel-plugins/getRemoveUnneededNulls",
"fable-babel-plugins/getTransformMacroExpressions"
];The loader automatically detects development mode and adds the "DEBUG" compilation constant when webpack.mode === "development".
Source maps are generated when enabled in Webpack configuration:
// Enable source maps in webpack config
module.exports = {
devtool: 'source-map', // or other source map options
// ... other config
};The loader handles source map generation by:
sourceMaps: true in Babel options when enabledThe loader integrates with Webpack through:
this.addDependency() for F# file dependencies