Skip to content

Conversation

@thetarnav
Copy link
Member

No description provided.

@chiefcll
Copy link
Contributor

chiefcll commented Aug 7, 2025

Looking cool. LMK when the TS are fixed up. Also want to put this in the main branch...

@elsassph
Copy link

elsassph commented Aug 7, 2025

Really curious what the intention is 😄

@thetarnav
Copy link
Member Author

@elsassph solid's universal.createRenderer api assumes dom-like api so it has to diff new and old children to detect changes in order, where to insert new elements and which to remove.
Lightning only needs to know which children were removed, update the el.children array as a whole, and set new parents.
I want to see if a simpler runtime could do the same with better performance and less bugs.
Currently there is a bug where sometimes children are reconciled incorrectly and removed children are still being rendered.
This experiment fixes that, but introduces some more, so it's not ready :D

@elsassph
Copy link

elsassph commented Aug 7, 2025

Maybe there's something related to L3 renderer, because we use Solid universal renderer with L2 and we aren't seeing such issues.

@thetarnav
Copy link
Member Author

The bug that I'm talking about has nothing to do with lightning renderer.
The added test reproduces it, and tests are using dom renderer instead of lighting.

@thetarnav
Copy link
Member Author

This experiment fixes that, but introduces some more, so it's not ready :D

One issue that it introduces currently is with using solid.untrack or an iife to run some code in jsx template.
For example:

<view>{(() => {
    const children = s.children(() => props.children)
    s.createEffect(() => {...})
    return children as any
})()}</view>

This gets compiled to

var el = s.createElement('view')
s.insert(el, () => {
    const children = s.children(() => props.children)
    s.createEffect(() => {})
    return children
})

And original solid runtime wraps each function in it's own effect,
In this case both () => {const children = ...} and accessing children gets wrapped with separate effects.
So when props.children update, only the children effect rerurns.

With my runtime everything happens under a single effect, so every time props.children updates, the entire effect has to rerun and s.children and s.createEffect gets created again.

The simple solution is to use /*@once*/ for solid to not treat the iife as something dynamic—as one should anyway probably.

<view>{/*@once*/(() => {
    const children = s.children(() => props.children)
    s.createEffect(() => {...})
    return children as any
})()}</view>

Matching solid current behavior in runtime would require wrapping each function in jsx children in a separate memo or effect, just as solid does.
I wonder if it's worth it if it's just needing /*@once*/ in rare cases.

@chiefcll
Copy link
Contributor

chiefcll commented Aug 7, 2025

I have never seen code written that way - usually I keep my JSX, JSX (ok with folks using once for those cases). But what about loops? Where there is a loop?

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.

3 participants