Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Take Sutil towards the Svelte experience #96

Open
joshushmaximus opened this issue Dec 9, 2024 · 1 comment
Open

Take Sutil towards the Svelte experience #96

joshushmaximus opened this issue Dec 9, 2024 · 1 comment

Comments

@joshushmaximus
Copy link

Opening an issue to discuss/document this idea further:

I would love to see how far the Fable compiler plugins could take Sutil towards the Svelte experience - by which I mean no "Bind.el" or "disposeOnUnmount" boilerplate that we currently have in Sutil. Svelte does all this for you
[via: https://x.com/DaveDawkins/status/1850538811442229667]

I personally am not familiar with fable (or really f# that much tbh).
I get what you're saying that if you could analyze the code being generated at the right stage (what stage?), you could automatically generate more code and reduce the burder on the user. Svelte is already a compiler and so it does this, to do the same you'd have to extend fable somehow to be able to generate more AST nodes for these things that eventually need to be bind.el-d?

Is it like this?

sutil -> fable -> html/ts

and if we do this

sutil -> [bind-identification-and-emitter] fable -> html/ts

then the sutil part becomes more like svelte (and also just simpler).

Can you expound on this further?

Recommended approach?

Best fable plugin documentation? (here is what i found, first seemed most applicable to this task)

@davedawkins
Copy link
Owner

davedawkins commented Dec 9, 2024

Well, it's

F# -> Fable -> JS

Using Sutil, the F# you write looks like this:

let view() = 
    let model = Store.make 0

    Html.div [
        Ev.onUnmount (fun _ -> model.Dispose())
        Bind.el (model, fun m -> text (sprintf "Counter = %d" m))
        Html.button [
               text "+"
               Ev.onClick (fun _ -> model |> Store.modify (fun m -> m + 1))
        ]
    ]

The proposition for using plugins is to get closer to the above without any of the boilerplate

[<Sutil()>]
let view() = 
    let model = Store.make 0  // It's OK to be explicit about where our stores are defined

    Html.div [
        text (sprintf "Counter = %d" model)
        Html.button [
               text "+"
               Ev.onClick (fun _ ->  model <- model + 1 )
        ]
    ]

Note:

  • We stay explicit in definining the store
  • From then on, we treat model as if it had been defined as mutable variable of type int (eg 'let mutable model = 0')
  • The plugin's job is to spot these references to 'model' and then wrap them with the Sutil boilerplate (disposing when out of scope, Binding for value access, and Store.modify for update)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants