Desktop apps in HTML and F#
Tags: fsharp, wpf, webdev
Published: 2021-08-30 22:21:20

_I created a starter desktop app using HTML/CSS/F# for the front end and F# .NET for the back end. All hosted in WPF._

> This post mostly covers the "why". Hit the [repo](https://github.com/kspeakman/FSharpHtmlDesktopApp) if you just care about "how".

Developers at my company are mostly coding for the web. But once in a while we need to create a Windows desktop app. Because some situations require direct access to hardware and running software. But a big challenge with desktop apps is their UI tech.


## Why web UI?

Our devs have a lot of skill investment in web tech. And I don't mean React and Webpack -- although we know a little about those. I'm talking about the open standards of HTML, CSS, and Javascript. Because of standardization I can use web tech to make a consistent-looking UI, no matter what device is consuming it.

Meanwhile desktop UI techs tend to be opinionated and proprietary. We develop for desktop infrequently, so non-transferrable learning investments into desktop UI tech is a hard sell.


## Which web UI?

It has been possible to use web tech in Windows desktop apps for a while. Problem was, the solutions were full of compromises.

UWP, for example, allows you to build apps using web tech. But it runs sandboxed, making it hard to do the one job it needs to do: direct access. WebBrowser and WebView have also existed for a while. They are embeddable browsers for WinForms/WPF apps. But they use IE or EdgeHTML for rendering. Need I say more?


### Why not Electron?

The elephant in the room is Electron. The main downside for us is the Node.js back-end. Some of our vendors do not provide libraries for it. And even if it can be awkwardly made to work using unsupported libraries, Node requires us to work in Javascript.

> Electron's cross-platform support is probably its biggest benefit... but we don't need that.

Yes, earlier I did list Javascript as a positive thing for web tech. I do like the standardized browser APIs available thru JS -- Media, Storage, Intl, etc. But let's be honest, JS also has footguns baked into the standard. And I strongly prefer to use something else: F# on .NET.


### WebView2

WebView2 is an embeddable browser for WinForms/WPF like WebView before it. WebView2 uses Chromium-based Edge for rendering. So unlike its predecessor, WebView2 keeps evolving with the web standards. And I get to use F# on .NET.

We have actually used WebView2 since shortly after its release. We used it to show HTML5 video content in a computer lab. It was a rush job and WebView2 was only a month old at the time. I wasn't ready to trust it, much less consider it for other uses. And I forgot about it.

Then earlier this year, Microsoft announced [Blazor Desktop](https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-1/#blazor-desktop-apps) based on WebView2. And then I found out Microsoft Teams is [ditching Electron for WebView2](https://twitter.com/rishmsft/status/1408085784016539653). This got me to take another look at it. One thing led to another and over the weekend I created a working demo: a WPF app with an F# web UI and F# .NET backend API.


## How does it work?

The UI is a webpack-built JS app just like you would expect. It uses F# and Elmish for a functional (as in functional programming) UI. The F# code gets transpiled to JS and uses React for DOM rendering.

The "backend" API is an F# library. In this starter app, the backend is very simple. So there is nothing interesting to demonstrate yet.

A messaging library is shared between the front and back. It defines all the requests and responses that can pass between them. 

The host application is WPF. WinForms would work too. Either way there is not much to it. The only control is the WebView2 control. And about 40 lines of wiring code.

For communication between the JS front and .NET back, I used WebView2's string-based messaging. Each side gets some functions to send/receive messages. Types from the messaging library are converted to JSON strings for transport.


## The repo

{% github kspeakman/FSharpHtmlDesktopApp no-readme %}


## Closing thoughts

This was a fun weekend project. It has a lot of promise to make desktop apps more manageable for our dev team. I'll try it out this coming month and let you know how it goes. For now, let me know what you think about making desktop apps with web tech and F#.