Bolero icon indicating copy to clipboard operation
Bolero copied to clipboard

Suggestion: Feliz HTML View

Open jkone27 opened this issue 3 years ago • 10 comments

Would it be possible to make Feliz HTML view an option ?

Html.h1 42

Html.div "Hello there!"

Html.div [ Html.h1 "So lightweight" ]

Html.ul [
  Html.li "One"
  Html.li [ Html.strong "Two" ]
  Html.li [ Html.em "Three" ]
]

https://zaid-ajaj.github.io/Feliz/#/Feliz/Syntax

instead of the current "more verbose"

let myElement name =
    div [] [
        h1 [] [text "My app"]
        p [] [textf "Hello %s and welcome to my app!" name]
    ]

jkone27 avatar Jul 18 '20 14:07 jkone27

This could definitely be done! It would have to be a reimplementation though, rather than a direct use of the Feliz library, since Feliz itself uses React types directly.

Tarmil avatar Jul 18 '20 16:07 Tarmil

Hi,

Would this library help? https://github.com/dbrattli/Feliz.ViewEngine

It basically returns a HTML formatted string using Feliz more succinct syntax

CallumVass avatar Aug 24 '20 15:08 CallumVass

It looks like it still uses ReactElement as an intermediate step, so I doubt we can use it directly.

Tarmil avatar Aug 26 '20 13:08 Tarmil

I'm not sure if that's something I would even want. Is Feliz really less verbose? I see two different examples as a form of comparison, and I'm seeing that "Html." is mandatory before each element, which seems more verbose. I think there would have to be more proof or a better pitch to help realize if anything needs to be changed syntactically. I do like some of the aesthetics in certain areas in Feliz, but Bolero seems fine in the way it's been evolving.

sksallaj82 avatar Aug 26 '20 15:08 sksallaj82

Inline HTML is silly: changes to it need recompilation, which is prohibitively more expensive compared to just putting your UI pieces (small and large) into external HTML files and using the templating TP. I have seen people "rationalizing" the use of inline HTML: how it makes it easier to create components and whatever, but you can do all that with snippets you read via the TP too, while keeping the original speed/convenience benefit. All in all: I'd recommend to externalize your UI instead of trying to mingle it into your application code.

granicz avatar Aug 26 '20 16:08 granicz

I'm not sure if that's something I would even want. Is Feliz really less verbose? I see two different examples as a form of comparison, and I'm seeing that "Html." is mandatory before each element, which seems more verbose. I think there would have to be more proof or a better pitch to help realize if anything needs to be changed syntactically. I do like some of the aesthetics in certain areas in Feliz, but Bolero seems fine in the way it's been evolving.

The main appeal of Feliz syntax to me is the simpler formatting. The two list function raises questions about how to format your code, and it can get a little hairy once you have multiple attributes and multiple children each with their own attributes. There's a good discussion on the Feliz repo about this and Isaac posted a sample of how they format in the dual list style

https://github.com/Zaid-Ajaj/Feliz/issues/155#issuecomment-610816990

Yes, this is clean, but using Bolero myself on an internal app over the past year it took time and experience to settle on a similar format. It's also not trivial to do either, I find it's something I often have to actively think about while writing the code.

I haven't used Feliz or the Fable ecosystem myself other than playing with some sample apps, so maybe there's some hidden dragons in Feliz, but it seems like a win for writing readable view code without having to think about your formatting

The other pain point is maintaining two lists as things becomes more nested can be legitimately difficult. I still run into weird compiler errors from a missing ], even after months of experience and using VSCode + Rainbow Brackets. Not all editors have good support for coloring matching brackets either, so that's something to consider.

weebs avatar Aug 27 '20 14:08 weebs

Inline HTML is silly: changes to it need recompilation, which is prohibitively more expensive compared to just putting your UI pieces (small and large) into external HTML files and using the templating TP. I have seen people "rationalizing" the use of inline HTML: how it makes it easier to create components and whatever, but you can do all that with snippets you read via the TP too, while keeping the original speed/convenience benefit. All in all: I'd recommend to externalize your UI instead of trying to mingle it into your application code.

@granicz I can't speak much on the templating TP as I haven't used it, but I think it's a little unfair to categorize inline HTML as silly. The HTML DSL's created by the F# community was one of the things that drew me to the language when I discovered Giraffe. Most HTML derived view/template engines I've worked with end up being yet another non-trivial abstraction to learn, while being less expressive than what you see in a good language level DSL. That's not to say there's anything wrong with HTML templates, and from what I've seen Bolero's have a better design than most, but I personally get a lot of value from the DSL

Let's compare the friendList template example with the inline DSL

Templating

<p>Here are my best friends:</p>
<ul>
    ${Friends}
    <template id="Friend">
        <li>${Name}</li>
    </template>
</ul>
type FriendList = Template<"friendList.html">

// Use the nested template `Friend`.
let showFriend (name: string) =
    FriendList.Friend()
        .Name(name)
        .Elt()

// Use the main template (full HTML file minus the <template> tag).
let listFriends (names: list<string>) =
    FriendList()
        .Friends(forEach names showFriend)
        .Elt()

Inline

let showFriend (friend: string) =
    li [] [ text friend ]

let listFriends (names: string list) =
    concat [
        p [] [ text "Here are my best friends:" ]
        ul [] [ forEach names showFriend ]
    ]

To do this with templates you have to understand the inline HTML concepts, as well as:

  • Type Providers
  • Holes
  • Nested templates

That being said, templates do provide their own advantages, and they do seem like they're implemented well in Bolero. I think your point about separating view code from the application is particularly interesting. Application logic rarely finds its way into our view functions, but it has before and templates creating an explicit barrier is appealing.

For hot reloading, that seems like more of a technical problem than an abstraction issue. Fable React already has hot reloading for their HTML DSL if you can serialize your app model, and from what I understand you still need to rebuild a Bolero app with templates whenever app logic changes anyway.

weebs avatar Aug 27 '20 15:08 weebs

@weebs Yes, hot reloading code changes is a technical problem and the situation around it will improve over time, but currently you need to recompile your full app and it takes time. Going the templating way helps deciding on the right model types early on, and most of the subsequent UI changes can thus be applied in a streamlined, efficient manner.

Most real-life apps will have sophisticated, deeply structured UIs, and experimenting with enhancements and even replacing large parts of the UI is often a dreaded requirement. Having to do that over inline HTML will be a massive hit.

granicz avatar Aug 27 '20 17:08 granicz

In all honesty, although I agree with @granicz, in this case, because there are no inline F# within HTML templates like there is in Blazor, it makes using inline HTML more intuitive. There is more outside the box mentality to get things to work with templates than there would be using inline HTML. It's unfortunate yet necessary. My rule of thumb is, create templates as much as you can first, where changes are to the values of the DOM element, if there's any kind of logical flow that determines considerable changes to the DOM elements themselves, then inline HTML is the way to go.

sksallaj82 avatar Sep 03 '20 21:09 sksallaj82

I am experimenting this kind of project: https://github.com/slaveOftime/Fun.Blazor

I made couple of helper functions like html.inject to create a component and inject service like ComponentHook which can manage observable state and lifecycle event and no elmish style needed. Of course we like elmish we can still use elmish style model. I also made an html.watch to check the state of chanages and only rerender if some data changed.

Just for fun now, not production ready 😂

Here is a docs link: https://funblazor.slaveoftime.fun/helper-functions

albertwoo avatar Jun 22 '21 11:06 albertwoo