mdgriffith / elm-ui

What if you never had to write CSS again?
https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/
BSD 3-Clause "New" or "Revised" License
1.36k stars 111 forks source link

`Element.Lazy.lazyN` with similar elements produces a lot of duplicate styling #220

Open miniBill opened 4 years ago

miniBill commented 4 years ago

Current behavior When using Element.Lazy.lazyN with a lot of very similar elements, elm-ui produces a lot of duplicate style tags. This has impacts on browser layout time and generated html size.

SSCCE: https://ellie-app.com/8V4h63cpJnRa1 If you look at the generated html, you'll see three identical style tags.

I guess this is an architectural tradeoff, because the objective of lazy is not touching a node if at all possible, and this is why you chose to encapsulate dynamic styles inside the node itself.

I'm not 100% sure of how it could be solved. I guess that ideally you would use some way to "store" the styles inside the lazy Html node and "retrieve" them when visiting it, but this is impossible with the current elm/html APIs.

In my particular application the styles are mostly identical. Wild suggestion, not a clean API but might evolve into one:

miniBillUseCaseColumn : (a -> b -> item -> Element msg) -> item -> a -> b -> List item -> Element msg
miniBillUseCaseColumn viewRow prototype paramA paramB items ~=
    Element.column [] <| (Lazy.lazy3 stylesFor viewRow prototype) :: List.map (Lazy.likeLazy4ButWithoutTheStylesFrom prototype viewRow paramA paramB) items

While using prototype as a "style prototype": do not render it, but create a lazy node with only styles. Then, when you render the other items, you can skip all the styles already defined in the first item.

Another idea would be using the first element as prototype, iff present.

Versions

miniBill commented 4 years ago

I wonder if https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Containment could help? Definitely not an expert in CSS though

PedroHLC commented 2 years ago

We were using the lazy, believing it optimized a list with around 100 rows. Then suddenly, someone added 2000 rows to one, and viewing it would freeze the entire app for 30 seconds. According to Devtools, it was a single "Recalculating styles". It turns out removing the lazy made it take less than 800ms.