-
Notifications
You must be signed in to change notification settings - Fork 25
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
adding dynamic component configuration rfc #48
base: master
Are you sure you want to change the base?
Conversation
@alejandro-sf It looks like something is wrong with the formatting? GitHub is not able to render the markdown correctly: rendered view |
Oh I didn't know the markdown was visible even from the review...I'll update to fix I used the quip export to markdown feature so there's probably something wrong there |
Please see the new formatting here |
this.loadCtor(); | ||
|
||
async loadCtor() { | ||
const ctor = await import(this.moduleName); |
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.
Let's leave dynamic import aside from this proposal. How the component constructor is loaded is independent of how the attributes, properties, event listeners are passed.
|
||
get configurations() { | ||
return { | ||
ctor: this.customCtor, |
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.
LWC already implements the lwc:is
directive to dynamically pass a component constructor at runtime. Accepting a ctor
property creates a duplicate. IMO this proposal should work both for static and dynamic component constructors.
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.
Does that mean you want 'ctor' to be renamed as 'is' or is there another mechanism for this?
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.
It's not the lwc:is
but rather the lwc:dynamic
that I was referring to above: https://github.com/salesforce/lwc-rfcs/blob/master/text/0110-dynamic-components.md#api
</template> | ||
``` | ||
```js | ||
import { LightningElement, api } from "lwc"; |
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.
This is not a valid JavaScript code block. I would also recommend making this example as minimal as possible to make it straightforward to understand.
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.
Should we pare this down? I wanted to make sure we had a compelling usecase for each of the 4 things you can configure in 1 place.
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.
I would keep the example in the RFC itself as simple a possible. You can add more complex examples at the end in an appendix for example this way is doesn't distract from the actual content of the RFC.
Before this proposal, dynamic component creation was done using the `lwc:dynamic` directive. This directive required a component author to know component configuration details like the property and event names at design time which breaks down for use cases that need true dynamic component creation. For instance, in the case of property values or event handlers one would have to keep a reference to the element and set the information retrieved at runtime manually. | ||
|
||
```js | ||
element; |
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.
This code block is not valid JavaScript.
|
||
## Proposal | ||
|
||
The proposal involves adding a new directive that captures the relevant information to configure a web component at runtime. The assumption is that this directive will be used in cases where the component module is unknown at runtime (therefore used alongside dynamic imports) and zero or more of the following are unknown at runtime: properties, attributes, or event handlers. |
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.
The proposal involves adding a new directive that captures the relevant information to configure a web component at runtime. The assumption is that this directive will be used in cases where the component module is unknown at runtime (therefore used alongside dynamic imports) and zero or more of the following are unknown at runtime: properties, attributes, or event handlers. | |
The proposal involves adding a new directive that captures the relevant information to configure a web component at runtime. The assumption is that this directive will be used in cases where the component constructor is unknown until runtime and zero or more of the following are unknown until runtime: properties, attributes, or event handlers. |
|
||
The directive `lwc:bind` can retrieve component configuration data via a JavaScript object with a pre-defined shape. Constructor is the only required property in the configuration data. | ||
|
||
## General Invariants |
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.
There is a mix of actual invariants and design details in this section.
For example, Changes to the configuration object must be reflected in the component
is not an invariant of this proposal but rather a design decision based on the proposed solution. I would recommend breaking this section apart and specifying each individual behavior.
|
||
* Changes to the configuration object must be reflected in the component (ie changing the properties will cause component properties to be set again) | ||
|
||
* Changing the constructor on a parent component will also trigger a cascade re-render of any child components |
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.
Changing a constructor requires unmounting the existing custom element and creating a new custom element. It actually doesn't re-render the children elements but creates brand new children elements.
|
||
This feature will be available in Salesforce Lightning Platform and LWR to certain teams depending on their use cases | ||
|
||
## Unresolved Questions |
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.
Questions that are not covered by this proposal:
- Can the
lwc:bind
directive be used with other directives, attributes and event handlers? - If the response to the previous answer is yes, what happens when the
lwc:bind
contains an attribute that is already defined via the template. For example:<x-foo lwc:bind={config} class="error"></x-foo>
withconfig = { attributes: { class: 'success' } }
? - In which order
properties
andattributes
are set? If the config is defined asconfig = { attributes: { class: 'error' }, properties: { className: 'success' } }
what is the expected output? - How are attributes values treated? How to add and remove an attribute? What is the semantic of the following attribute values:
null
,undefined
,true
andfalse
?
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.
what about special properties, like innerHtml
, outerHtml
, innerText
, etc? Will they be allowed?
There's already a [inner html binding RFC] (#15), which states some security concerns. Open question: Does this lwc:bind
proposal overlaps with lwc:inner-html
?
``` | ||
A new tool must be introduced that will allow component authors to configure their components with information retrieved at runtime without relying on maintaining element references or manually manipulating the DOM. | ||
|
||
## Proposal |
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.
It would be great to add a section about how other frameworks are approaching this issue.
update RFC doc
Thanks for the contribution! It looks like @wanyanxu is an internal user so signing the CLA is not required. However, we need to confirm this. |
Thanks for the contribution! Unfortunately we can't verify the commit author(s): Alejandro Lopez <a***@A***.i***.s***.com>. One possible solution is to add that email to your GitHub account. Alternatively you can change your commits to another email and force push the change. After getting your commits associated with your GitHub account, sign the Salesforce.com Contributor License Agreement and this Pull Request will be revalidated. |
@wire(myAdapter, { id: 'someDashboardId' }) { | ||
chartDefinitions({ data, error }) { |
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.
@wire(myAdapter, { id: 'someDashboardId' }) { | |
chartDefinitions({ data, error }) { | |
@wire(myAdapter, { id: 'someDashboardId' }) | |
chartDefinitions({ data, error }) { |
@api moduleName; | ||
|
||
connectedCallback() { | ||
const ctor = await import(this.moduleName); |
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.
invalid js
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.
Is this because await must be in an async function?
Rendered