SuaveIO / suave

Suave is a simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition.
https://suave.io
Other
1.32k stars 198 forks source link

have Fable compiler support Suave F# webserver for cross language development #778

Open jkone27 opened 8 months ago

jkone27 commented 8 months ago

would be grate if suave could be the cross language web platform we all dream of, i tried to compile it with fable on a single fsx script (dotnet fable), got this error, seems the fish custom operator is not defined, maybe there is work arounds..

Suave_Operators_op_GreaterEqualsGreater

here the full code, to be compiled with dotnet fable (defaults to javascript)

// npm init type module, npm add express, dotnet tool install fable, dotnet fable express.fsx, node express.fs.js
#r "nuget: Suave"
#r "nuget: Fable.Core"
#r "nuget: Feliz.ViewEngine"
#r "nuget: Feliz.ViewEngine.Htmx"
#r "nuget: Feliz.Bulma"

open Suave
open Suave.Filters
open Suave.Operators
open Suave.Successful
open Suave.Control
open Feliz.ViewEngine
open Feliz.ViewEngine.Htmx

module View =

    let buttonOne =
        Html.button [
            prop.className "button is-primary"
            prop.text "NEW BUTTON"
            hx.post "/button-one"
            hx.swap "innerHtml"
        ]

    let buttonOneHtml =
        buttonOne 
        |> Render.htmlView

    let view =
        Html.html [
            Html.head [
                Html.link [
                    prop.rel "stylesheet"
                    prop.href "https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"
                ]
                Html.script [
                    prop.src "https://unpkg.com/htmx.org@1.9.10"
                ]
            ]
            Html.body [
                Html.h1 [
                    prop.className "hero is-primary"
                    prop.text "Hello Feliz from express!" 
                ]
                Html.section [
                    Html.p "here is a button..."
                    buttonOne
                ]
            ]
        ]
        |> Render.htmlView 

    let buttonTwo =
        Html.button [
            prop.className "button is-error"
            prop.text "FROM HTMX"
            hx.post "/button-two"
        ]
        |> Render.htmlView 

let mainApp =
    (Suave.Filters.path "/") 
    >=> (Suave.Successful.OK View.view)

let getResponseApp = 
    (Suave.Filters.path "/button-one")
    >=> (Suave.Successful.OK View.buttonOneHtml)

let click2Response = 
    (Suave.Filters.path "/button-two")
    >=> (Suave.Successful.OK View.buttonTwo)

let app =
    Suave.Filters.GET
    >=> (Suave.WebPart.choose [ 
        mainApp
        getResponseApp
        click2Response
    ])

Suave.Web.startWebServer Suave.Web.defaultConfig app
njlr commented 6 months ago

For Fable to work:

  1. The source code needs to be bundled in the package.
  2. The code must only call functions that Fable supports.

(1) is quite easy to fix but (2) is significant work.

The approach would be to isolate the platform code that is .NET specific and provide the same API using Node.js built-ins.

To get an idea of how much code this is, see the error message from running dotnet fable ./src/Suave/Suave.fsproj.

e.g.

./src/Suave/WebSocket.fs(225,29): (225,41) error FABLE: System.Memory`1..ctor (static) is not supported by Fable