Automatic code extraction #2 – no $() wrappers #336
maiieul
started this conversation in
Proposals For Qwik
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
What is it about?
Automatically extracting inner helper functions inside components to reduce confusion, boilerplate and gotchas caused by QRL
$()wrappers. Instead of extracting into QRLs through$()wrappers, we can extract by changing the functions signatures, accepting an extra argument.The mental model shifts from "magic happens in
$()", to "magic happens incomponent$and hooks" – which is the actual place where it needs to happen in practice. With the former approach, the developer must learn to manually wrap functions with$()and how to deal with those boundaries, while with the latter the developer only needs to learn how to deal with thecomponent$and hooks boundaries.What's the motivation for this proposal?
Problems you are trying to solve:
The
$()API$()$()only accepts serializable closures (e.g. no classes or factory functions).The reason why we are currently forced to wrap inner helper functions with
$()is because those functions need to be extracted. They need to be extracted so that event handlers and children can call the functions directly without waking up other handlers/children. To do this extraction, we use QRLs, which in turn makes those functions lazy-loadable. We therefore need to let the developer know that the API is async, and we do that with the explicit$()wrapper. In theory though, inner helper functions don't need to be lazy-loadable and should actually be synchronous, because helper functions can only be called by an actual event handler (e.g.onClick$,useTask$,useVisibleTask$, etc.) and cannot be called on their own. Event handlers are the only nodes that really need to be lazy-loadable on demand.Goals you are trying to achieve:
Consider:
could be simplified into:
Notice that both the
incrementanddecrementfunctions now become synchronous, but thehandleClick$prop remains a QRL due to the optimizer 'one file transform at a time' constraint that we currently enforce.This would:
$(). Only the event handlers (e.g.onClick$) andcomponent$,useTask$,useVisibleTask$, etc. are marked with$, clearly expressing that they need to be lazy loaded boundaries.$()wrappers and resultingasync/awaitcalls.$().Solution
What do you propose?
Instead of extracting through QRLs, I explored automatically extracting all the component inner helpers and add an object param (as the last param) that takes in the closed over variables.
So instead of trasforming
into
which would then be called using captures:
we'd transform
into
which would then be called like
Instead of capturing the function itself, the segments would capture it's closed over variables (
countin this case).See the diff here to see what the entire optimizer output would look like.
Now if the component inner helper functions don't need to be wrapped with
$(), we can also changeuseOnDocument/useOnWindow/useOntouseOnDocument$/useOnWindow$/useOn$and we can deprecate the need for a public$()API.The contraints remain the same, inner helper functions inside component$ closing over other component$ values have special rules, but the mental model is closer to the practical constraint and therefore easier. Instead of telling the developer to wrap every inner helper functions with
$()and that special rules apply to those functions, we only tell the developer that special rules apply inside of component$ (and in hooks, which are bound to be used in component$).Playgrounds:
Links / References
No response
Beta Was this translation helpful? Give feedback.
All reactions