This project shows how to create a "conventional" server-side-rendered HTML app with client-side JavaScript using F# for both server and client. This approach may fit for projects using technologies such as HTMX.
- Client - Contains client-side specific F#.
- Server - Contains ASP .NET server code using Giraffe + Saturn.
- Shared - Contains shared F# to be used on both client and server.
- Add a package.json file and install to create the required package-lock.json file. This file contains Vite, as well as some configuration recommended in the official Vite docs for "library mode".
- Add the Fable tool (see dotnet-tools.json).
This folder contains a standard F# console application with the following modifications:
- Add the following node to the
fsproj
file:<DefineConstants>FABLE_COMPILER</DefineConstants>
- You can compile the project using:
This will compile the project and put the raw JS outputs into the
dotnet fable --cwd src/client -s -o transpiled
transpiled
folder. - Configure Vite using the appropriate configuration file. This file instructs vite to process the
transpiled
folder and put the bundled + minified outputs in thesrc/server/dist
folder. You can run vite with:cd src/client npx vite build
- You can run both Fable and Vite together:
dotnet fable --cwd src/client -s -o transpiled --run npx vite build
This folder contains a standard console application and uses Giraffe.ViewEngine to dynamically build HTML on the server. Key elements required for accessing the Fable-rendered JS are:
- Serve up Fable-rendered JS
use_static "dist"
- Import Fable-rendered JS
head [] [ script [ _type "module"; _src "app.js" ] [] ]
- Build client assets and store results in Server static files folder:
dotnet fable watch --cwd src/client -s -o transpiled --run npx vite build --watch
Note the uses of
watch
and--watch
, which will rebuild and rebundle the JS whenever client F# changes. You will still to reload the browser though! - Run the server (ideally in a separate terminal):
dotnet watch run
- Your client-side F# will now be available in HTML rendered by Giraffe e.g.
document.getElementById("btnClick").onclick <- (fun _ -> window.alert (Shared.Say.hello "isaac"))