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

[#249] Use computation expression syntax for HTML #253

Merged
merged 18 commits into from Apr 9, 2022
Merged

[#249] Use computation expression syntax for HTML #253

merged 18 commits into from Apr 9, 2022

Conversation

Tarmil
Copy link
Member

@Tarmil Tarmil commented Feb 20, 2022

Replace the list-based syntax with a computation expression-based syntax. This enables much better inlining of the rendering (see the corresponding issue #249).

// v0.18 syntax
let body =
    div [ attr.id "test" ] [
        text "Hello "
        b [ on.click (fun _ -> printfn "Click!") ] [ text "Bolero" ]
    ]

// CE syntax
let body =
    div {
        attr.id "test"
        "Hello"
        b { on.click (fun _ -> printfn "Click!"); "Bolero" }
    }
  • Replace the Node and Attr unions with delegates that perform the rendering directly.
  • Add a computation expression to build elements.
    • Ensure the order of the content of elements: Attr - Key - Ref - Children.
      This is done by having the right set of Combine methods on the CE builder (for example there's a Combine(Attr, Children) but no Combine(Children, Attr).
  • Add a computation expression to build components.
    • Note: thanks to the inlining, this seems to incidentally fix Trimming removes method required by Bolero.Html.comp #250 at least in some cases. This needs to be investigated further and confirmed that it is fixed in all cases.
    • Ensure the order of the content of components.
      Unlike elements, component children are rendered inside an Attr named ChildContent.
    • Add a computation expression to build components with some built-in attributes (such as lazyComp* and navLink).
    • Implement virtualize as a computation expression, using let! to pass the item, for example:

      Bolero/tests/Client/Main.fs

      Lines 293 to 302 in 27a0101

      virtualize.comp {
      virtualize.placeholder <| fun p ->
      div { attr.style "border: solid 1px gray;"; $"Placeholder #{p.Index}" }
      let! text = virtualize.itemsProvider <| fun r ->
      ValueTask<ItemsProviderResult<_>>(task {
      do! Task.Delay 1000
      return ItemsProviderResult([r.StartIndex..r.StartIndex+r.Count-1], 2000)
      })
      div { attr.style "border: solid 1px gray;"; $"Item #{text}" }
      }
  • Add a computation expression for concat.
  • Replace the value empty with a function empty() so that it can be inlined.
  • Allow putting a string directly in the computation expressions without the text function.
  • Benchmark the rendering of old vs new syntax.
  • Configure trimming so that unused element builders aren't included in the served assembly.

⚠️Breaking change: this system doesn't allow the merging of classes from multiple attr.classes attributes like v0.18- does.

  • Mark attr.classes as obsolete? It doesn't have much added value compared with attr.``class`` if different class lists aren't merged anymore.

@Tarmil Tarmil marked this pull request as draft February 20, 2022 15:35
@Tarmil
Copy link
Member Author

Tarmil commented Mar 2, 2022

  • Ensure the order of the content of components.
    Unlike elements, component children are rendered inside an Attr named ChildContent.

This is turning into a bigger pain point than I expected. It is forcing us to have Attr - Children - Key - Ref as the order of items in a component. But it would be really counter-intuitive, from a user point of view, to enforce a different order in elements and in components...

The best solution I can see right now is to have a function that combines the Key and Ref, and then have the component builder's implementation of Combine(KeyAndRef, Children) swap the two in its implementation. This way, we can enforce the order Attr - KeyAndRef - Children in both elements and components.

@Tarmil Tarmil marked this pull request as ready for review March 3, 2022 14:28
@Tarmil
Copy link
Member Author

Tarmil commented Apr 9, 2022

This is turning into a bigger pain point than I expected. It is forcing us to have Attr - Children - Key - Ref as the order of items in a component. But it would be really counter-intuitive, from a user point of view, to enforce a different order in elements and in components...

The best solution I can see right now is to have a function that combines the Key and Ref, and then have the component builder's implementation of Combine(KeyAndRef, Children) swap the two in its implementation. This way, we can enforce the order Attr - KeyAndRef - Children in both elements and components.

As it turns out, there's an easier solution to this issue: the key can come before attributes. So we can have a Key - Attr - Ref - Children order, and have the component implementation swap the last two.

@Tarmil Tarmil merged commit 22d750c into master Apr 9, 2022
@Tarmil Tarmil deleted the inline branch April 9, 2022 16:32
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

Successfully merging this pull request may close these issues.

Trimming removes method required by Bolero.Html.comp
1 participant