Hello, WebSharper!

      3 Comments on Hello, WebSharper!

In my previous post I was explaining why I chose WebSharper as my main topic for DSP 2017. If you haven’t read it yet, here’s the short answer: full-stack Web Dev, F#, and no JavaScript. So yesterday I put on my coding pants and got to work. More or less one hour later, I ended with a rather simple but functional website that looks like this:

(click on the GIF to enlarge)

As you can see, the website basically does just two things:
– it queries for your name, and then says ‘Hello!’ to you. This is done on the server side.
– it displays the number of times you click on the 2nd button. This is done on the client side.

All this in just about one hour? Not bad at all, especially for a noob like me! Let’s see in details what I did to get there. You can download the source code from my GitHub repo.

The initial setup

In order to use WebSharper, you need to install a couple of things first. Don’t worry, it won’t cost you a penny. Head down to their download page and click on the download link for your favourite editor. I’m personally using Visual Studio 2015 Community Edition that you can download for free from here.

Run the WebSharper.vsix file and follow the setup instructions. Once it is done, you should end up with a bunch of new templates in Visual Studio, under the following path:
Templates → Other Languages → Visual F#  → WebSharper

That’s a lot of different options and we will look at a few of them in coming posts. For now I decided to go with the Self-Hosted Client-Server Application, which basically represents a regular website with interactions between the server and the browser.With this option the web server consists of a single executable file (the Visual Studio project’s output is a console application).

As the description says, the website will be self-hosted using OWIN but WebSharper supports other hosting options like IIS and Suave. As I was lazy and didn’t want to do any extra configuration this seemed to me like the best choice.

Show us the code already!

You’re right, time to take a deeper look at the innards of the website. The project is rather small and consists of the following files:
of which only four will be of interest to us:

  • Main.fs
  • Main.html
  • Client.fs
  • Remoting.fs

Combined together they represent around 150 lines of code and HTML. That’s not a lot, and this includes comments, blank lines and open statements (the F# equivalent of using in C# or import in Java)!  It took me around 30 minutes to understand the relations and dependencies between each file, so let me guide you through the most interesting parts. You can browse the full files directly from the GitHub repo):


type EndPoint =
    | [<EndPoint "GET /">] Home

This type will list all endpoints (pages, URLs…) of your website. Here we just have one endpoint, which will be our Home page. It can be accessed via a HTTP GET call to the root URL of our website (http://localhost:9000/ in our case).

    [<Website>] // Main entry point for our application
    let Main =
        Application.MultiPage (fun context action ->
            match action with
            | Home -> HomePage context

This snippet defines our routing rules. Here the configuration says that when a HTTP GET call to http://localhost:9000/ is received, the server should respond by calling a certain HomePage function. This function is defined below:

let HomePage context =
        Templating.Main context EndPoint.Home "Hello WebSharper" [
            H2 [Text "Welcome to Hello WebSharper. What's your name?"]
            Div [ClientSide <@ Client.Main() @>]

The function defines the structure of our main page. The title of the page will be ‘Hello WebSharper’ and the page itself will consist of two HTML elements:

  • A h2 header containing the text ‘Welcome to Hello WebSharper. What’s your name?’
  • A div container with the ‘weird’ syntax below
Div [ClientSide <@ Client.Main() @>]

This simply says that the code from the Main function of the Client Module should be inserted within this particular div element. Here is the code of the Main function in question:


module Client =

    let Main () =
        let input = Input [Attr.Value ""] -< []
        let output = H1 [Text "Hello, Stranger...?"]
        let inputValue = H4 []
        let someStaticText = P []
        let mutable clickCounter = 1

        Div [

            Button [Text "Send to server"] // Sends a request to the server
            |>! OnClick (fun _ _ ->
                async {
                    inputValue.Text <- input.Value
                    let! data = Server.sayHelloAsync input.Value
                    output.Text <- data
                |> Async.Start

            Div [Attr.Class "hello"] -< [output]
            HR []
            Button [Text "Run some client-side action"] // Runs an action on the client side
                |>! OnClick (fun _ _ ->
                    someStaticText.Text <- sprintf "You clicked the button %d times." clickCounter
                    clickCounter <- clickCounter + 1

            Div [] -< [someStaticText]

There are two things to note here:

  1. The [<JavaScript>] attribute is part of WebSharper and explicitly tells the compiler that the whole logic of the Client module should be transpiled to JavaScript.
  2. The Main function just defines a bunch of other HTML elements. The most worthy of attention are the two buttons with their associated logic expressed via the OnClick functions.

The first button called ‘Send to server’ is actually making an asynchronous HTTP POST call to the server upon click.

async {
    let! data = Server.sayHelloAsync input.Value

The sayHelloAsync function is defined in our Remoting.fs file:


module Server =
    let sayHello usr = "Hello, " + usr + "!"

    let sayHelloAsync username =
        async { return sayHello username }

Note the use of the [<Remote>] attribute from WebSharper. It enables to call a function defined on the server-side directly from the client-side! Now, since the client-side code is transpiled from F# to JavaScript, let’s have a look at what happens under the hood when such function is called:

  1. The data passed to Server.sayHelloAsync is serialized to Json on the client-side (JavaScript).
  2. It makes an asynchronous call (HTTP POST) to the Server.sayHelloAsync on the server-side (JavaScript).
  3. The server deserializes the Json data and processes it (F#).
  4. The server serializes the answer to Json and sends it back to the client (F#).
  5. The client receives the data and processes it (JavaScript).

Now, I don’t know about you, but this seems pretty powerful to me! How much time do programmers normally waste on getting all those steps right? How many times did you have issues with Json serialization or deserialization, or simply getting the URL right? Not to mention contracts changing on either side of the wire. You can forget about all those problems here, as WebSharper takes care of it all for you. And this is the way it should be. I made another short GIF to illustrate what we’ve just described:

(click on the GIF to enlarge)

This post is getting pretty long already, let’s wrap up. We haven’t talked about the role of the Main.html file and HTML bindings in WebSharper just yet. so this will probably be featured in a future post. You will also notice I created another project called HelloWebSharper.Tests. We will surely be going over this subject as well.

I hope you guys liked this introduction! Don’t hesitate to leave a comment if you have any questions or comments.


3 thoughts on “Hello, WebSharper!

  1. Dawid

    Cool, technical stuff I can already see here 😉
    I’ve not been writing too much JavaScript personally, but this client-server remote calls and the whole transformation between JSON and JavaScript seems really nice.
    This technology is very interesting, waiting for the next posts 🙂

  2. Pingback: Overview of WebSharper’s templating engine – Part 1, Text holes – Youenn Bouglouan

  3. Pingback: Create a website quickly using F“ | StratCom

Leave a Reply

Your email address will not be published. Required fields are marked *