π₯οΈ One F# Codebase. Website or Native Desktop App. You Pick at Deploy Time.
v3.2.0 adds a cross-platform desktop host to the template: a tiny Photino.NET shell that runs the same ASP.NET Core server in-process and shows the same Fable.Lit client in a native window β WebView2 on Windows, WKWebView on macOS, WebKitGTK on Linux.
No Electron. No bundled Chromium. No code changes between web and desktop.
β‘ The Headline: Web-Grade Hot Reload in a Native Window
Traditional .NET desktop UI (WPF, WinForms, Avalonia) means edit β compile β restart β re-navigate. The desktop host inherits the web stack's dev loop instead:
# Terminal 1 - the client dev server
cd MyApp/WebLit
npm run start# Terminal 2 - the desktop shell (hosts the server in-process)
cd MyApp/Desktop
dotnet runEdit your F# view code, hit save, and watch the native window update in under a second. Full Fable HMR, Elmish state preserved.
π¦ What's in the Box
- New
Desktopproject (~90 lines) β starts Kestrel in-process and opens a native window. In Release it binds a dynamic loopback port and serves the built client fromwwwrootnext to the exe: fully self-contained, no configuration. WebApi/WebApp.fsβ the server wiring, extracted into one parameterized builder shared by every host (web, desktop, or embedded). Your RPC implementations don't know or care which host they're running in.build.cmd PackDesktopβ publishes the desktop app + built client to.build/desktop/, ready to zip and ship.- Powered by Serde.FS 1.0.0-beta.4 β
MapRpcApinow self-initializes, so hosting the RPC server in-process requires zero bootstrap ceremony. The same typed client β server contracts work identically in a browser tab and a native window.
ποΈ Bonus: AutoCAD / Revit Add-in Recipe
The same architecture β in-process Kestrel + a WebView showing your Fable client β also works embedded inside host applications like AutoCAD and Revit (2025+). That means hot-reloadable web UI in a palette or dockable pane, with typed RPC calls marshaled onto the CAD API thread.
The full pattern (lifecycle, the ExternalEvent dispatcher bridge, WebView2 gotchas) is documented in docs/cad-addin-recipe.md.
π Getting Started
dotnet new install fable-lit-fullstack-template
dotnet new flft -n MyAppThe Desktop project is included in every new app β if you only want the website, just delete the folder.
π Also in This Release
- Fixed the README's install instructions (the short name is
flft) and dev command (npm run start). CatFactsBaseUrlmoved into baseappsettings.jsonso Production-environment hosts work out of the box.- Cross-platform notes: Windows uses the preinstalled WebView2 Runtime; Linux needs
libwebkit2gtk-4.1; macOS uses the built-in WKWebView. (Debug-mode HTTPS on macOS/Linux has a
documented workaround in the README.)
π‘ Why This Matters
The classic desktop F# dilemma: you want native deployment, but you also want a modern, fast-iterating UI stack. Now you don't choose. Start as a desktop app and become a website later (or vice versa) by changing nothing β WebApi, WebLit, and Shared are byte-identical between hosts. The deployment target is just a question of which ~90-line shell you run.