-
Notifications
You must be signed in to change notification settings - Fork 789
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
fix(runtime): textContent for scoped components with slots #3047
fix(runtime): textContent for scoped components with slots #3047
Conversation
Hey! |
Eagle eye! I did have your PR in mind when I was working on this 🙂 I definitely feel better equipped to start looking at that one in particular when I get the time after doing a piece of it myself. I'm pushing this subset of work out now to offer up a fix for an enterprise customer, but that doesn't mean this can't be usurped by the implementation in #2938. Just don't want you thinking we're ignoring it completely 😉 |
Ha! Very wise. |
No worries - honestly after spending some time in the scoped-slot domain that PR's all the more impressive! |
bf0b64c
to
9d75d4b
Compare
patch textContent for scoped components that use slots. because there is no shadow dom, calling the setter/getter on `textContent` would otherwise act on the bare HTML elements. use the stencil metadata to relocate the text to the proper location this functionality is hidden behind a feature flag. users may enable it by setting `scopedSlotTextContentFix` to `true` in the `extras` section of their Stencil configuration file. This field defaults to `false` (keeping the same behavior that exists today) while this flag is evaluated. this does _not_ bring this functionality over to the custom elements build
9d75d4b
to
f4e2617
Compare
Can you share a bit about this? Does some render code differ between output targets due to - I assume - Lazy Loading's extensive coupling? Can you see a path toward unifying that behavior? |
None of the optional patches apply to this output. I looked into this before and there didn’t appear to be any reason 🤷🏻♂️. These monkey patches can apply without issue to that output (in my PR I did that without obvious problems). My best guesses are it was forgotten about(?) or there was a thought that it wouldn’t be a priority with the custom elements build seeing as the main / initial usecase was consumption by bundler meaning users can apply their own patches? it is interesting to me that there hasn’t been any issues raised about it that I could find |
I think @johnjenkins is correct there (or, I came to the same conclusions laid out here). The patch as defined in ATM, serving the custom elements bundle will result in the text node NOT being placed in the correct place. So we should absolutely backport/unify this fix - I added this to the user story refinement sheet. I didn't implement it here to keep this PR as simple as possible (and to get this fix out to the customer sooner). My thought here was that once we tackled some of the testing infrastructure work we have planned for this quarter, we'd be in a great place to backport this with tests 🙂 |
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.
Worked great from my local tests!
src/runtime/dom-extras.ts
Outdated
const slotNode = getHostSlotNode(this.childNodes, ''); | ||
// when a slot node is found, the textContent will be found in the next sibling (text) node. only if we can | ||
// find that text node should we try to pull a value from it | ||
if (slotNode?.nextSibling) { |
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.
Why would this need to access the next sibling? Using cmp-label
as an example, I assume slotNode
and slotNode.nextSibling
are the following:
<Host>
<label>
<slot /> <!-- slotNode -->
<div>Non-slotted text</div> <!-- slotNode.nextSibling -->
</label>
</Host>
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 because when not using shadow: true
stencil tries to recreate the behaviour of slots using empty text nodes to preserve the slot position. Thus the next nodes after the slot text node, should be some slotted content.
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.
@ltm not exactly. Let's say we have a layout that looks something like:
<Host>
<label>
<slot />
<div>Non-slot</div>
</label>
</Host>
When we're doing slot relocation, calling childNodes
on the label element yields:
where slotNode
is that first text node, and slotNode.nextSibling
in this case is the second text node.
When we call getHostSlotNode
, it finds the first text node, and assigns it to slotNode
because that node has the Stencil marker '[s-sn]` (slot name) set to an empty string (which is what we wanted).
However, in cases like this, the VDOM has placed the content in that second text node. Attempting to place the value received when setting textContent
in the first node will result in concatenation of that received value (from setting textContent
) and what's in the second text node. So, we check here for this case first.
However, you also presented a case internally where this isn't always the case. I've updated this PR with additonal tests and hopefully clearer comments. LMK what you think
handle the case where slot relocation has not resulted in an empty text node slot followed by another text node containing the actual test moved the scoped-slot-test to scoped-slot-text-with-sibling updated pre-existing scoped-slot-test so that the slot in the HTML did not have a sibling div
Leaving a note for future us - we know this doesn't cover every edge case. We've marked this as experimental in the docs, and will likely be revisiting this in the future |
Pull request checklist
Please check if your PR fulfills the following requirements:
npm run build
) was run locally and any changes were pushednpm test
) were run locally and passednpm run test.karma.prod
) were run locally and passednpm run prettier
) was run locally and passedPull request type
Please check the type of change your PR introduces:
What is the current behavior?
GitHub Issue Number: #2801
The issue above points to a bug when using Stencil w/Maquette. The underlying cause is Stencil does not adhere to "the correct thing to do" when
textContent
is set, which Maquette is doing under the hood in the reproduction case when creating this node:What is the new behavior?
patch
textContent
for scoped components that use slots. because there isno shadow dom, calling the setter/getter on
textContent
wouldotherwise act on the bare HTML elements. use the stencil metadata to
relocate the text to the proper location
this functionality is hidden behind a feature flag. users may enable it
by setting
scopedSlotTextContentFix
totrue
in theextras
sectionof their Stencil configuration file. This field defaults to
false
(keeping the same behavior that exists today) while this flag is
evaluated.
Does this introduce a breaking change?
Testing
npm ci && npm run build.prod && npm pack
npm i <PATH_TO_TARBALL>
stencil.config.ts
file as follows:npm start
, observe the text being slotted correctly:Other information
this does not bring this functionality over to the custom elements
build. this will be done in a future story (added to the team refinement sheet)
the second commit contains some JSDoc I created as I combed through the code. they are not strictly related/necessary for the fix, but something that were tangentially related enough for me to feel it was worth including here. I can put them in a separate PR if y'all feel it's not a good time/place to add them