Installation
Partas.Solid has two NuGet packages:
- Partas.Solid, the DSL and the bindings.
- Partas.Solid.FablePlugin, the Fable compiler plugin that turns your F# into JSX.
Partas.Soliddepends on it.
Fable writes .jsx files, and a bundler such as Vite runs the Solid JSX compiler over them, so you need both a .NET and a Node toolchain.
Requirements
| Tool | Version |
|---|---|
| .NET SDK | 10 recommended. Partas.Solid targets net8.0, but it references FSharp.Core 10 |
| Fable | 5.x. The repository pins the tool at 5.13.0 |
| Fable.Core | 5.2.0, a dependency of Partas.Solid |
| Node | 22.12 or later |
The .NET side
1. Install Fable
dotnet new tool-manifest
dotnet tool install fable --version 5.13.0
2. Build the 3.0 packages
Clone the repository, check out the Solid 2 branch, and pack both packages into a folder:
git clone https://github.com/shayanhabibi/Partas.Solid.git
cd Partas.Solid
git checkout solid2rc
dotnet pack Partas.Solid.FablePlugin/Partas.Solid.FablePlugin.fsproj -c Release -o ../partas-feed
dotnet pack Partas.Solid/Partas.Solid.fsproj -c Release -o ../partas-feed
3. Add the local feed
Add a nuget.config next to your solution:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="partas-local" value="../partas-feed" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
4. Reference Partas.Solid
dotnet add package Partas.Solid --version 3.0.0
If you use Paket, add nuget Partas.Solid 3.0.0 to paket.dependencies along with a source line for the feed folder, then run paket install.
Partas.Solid brings in Partas.Solid.FablePlugin, Fable.Core 5.2.0, Fable.Browser.Dom 2.20.0, Xantham.Fable.Core.TS and FSharp.Core 10.
The npm side
Solid 2 is a release candidate, so pin the exact versions Partas.Solid 3.0 is tested against:
npm install solid-js@2.0.0-rc.9 @solidjs/web@2.0.0-rc.9
npm install --save-dev vite@8.3.1 @solidjs/vite-plugin@3.0.0-next.44 @solidjs/compiler@2.0.0-rc.9 @solidjs/babel-plugin@2.0.0-rc.9
Or in package.json:
{
"type": "module",
"dependencies": {
"@solidjs/web": "2.0.0-rc.9",
"solid-js": "2.0.0-rc.9"
},
"devDependencies": {
"@solidjs/babel-plugin": "2.0.0-rc.9",
"@solidjs/compiler": "2.0.0-rc.9",
"@solidjs/vite-plugin": "3.0.0-next.44",
"vite": "8.3.1"
},
"overrides": {
"@solidjs/compiler": "2.0.0-rc.9",
"@solidjs/babel-plugin": "2.0.0-rc.9",
"solid-js": "2.0.0-rc.9",
"@solidjs/web": "2.0.0-rc.9"
}
}
The overrides block stops npm from pulling in a second, different Solid release (of solid-js, @solidjs/web or the compiler) through the Vite plugin.
In Solid 2 the web runtime moved from solid-js/web to @solidjs/web, which provides render, hydrate, Portal and Dynamic. In F# they are in the Partas.Solid.Web namespace.
A minimal vite.config.js that picks up Fable's output:
import { defineConfig } from "vite";
import solid from "@solidjs/vite-plugin";
export default defineConfig({
plugins: [
solid({
include: ["**/*.jsx"],
exclude: ["node_modules/**", "**/fable_modules/**"]
})
]
});
Mounting the app
Mount the root component with render. It returns a function that disposes the app.
module App
open Partas.Solid
open Partas.Solid.Web
open Browser.Dom
[<SolidComponent>]
let App () =
h1 () { "Hello from F#" }
render ((fun () -> App ()), document.getElementById "root") |> ignore
Bindings and Femto
Some binding packages carry npm metadata for Femto, which can then install their npm dependencies for you. Bindings that target Solid 1.x will not work with Solid 2. See the ecosystem for what has been ported.
Compiling
Pass these flags to Fable:
dotnet fable -e .fs.jsx -c Release [--typedArrays false]
| Flag | Why |
|---|---|
-e .fs.jsx | The plugin emits JSX, so Fable must write files with a .jsx extension. The Solid compiler then reads them. |
-c Release | F# and Fable produce a different AST in Debug and Release. The plugin was built against the Release AST. Pass -c Release every time, including under dotnet fable watch, which otherwise compiles in Debug. |
--typedArrays false | Fable compiles numeric arrays to typed arrays, so an int[] becomes an Int32Array. Some libraries expect a plain array and break on typed arrays. Turn them off with this flag, or box the values ([\| box 5 \|]) where it matters. |
Next
- Overview: the two ways to write a component.
- Oxpecker DSL: how elements, attributes and children are written.
- Common issues: what to check when the output looks wrong.
- Migrating to Solid 2: if you are coming from Partas.Solid 2.x.
