-
Notifications
You must be signed in to change notification settings - Fork 399
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
POC: dynamic component template directive #3218
Conversation
return c(sel, Ctor, data, children); | ||
// We don't ahve to get the custom element name from the Ctor, we could store it in a weakmap or somewhere to retrieve it. | ||
// Alternatively, we could generate a name or ask the component author to provide a name. | ||
return c(Ctor.sel, Ctor, data, children); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the purposes of the POC I needed a way to store the inferred tag name. I chose to store it on the Ctor but there are other options as well.
if (isComponentConstructor(Ctor)) { | ||
Ctor.sel = sel; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this POC registerComponent
would store the tag name on the Ctor as an example.
<template>
<template lwc:dynamic={ctor} lwc:attributes={databag}></template>
</template> Two problems with this approach I see:
|
@abdulsattar Thanks for the feedback! I discussed this with @ravijayaramappa and I think it may be better to only allow assigning props through The idea is to stay consistent with respect to how the component is created. When the component is created programmatically with That does leave a gap in assigning event handlers to the template though. Using a pre-defined element like The reason I went with I'll add this feedback to the RFC. |
Something that I raised during the last sync that I would like to capture here is that the
IMO, it would be preferable to use a different tag name to denote a custom element if we pursue this route. I would vote for using the |
@pmdartus If we are going to use document.createElement('lwc:dynamic') |
@pmdartus thanks for pointing this out, I agree the usage of dynamic components in this POC does not represent an HTML fragment. I think to make a <template lwc:dynamic>
{insertDynamicElementHere}
</template> Additionally, I interpreted this line from the HTML spec:
to mean the Based on these two observations, I think going with a placeholder tag like Going a step further, I wonder if making a This could have the benefit of allowing for intermediate content to be displayed, like a loading screen, while the constructor is being retrieved. I'll include this feedback in the RFC. @nolanlawson would using document.createElement('lwc:dynamic') cause any issues? Could doing that interfere with the structure of the vnodes? |
@jmsjtu It's not that it would mess with the vnodes; it's just that it feels icky if folks on-platform are able to create their own |
I am not sure to understand why we would need to squat the I also don't think that we should prevent developers from creating elements using Are you concerned that developers might already have HTML elements in their templates using the
I don't think this is the correct way to interpret the HTML specification. In the context of the spec, interpret refers to the semantic of the DOM node (interpret definition). If you look at how the same term is applied to other DOM elements like
Yes, it's also another avenue worth pursuing. I am not married to the idea of using a special tag name for dynamic components. The main challenge we discussed in the past is how we ensure that the LWC engine is in control of the |
No, I just want to avoid any confusion. A dev warning at runtime is fine. I am agnostic to what the developer-facing syntax looks like, but I much prefer handling this in the compiler rather than at runtime. It just seems like less code overall to maintain, and less potential for accidentally exposing subtle API surface at runtime. Hence why I prefer this proposal to #3204. |
Thanks for clearing this up @pmdartus! |
Ok, it feels that all of you are inching to the solution that I'm proposing, which is a good thing IMO. @pmdartus the signal should be an attribute, not the name... that way we avoid the whole question about what the name should be... and how to query that name, etc. In the other proposal, the attribute @nolanlawson @jmsjtu the talking point is really about re-creating of the element vs re-using the element. The implications for me are very clear, either you put the pressure on the framework (LWC) or you put it on the developer, someone has to track down the replacement of the element if they want to hold a reference, or add a manual listener, etc. Who is going to be, is the real question. In this case, I'm leaning toward the framework to take care of that, but that's just an opinion. |
There is one more thing that I don't think has surface in this discussion, it is the mismatches between constructors, and the implications for allocation of children. |
Details
This is a follow-up to #3204 and is a POC of how
lwc:dynamic
can work as a template directive.This POC works very similarly to how the existing
lwc:dynamic
works but rather than using a placeholder tag name for the dynamic component, it uses an inferred name.Most of the work is done by the compiler to wire up the template in a way that can fit into the current element creation process using the diffing algo.
How it works
The syntax for using the directive is as follows:
Mimicking the current behavior,
lwc:dynamic
stores the constructor but because this directive now belongs to a template we'll need another way to assign attributes and event listeners.One option to store these values is to use another directive, for example,
lwc:attributes
that houses the values and passes them to the dynamic component once it's been instantiated.Alternatively we may be able to just use
lwc:spread
for this.The output of the template function will look as follows:
The difference from the current behavior is that we're no longer passing a tag name to the dc function.
The tag name can be inferred in a number of different ways but in this example, I've stored the name on the Ctor.
Note: When the rollup plugin runs the namespace and name are both available, these can be used to infer the name of the component.
The new DC function would look something like this:
With this design, we can continue to use the current flow for generating dynamic components (through the diffing algo), as the main functionality of the dc function remains the same.
This also means that the logic to instantiate and insert dynamic elements will follow the same flow as custom elements do currently.
Considerations
Here are a few points about the design that needs fleshing out / finalizing.