-
Notifications
You must be signed in to change notification settings - Fork 794
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(shadowDomShim): slot behaviour #2938
Conversation
…hods dealing with adding to components fix(scoped / shadow-shim slots): vdom-render was removing all slotted children when a slot or slot parent was removed
apply dom patches to no-encapsulated components.
To any requiring this sooner, rather than later I built out a temporary package of all my recent PRs - including this ^. What else: You can test it out with little disruption by just swapping out any reference to @stencil/core in your package.json
becomes
I will keep this package in-sync with @stencil/core master up until the relevant PRs get accepted or rejected. |
…fallback content. feat(patch remove / removeChild): non-shadow components will show/hide fallback content on slot node addition/removal
…il into fix-scoped-slot-render
@johnjenkins I tried installing your temp package on my repro setup for #2801 but after I |
Thanks for raising @eriklharper - yeah try purging - otherwise give me an hour and I’ll see what’s up. You on windows? |
Mac Catalina 10.15.7 |
hmm weird - it is a thing :) https://www.npmjs.com/package/@johnjenkins/stencil-community .. try |
I'm still seeing the issue with your fix applied. Here's my repro case if you want to try this out yourself, its just a |
@eriklharper thanks! |
Thanks for looking into this @johnjenkins ! This has long been a thorny issue and we're currently trying to work around it by ditching scoped components altogether, but if you can come up with a fix that will be splendid! |
@eriklharper good news! |
💥 This is great @johnjenkins ! It's working for me in my repro setup! I see that the comment node appears just like the other use case that uses a wrapping element around the text. |
@eriklharper SO this is the working version?
|
Hi @johnjenkins. Many thanks for your work! It does indeed fix the example component I posted in my issue. I also think your additional added features are really valuable. I'm currently using your distribution with But unfortunately I discovered 2 new issues introduced by your changes:
import { Host, Component, h } from '@stencil/core';
@Component({
tag: 'my-component',
styles: `
:host {
display: flex;
gap: 0.5rem;
}
.item, ::slotted(.item) {
+ display: block;
border: 2px solid #ccc;
padding: 0.25rem;
}
`,
shadow: false,
scoped: true,
})
export class MyComponent {
render() {
return (
<Host>
<slot>
<div class="item">Default #1</div>
<div class="item">Default #2</div>
<div class="item">Default #3</div>
</slot>
</Host>
);
}
}
import { Component, Host, h } from "@stencil/core";
@Component({
tag: "my-component",
styles: `
:host {
display: block;
}
`,
scoped: true,
})
export class MyComponent {
render() {
return (
<Host>
<slot name="content">
<slot name="before">DEFAULT BEFORE</slot>
<slot> DEFAULT CONTENT </slot>
<slot name="after">DEFAULT AFTER</slot>
</slot>
</Host>
);
}
} This component yields the following results: <my-component> CONTENT </my-component> → Only <my-component>
<span slot="before">BEFORE</span>
CONTENT
<span slot="after">AFTER</span>
</my-component> → Correctly renders as <my-component></my-component> → doesn't render at all instead of rendering as Changing <my-component> CONTENT </my-component> → Correctly renders as <my-component></my-component> → Doesn't render at all and throws the same error None of these issues occur with Again, many thanks for your work. It would be great if you could take a look at these problems. (Tested with Firefox 89.0.2 and Chrome 91.0.4472.124) |
hey @PaulRaschke - thanks so much for taking time to test this! |
Yes indeedly doodly |
This was a false alarm on my part – as I was working on getting a minimum reproduction together I realized that the slotted component that I was testing had invalid html structure. After reworking that, was able to confirm this works as expected. Thanks again, and sorry for the distraction! |
I've tested this and it seems to work, except for the Hydration errors that started to appear on Next.js |
The only way, I've found to overcome the hydration problem was by adding a useEffect const [loaded, setLoaded] = useState<boolean>(false)
useEffect(() => {
if (!loaded) {
setLoaded(true)
}
}, [loaded]) |
@JessicaSachs Since the release of version 4 was already done, could you guys take this PR into account 🙏🏻 |
Is there already an ETA for this bugfix? |
i also want to know. |
+1 |
Hello 👋 I tested the released alpha version with our app.
I have updated my reproduction repository with this behavior: https://github.com/eWert-Online/stencil-ssr-hydrate-reproduction/tree/alpha-test You can also see the resulting behavior in this video: reproduction-video.webm |
We are using johnjenkins/[email protected] and can confirm that the e.split error with SVGs exists with this PR. We worked around it by using innerHTML to set the svg. |
As per @mayerraphael issue (#4278) it seems like this is an existing issue in the current codebase.. not sure I should make this PR any bigger :D / this bug is beyond the scope of this PR
I just took your repo for a spin - it seems the SVG error halts the hydration process (before it's finished re-slotting elements) so causes the second error / 'race condition' |
@johnjenkins I can only reproduce the error with this PR. It seems to be related. I updated #4278 and linked a repo for reproduction. |
Hey folks 👋 With today's release of Stencil v4.1.0, we introduced a new flag called |
The following bug(s) have fixes included in today's v4.2.0 release: |
This adds a regression test for the issue reported in #4278, which doesn't currently occur on `main` but does occur in the branch associated with #2938 (a PR containing a bunch of changes for fixing bugs with slots). This regression test will give us a bit more safety as we go to add more slot behavior fixes in the future.
This adds a regression test for the issue reported in #4278, which doesn't currently occur on `main` but does occur in the branch associated with #2938 (a PR containing a bunch of changes for fixing bugs with slots). This regression test will give us a bit more safety as we go to add more slot behavior fixes in the future.
This adds a regression test for the issue reported in #4278, which doesn't currently occur on `main` but does occur in the branch associated with #2938 (a PR containing a bunch of changes for fixing bugs with slots). This regression test will give us a bit more safety as we go to add more slot behavior fixes in the future.
This adds a regression test for the issue reported in #4278, which doesn't currently occur on `main` but does occur in the branch associated with #2938 (a PR containing a bunch of changes for fixing bugs with slots). This regression test will give us a bit more safety as we go to add more slot behavior fixes in the future.
This adds a regression test for the issue reported in #4278, which doesn't currently occur on `main` but does occur in the branch associated with #2938 (a PR containing a bunch of changes for fixing bugs with slots). This regression test will give us a bit more safety as we go to add more slot behavior fixes in the future.
This adds a regression test for the issue reported in #4278, which doesn't currently occur on `main` but does occur in the branch associated with #2938 (a PR containing a bunch of changes for fixing bugs with slots). This regression test will give us a bit more safety as we go to add more slot behavior fixes in the future.
This adds a regression test for the issue reported in #4278, which doesn't currently occur on `main` but does occur in the branch associated with #2938 (a PR containing a bunch of changes for fixing bugs with slots). This regression test will give us a bit more safety as we go to add more slot behavior fixes in the future.
This problem is still occurring, even on version 4.3.0 with the experimentalSlotFixes option |
Can you please open a new issue with a minimal reproduction case for the team to take a look at? |
Sure, thanks for the fast feedback @rwaskiewicz |
@rwaskiewicz After investigating more, I've concluded that it's actually not a stencil bug but actually it only occurs when using the React Wrapper, if I attempt to use without the wrapper everything works as expected. Therefore I've opened the ticket on stencil-ds-output-targets ionic-team/stencil-ds-output-targets#393 |
Hi all! You may have seen we've been chipping away at a list of slot-related issues (pulled from this PR) over the last several months. These changes have been placed behind the (newly introduced) With a majority of this work wrapped up, we're encouraging you all to enable and test out these changes so we can verify their correctness in a larger set of use cases. The plan is that these flags will be enabled by default in Stencil v5. We do, however, want to note that these flags do not address SSR related issues that were mentioned in this PR. This includes #3413 and #2905. SSR related issues will be handled separately. If anyone still experiences any of the issues claimed to be fixed by these config flags (or encounters any new issues), please open a new issue with a reproduction. Opening new issues will help us stay organized and prioritize fixes! Lastly, we want to give a HUGE shoutout to @johnjenkins for his work on this PR! It was truly helpful as a starting point and reference while working through these issues. Thank you! |
This PR looks to fix a number of issues relating to slots and how they are managed when a component is not
shadow: true
OR if the browser in question is using theshadowDomShim
.Hence forth, I'll refer to these as 'non-shadow' components.
At present in order for non-shadow components to have similar behaviour to shadow-components (when it comes to the dom api) - stencil provides 2/3 opt-in
extras
: appendChildSlotFix, cloneNodeFix and slotChildNodesFix (https://stenciljs.com/docs/config-extras).'appendChildSlotFix' - when you write
myComponent.appendChild(newElement);
, the new element will arrive in an appropriate slot - not just be appended to the bottom of your non-shadow component.'slotChildNodesFix' - when you write
myComponent.childNodes
|myComponent.children
only the slotted nodes / elements - not all nodes in the non-shadow component dom - are returned.I feel quite strongly, that this ^ makes little sense.
Until very recently I
shadow: true
On an old browser would automatically try to mimic shadow components.shadow: false
/scoped: true
would not behave so differently regarding native APIs.I'm pretty sure a number of bugs reported are the result of simply not having these
extras
applied.Additionally, at present, applying these extras will also (totally unnecessarily) apply them to
shadow: true
components on modern browsers!This PR
This PR applies both aforementioned patches automatically on all non-shadow components and also adds new patches for nearly all DOM methods & accessors relating to the addition of new nodes:
innerHTML
,innerText
,textContent
,appendChild()
,append()
,prepend()
,insertAdjacentText()
,insertAdjacentElement()
,insertAdjacentHTML()
,replaceChildren()
With these, I believe non-shadow components feel more similar to shadow components.
I also believe many of the kinks related to non-shadow components within frameworks (vue / react et al) will go away - I'll do more testing to confirm this. The vdom renderers of these libraries will add nodes via these methods when all is said and done.
All 'native' methods / accessors are accessible by simply prepending '__' to the relevant thing: i.e.
myComponent.__innerHTML
ormyComponent.__appendChild(newThing)
; think of it as the equivalent ofmyShadowComponent.shadowRoot.innerHTML
.I did think about patching a mock
myComponent.shadowRoot
but it felt over-engineered and silly.cloneNodeFix
is still not automatically applied as I thought this was a more niche requirement(?). However now it will only apply to non-shadow components.I've added a deprecated flag to both the 'appendChildSlotFix' and 'slotChildNodesFix' extras within stencil.config. Continuing to include them will not break anything.
Lastly, I've made a small fix to stencil's vdom-renderer.
Here's a silly example:
At present, within a non-shadow component whenever
this.aBoolean
changes, the<slot/>
is deemed to have been removed and so all it's currently slotted children are also removed.This PR also fixes that.
Fixes #2004
Fixes #2641
Fixes #1968
Fixes #1997
Fixes #2801
Fixes #2257
Fixes #3913
Fixes #3977
Fixes #4284
Fixes #4523
Fixes #4525
Potentially fixes #2259
Potentially fixes #2036
Heavily referenced #2012
I’ve done quite a bit of testing in IE11, Edge 18 and all modern browsers. All current tests within stencil (spec / end-to-end via jest and karma) continue to pass.
New commit!
Commit f9a0063 sees an overhaul of non-shadow component fallback content.
(I did think about putting this in a separate PR, but the issues and requirements were very closely linked (and difficult to untangle) so it made more sense to add it here).
What is the current behavior?
In non-shadow components, slot fallback content behaviour is re-created by wrapping all fallback nodes in an
<slot-fb>
element.Wrapping nodes can create issues regarding css presentation (e.g. flex children)
What is the new behavior?
In non-shadow components, slot fallback content nodes are no longer wrapped.
Instead, in the same way that non-shadow components store slot meta in an empty text node, this same text node now stores data regarding fallback content.
Does this introduce a breaking change?
Potentially - if anyone was using the
slot-fb
for reference or styling, that will now not work.Testing
All karma & Jest tests have been updated to reflect the behaviour / lack of wrapping element.
I have also manually tested changes in an external, linked project.
Also, there was a lack of tests within Stencil for nested slots (e.g.
<slot name="content"> <slot></slot> <slot name="after"></slot> </slot>
). I've added new spec tests to cover this.Additionally
I have also now patched all,
node.remove()
andparentNode.removeChild()
on non-shadow slotted nodes - when there is slot fallback content - to assess whether fallback content should show or hide.I have also tested and amended my changes against open issues related to slot fallback content so have marked them as fixes here.
Fixes #2937
Fixes #2878
Fixes #2997
Fixes #3278
Potentially fixes #2877
New commits!
New commits address client side hydration (after using something like
renderToString()
).Fixes #3413
Fixes #3593
Fixes #2905
Fixes #2366
Fixes #2036
Fixes #1993
Whilst investigating, a number of these issues were related to
<slot />
s and how they are managed.Additionally my changes around slot fallback content weren’t working with server / client hydration.
Finally, I found when working with frameworks (like nuxt) they would attempt to resolve their vdom against the real DOM after SSR by stepping through it with accessors like ‘nextSibling’. This fails for non-shadow elements so nuxt duplicates the nodes it thinks it cannot find.
To mitigate this I’ve patched these accessors just for non-shadow, client hydrated, slotted nodes.
A number of these bugs are demoed - https://stackblitz.com/edit/stencil-start-yoemx6
And here's the same demos with this PR applied - https://stackblitz.com/edit/stencil-start-brthw2