luwes / sinuous

🧬 Light, fast, reactive UI library
https://sinuous.netlify.app
1.04k stars 34 forks source link

Template Examples #108

Closed theSherwood closed 4 years ago

theSherwood commented 4 years ago

@luwes I've been looking at the template package, which seems interesting, but I can't seem to get it to work with conditionals. Does it work with conditionals and do you have an example of that?

ryansolid commented 4 years ago

I'm going to throw on. Since I've been curious about this for a long time. This by far the most interesting feature of Sinuous to me (mostly as it is the most different from what I do with Solid). Solid's html tag I Just-in-Time compile the template into something very similar to what I do with the JSX, which means incredible performance (Maybe like a 3% hit over precompiled JSX). But it also means code bloat because I'm basically shipping htm in the client code. It's almost 5kb extra minified on its own! The benefit of course is that it is much faster than than any HyperScript version and the user just gets this optimization for free without thinking about it. They just write the code like normal and it is optimal. The same uncompiled html tagged code for Solid should be about 15% more performant (in something like JS Frameworks Benchmark).

See https://medium.com/better-programming/the-fastest-way-to-render-the-dom-e3b226b15ca3?source=friends_link&sk=5ae1688dde789e46cecf5c976e708da5. Keep in mind I'm using Solid's slower Proxy in all those examples except Solid Signals so the HyperScript/Tagged Template versions should be about 5% faster.

Now Sinuous neck and neck with compiled approaches on the benchmark. Why is that? Sinuous html runs on HyperScript which is almost identical to Solid's and that on its own is much slower(still faster than like Preact, but slower than libraries like Inferno or uhtml). However, the template mechanism allows Sinuous to escape the multicast nature of observables and computations and with a special syntax use a similar at runtime construction technique. This template approach has a 2nd benefit in that it doesn't have to worry about disposal in the same way so it tends to be more performant when removing rows from a table. It removes almost all reactive overhead making it about the same something like mikado, or stage0.

It would be really helpful to understand the limitations and restrictions here. Can they be nested? Can I build my whole view with nested templates? Nested Components? Nested conditionals and lists? Could templateing everything be a compilation advantage for htm? Or is this reserved a special purpose tool to optimize specific scenarios where you might need to repeat the same thing in a large list?

luwes commented 4 years ago

sorry for the slow response, it's been a while since I worked on the template module. trying to remember how it all worked :) great questions though.

I'll try to put together an example, I think conditionals should work. One extension I built on top of template is the sinuous/render module. it works like lit-html.

mm looking at the code of render this is pretty much what you're after I think. have a look:

https://github.com/luwes/sinuous/blob/d2b979e34ae525befc2f98c610ab08b5e21b18b5/packages/sinuous/render/test/render.js#L124-L143

some more context on sinuous/render: https://github.com/luwes/sinuous/issues/58

ryansolid commented 4 years ago

I see that makes sense. But those components would need to be wrapped in a computation to update if they were tied to reactive data. That's perfectly fine. It's just a little bit different.

The template mechanism is still able to do fine-grained updates if I understood properly with those helper wrappers. In that it builds a proxy of sorts. So you could say update a row label without rerunning the whole list. Does that mechanism support nesting?

luwes commented 4 years ago

ah right, no inline it doesn't support conditionals. it would have to be added as a value of the template data. that's not so user friendly. https://components.studio/edit/GZOlHjjvYJIB0e8IdQ7Q

ryansolid commented 4 years ago

Oh ok, that makes sense. Basically there are no expressions in the template so you basically need to set it as an observable. Ok well good to know. Doable in a pinch but not exactly general purpose. Cool thanks.

Dan-Do commented 3 years ago

ah right, no inline it doesn't support conditionals. it would have to be added as a value of the template data. that's not so user friendly. https://components.studio/edit/GZOlHjjvYJIB0e8IdQ7Q

Can we create a nested template like this:

const PhoneLog = template(() => html`
<div class="card col-md-4 col-sm-6">
    <h5 class="card-header d-flex justify-content-between">
        <a href="/person?q=${t('phone')}">${t('phone')}</a>
        <a href="tel:${t('phone')}"><i class="fas fa-phone"></i></a>
    </h5>
    <div class="card-body">${t('entries').map(e => template(() => html`
        <p class="card-text"><strong>${t('time')}:</strong></p>`)(e))}
    </div>
</div>`);