-
Notifications
You must be signed in to change notification settings - Fork 400
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
refactor: fix forwarded light DOM slots mapping #3883
Conversation
@@ -99,6 +100,7 @@ export interface VBaseElement extends BaseVNode, BaseVParent { | |||
data: VElementData; | |||
elm: Element | undefined; | |||
key: Key; | |||
slotAssignment: string | undefined; |
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.
We need to move slot assignment outside the props
in ElementData
because static vnodes can also be reassigned during light DOM slot forwarding.
For example:
<x-slot-cmp>
<div>This is a static element</div>
</x-slot-cmp>
<template>
<slot slot="foo"></slot>
</template>
// x-slot-cmp
In the above example, the div, which is a static element needs to be forwarded to thefoo
slot. This can't happen through the props
because static vnodes don't update attributes from props.
attrs: { | ||
slot: 'first', | ||
}, | ||
slotAssignment: 'first', |
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.
We'll need to add an ACT compiler change 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.
This might be an issue if we decide to use API versioning because of the mechanics of how ACT compiler + API versioning works.
Try publishing an alpha version of LWC with these and run the jest tests on core with this change.
const vFragBookend = process.env.API_VERSION > 59 ? document.createComment('') : ''; | ||
const commentNode = document.createComment(' comments being forwarded '); | ||
|
||
describe('slot forwarding', () => { |
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.
These tests asserts that forwarding slots between light and shadow DOM should produce the same results.
|
||
import LightContainer from './x/lightContainer/lightContainer'; | ||
|
||
describe('light DOM slot forwarding reactivity', () => { |
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.
These tests ensure that dynamically setting the slot
attribute on a forwarded slot works properly between light and shadow DOM.
packages/@lwc/integration-karma/test/light-dom/slot-fowarding/scoped-slots/index.spec.js
Show resolved
Hide resolved
This reverts commit dce30db.
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.
Great work on this!! A real beast of a PR. 💪
Overall it looks good to me, but I would like to review in dev sync since this is a risky change touching a lot of the framework internals.
const defaultSlotContent = slots['default-slot'].assignedNodes(); | ||
expect(defaultSlotContent[0].textContent).toEqual('Text being forwarded'); | ||
if (!process.env.NATIVE_SHADOW) { | ||
// Native shadow doesn't slot comments |
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.
TIL 😂
if (isExpression(value)) { | ||
slotValue = codeGen.bindExpression(value); | ||
} else { | ||
slotValue = isStringLiteral(value) ? t.literal(value.value) : t.literal(''); |
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 there any way this could be a breaking change? E.g. are we treating slot={boolean}
or slot={null}
or slot={undefined}
or any other non-string values any different from before?
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.
@nolanlawson I have a test in the @lwc/template-compiler
to test the various combinations for values passed to the slot
attribute.
Here's a stackblitz demo using LWC 5.1.0 to compare.
I compared the tmpl
functions and it looks like the resulting values are the same, the slot
value is always transformed into a string.
I created this section by extracting what we were doing with the slot
value in computeAttrValue
and it should be doing the same thing as before.
packages/@lwc/integration-karma/test/light-dom/scoped-slot/index.spec.js
Outdated
Show resolved
Hide resolved
...on-karma/test/light-dom/slot-fowarding/slots/forwarding/x/lightContainer/lightContainer.html
Show resolved
Hide resolved
❌ An unexpected error occurred while attempting to start the |
❌ An unexpected error occurred while attempting to start the |
❌ An unexpected error occurred while attempting to start the |
❌ An unexpected error occurred while attempting to start the |
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.
LGTM, just a minor note about hoisting a variable, and also of course we need to update the ACT Compiler.
If there are significant breaking changes, we should also consider API versioning. This will be determined by testing downstreams.
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.
LGTM! Worst comes to worst, we can revert and then add it to the API versioning changes for LWC v6.0.0.
@nolanlawson I ran through all the nucleus downstream and found the following:
I mainly have a question about #3 above, do you think it's worth adding API versioning for this? They could always just update the selector themselves. I also ran through the core jest tests and didn't find any snapshots that needed to be updated. |
@jmsjtu The |
Details
Fixes #3843 and replaces #3854.
The main issue with #3854 is that it does not handle static fragments and does not work properly with reactive slot assignment (
slot={reactiveValue}
).There will also need to be a separate PR to update the ACT compiler.
This PR fixes the issue of light DOM slots not mapping correctly when they are forwarded to another component.
Essentially, when a light DOM slot is passed as a child to another element it will return the children rather than create a slot element.
This can cause the slot mapping to be incorrect when the children have a
slot
attribute already.For example:
In the above example, when the
slot
element is passedx-leaf
, the children are passed directly (noslot
element is created).Since the
div
element has aslot="namedSlot"
attribute, the slot mapping will attempt to map to a slot named "namedSlot" which doesn't exist and does not render.This is especially an issue with native shadow DOM as in order to render the slot correctly, the
slot
attribute must be included on the element.Note, this is only an issue when the root of the slotted content is a
slot
. In the above example, if theslot
was wrapped in adiv
the content would render correctly.ex:
This PR resolves the issue by replacing the
slot
attribute on the children with the correctslot
attribute mapping.In above example, the div
slot
attribute will be removed on thediv
so that it can render properly.Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?
The top-level element of any content that is slotted into a light DOM
<slot>
element will have theslot
attribute updated to match theslot
attribute of the<slot>
element.For example,
Will render as follows when it is slotted into
<x-leaf>
:Note that the top
<div>
element'sslot
attribute value has been removed.This is because the light DOM named slot does not contain a
slot
attribute, ie:<slot name="namedSlot">
, does not contain aslot
attribute.Since light DOM
<slot>
elements do not get rendered into the DOM and the content is directly appended to the host element, this is needed to correctly forward the slotted content to the correct named slot.Additionally, updating the
slot
attribute of the slotted content is necessary in order to slot content correctly in native shadow.GUS work item
W-14356488