How to run WebSharper F# examples

Most often, and in particular in the Examples section of this site, you will find WebSharper snippets and examples that define a WebSharper control such as:

namespace Samples
...
[<JavaScript>]
module HelloWorld =

    let Main () = ...

type HelloWorldViewer() =
    inherit Web.Control()
    
    [<JavaScript>]
    override this.Body = HelloWorld.Main () :> _

This section explains how you can run and test these controls, using the Hello World example as defined above.

Testing via single-page applications (SPAs)

Most of the examples on this web site do not require a server side, e.g. they come without an RPC-based backend. One of the easiest ways to run these examples is within a single-page application (SPA).

To embed the Hello World example in an HTML application, follow these steps:

  1. Create a new SPA application using the "Single-Page Application" project template.

  2. Open Client.fs and edit its content as follows:

  1. Keep the namespace declaration

  2. Override the rest of the file with the code from the example. You don't need to carry over the code for the HelloWorldViewer type. Instead, add the following lines at the end of the example module to execute the pagelet by appending it to a placeholder node with ID entrypoint (choose freely):

    let Run = (Main ()).AppendTo "entrypoint"

    With these changes, your code should look like this (with the namespace matching the one you created):

    namespace Bundle1

    open WebSharper open WebSharper.Html open WebSharper.Html.Client

    [] module HelloWorld =

      let Main () =
          let welcome = P [Text "Welcome"]
          Div [
              welcome
              Button [Text "Click Me!"]
              |>! OnClick (fun e args ->
                  welcome.Text <- "Hello, world!")
          ]
    
      let Run = (Main ()).AppendTo "entrypoint"
    

    WebSharper 3 is auto-initializing all module-level values after the page loads, so the generated content will be added to the DOM.

  3. Add the pagelet placeholder you used, in index.html before the generated JavaScript include:

    ...

    ...
  4. At this point, you should be able to compile your application and run it. Please note that this project template by default starts a web deployment and tries to open the root of the web application (instead of an actual HTML file), and will fail doing so. Instead, you should open index.html.

Testing via HTML applications

An alternative way to run examples on this site is by embedding them into a sitelet that generates an HTML application. Follow these steps:

  1. Create a new HTML application using the "HTML Application" project template.

  2. Open Client.fs and edit its contents as follows:

  1. Keep the namespace declaration

  2. Override the rest of the file with the code from the example. You don't need to carry over the code for the HelloWorldViewer type. Your code should look like (with the namespace matching the one you created):

    namespace HtmlApp1

    open WebSharper open WebSharper.Html open WebSharper.Html.Client

    [] module HelloWorld =

      let Main () =
          let welcome = P [Text "Welcome"]
          Div [
              welcome
              Button [Text "Click Me!"]
              |>! OnClick (fun e args ->
                  welcome.Text <- "Hello, world!")
          ]
    
  1. Open Main.fs and change the reference to the pagelet contained on the Home page:

    ...
    module Controls =
    
        [<Sealed>]
        type EntryPoint() =
            inherit Web.Control()
    
            [<JavaScript>]
            override __.Body =
                HelloWorld.Main() :> _
    ...
    
  2. You can now compile the application, navigate to bin\html and open index.html to see the Hello World snippet run.

This project template contains more code in Main.fs to manage an HTML template and two pages in the master sitelet. You can safely remove these unused parts and reduce Main.fs to the following code:

namespace HtmlApp1

open WebSharper.Html.Server
open WebSharper
open WebSharper.Sitelets

type Action =
    | Home

module Controls =

    [<Sealed>]
    type EntryPoint() =
        inherit Web.Control()

        [<JavaScript>]
        override __.Body =
            HelloWorld.Main() :> _

module Site =

    let HomePage =
        Content.PageContent <| fun ctx ->
            { Page.Default with 
                Title = Some "Home page"
                Body =
                    [
                        Div [new Controls.EntryPoint()]
                    ]
            }

    let Main =
        Sitelet.Content "/" Home HomePage

[<Sealed>]
type Website() =
    interface IWebsite<Action> with
        member this.Sitelet = Site.Main
        member this.Actions = [Home]

[<assembly: Website(typeof<Website>)>]
do ()

Testing via client-server applications

While most of the examples on this site are "client-only", a handful of them are actually client-server applications, such as the Remoting and the Chat examples.

To run these more complex examples, follow these steps:

  1. Create a new client-server application using the "Client-Server Application" project template.

  2. This project template features three separate files: Client.fs, Remoting.fs and Main.fs for the client, server, and putting-together sides of things. To keep things simple, you can remove Remoting.fs from your project, and keep both tiers in Client.fs.

  3. Open Client.fs and edit its contents as follows:

  1. Keep the namespace declaration

  2. Override the rest of the file with the code from the example. You don't need to carry over the code for the xxxViewer type. Your code should look like (with the namespace matching the one you created, and assuming you adapted the Chat example):

    namespace Website2

    ...

    module Chat = ...

      module Auth =
      ...
      module State =
      ...
      module Rpc =
      ...
    
      [<JavaScript>]
      module Ui =
          let ChatBox () =
          ...
    
      [<JavaScript>]
      let Main () = Ui.ChatBox()
    
  1. Simplify Main.fs as follows:

    namespace Website2
    
    open WebSharper.Html.Server
    open WebSharper
    open WebSharper.Sitelets
    
    type Action =
        | Home
    
    module Controls =
    
        [<Sealed>]
        type EntryPoint() =
            inherit Web.Control()
    
            [<JavaScript>]
            override __.Body =
                Chat.Main() :> _
    
    module Site =
    
        let HomePage =
            Content.PageContent <| fun ctx ->
                { Page.Default with 
                    Title = Some "Home page"
                    Body =
                        [
                            Div [new Controls.EntryPoint()]
                        ]
                }
    
        let Main =
            Sitelet.Content "/" Home HomePage
    
    [<Sealed>]
    type Website() =
        interface IWebsite<Action> with
            member this.Sitelet = Site.Main
            member this.Actions = [Home]
    
    type Global() =
        inherit System.Web.HttpApplication()
    
        member g.Application_Start(sender: obj, args: System.EventArgs) =
            ()
    
    [<assembly: Website(typeof<Website>)>]
    do ()
    
  2. You can now run your application.

Testing via ASPX markup

To test via ASPX markup, in addition to the steps outlined in the ASP.NET integration page, you need to configure your WebSharper control to be visible as an ASP.NET server control.

Assuming the Samples namespace as in the above code snippet, and WebSharperProject as the name of your assembly, you should add an entry in your Web.Config to reference this namespace, along with the desired tag prefix and the assembly that contains it.

It should look something like this:

<configuration>
    <system.web>
		<pages>
			<controls>
			...
				<add tagPrefix="samples"
					 namespace="Samples"
					 assembly="WebSharperProject"/>
			</controls>
			...

Once configured and having added the WebSharper script manager tag, you can embed your WebSharper control in your ASPX markup as:

<samples:HelloWorldViewer runat="server" />