fix(runtime): add display style to slot-fb elements#5028
Conversation
|
| Path | Error Count |
|---|---|
| src/dev-server/index.ts | 37 |
| src/mock-doc/serialize-node.ts | 36 |
| src/dev-server/server-process.ts | 32 |
| src/compiler/build/build-stats.ts | 27 |
| src/compiler/output-targets/dist-lazy/generate-lazy-module.ts | 25 |
| src/compiler/style/test/optimize-css.spec.ts | 23 |
| src/testing/puppeteer/puppeteer-element.ts | 23 |
| src/compiler/prerender/prerender-main.ts | 22 |
| src/runtime/client-hydrate.ts | 19 |
| src/screenshot/connector-base.ts | 19 |
| src/runtime/vdom/vdom-render.ts | 18 |
| src/compiler/config/test/validate-paths.spec.ts | 16 |
| src/dev-server/request-handler.ts | 15 |
| src/compiler/prerender/prerender-optimize.ts | 14 |
| src/compiler/sys/stencil-sys.ts | 14 |
| src/compiler/transpile/transpile-module.ts | 14 |
| src/runtime/vdom/vdom-annotations.ts | 14 |
| src/sys/node/node-sys.ts | 14 |
| src/compiler/build/build-finish.ts | 13 |
| src/compiler/prerender/prerender-queue.ts | 13 |
Our most common errors
| Typescript Error Code | Count |
|---|---|
| TS2345 | 417 |
| TS2322 | 392 |
| TS18048 | 310 |
| TS18047 | 101 |
| TS2722 | 38 |
| TS2532 | 34 |
| TS2531 | 23 |
| TS2454 | 14 |
| TS2352 | 13 |
| TS2769 | 10 |
| TS2790 | 10 |
| TS2538 | 8 |
| TS2344 | 5 |
| TS2416 | 4 |
| TS2493 | 3 |
| TS2488 | 2 |
| TS18046 | 2 |
| TS2684 | 1 |
| TS2430 | 1 |
Unused exports report
There are 15 unused exports on this PR. That's the same number of errors on main, so at least we're not creating new ones!
Unused exports
| File | Line | Identifier |
|---|---|---|
| src/runtime/bootstrap-lazy.ts | 21 | setNonce |
| src/screenshot/screenshot-fs.ts | 18 | readScreenshotData |
| src/testing/testing-utils.ts | 198 | withSilentWarn |
| src/utils/index.ts | 145 | CUSTOM |
| src/utils/index.ts | 251 | resolve |
| src/utils/index.ts | 269 | normalize |
| src/utils/index.ts | 7 | escapeRegExpSpecialCharacters |
| src/compiler/app-core/app-data.ts | 25 | BUILD |
| src/compiler/app-core/app-data.ts | 115 | Env |
| src/compiler/app-core/app-data.ts | 117 | NAMESPACE |
| src/compiler/fs-watch/fs-watch-rebuild.ts | 123 | updateCacheFromRebuild |
| src/compiler/types/validate-primary-package-output-target.ts | 62 | satisfies |
| src/compiler/types/validate-primary-package-output-target.ts | 62 | Record |
| src/testing/puppeteer/puppeteer-declarations.ts | 485 | WaitForEventOptions |
| src/compiler/sys/fetch/write-fetch-success.ts | 7 | writeFetchSuccessSync |
tanner-reits
left a comment
There was a problem hiding this comment.
Noting a few things
| const head = doc.head; | ||
| const metaCharset = /*@__PURE__*/ head.querySelector('meta[charset]'); | ||
| const visibilityStyle = /*@__PURE__*/ doc.createElement('style'); | ||
| const dataStyles = /*@__PURE__*/ doc.createElement('style'); |
There was a problem hiding this comment.
Renamed this since it wasn't really only responsible for visibility styles anymore
src/runtime/bootstrap-lazy.ts
Outdated
| const nonce = plt.$nonce$ ?? queryNonceMetaTagContent(doc); | ||
| if (nonce != null) { | ||
| dataStyles.setAttribute('nonce', nonce); |
There was a problem hiding this comment.
This shouldn't have been contingent on the invisiblePrehydration stuff in the first place
| export const HYDRATE_CHILD_ID = 'c-id'; | ||
| export const HYDRATED_CSS = '{visibility:hidden}.hydrated{visibility:inherit}'; | ||
|
|
||
| export const SLOT_FB_CSS = 'slot-fb{display:contents}slot-fb[hidden]{display:none}'; |
There was a problem hiding this comment.
We have to have two style rules here rather than using :not([hidden]) since we support some browsers that don't support :not() yet
There was a problem hiding this comment.
Can you do me a favor and add a (code) comment here with that information? That might not be immediately obvious if someone were reading the source file as-is.
|
|
||
| // TODO(STENCIL-18) Restore this test and fix the underlying issue. | ||
| xdescribe('slot-fallback', () => { | ||
| describe('slot-fallback', () => { |
There was a problem hiding this comment.
Went ahead and restored these tests while I was in here since I needed to add some new ones anyway.
alicewriteswrongs
left a comment
There was a problem hiding this comment.
looks good to me!
| export const HYDRATE_CHILD_ID = 'c-id'; | ||
| export const HYDRATED_CSS = '{visibility:hidden}.hydrated{visibility:inherit}'; | ||
|
|
||
| export const SLOT_FB_CSS = 'slot-fb{display:contents}slot-fb[hidden]{display:none}'; |
There was a problem hiding this comment.
Can you do me a favor and add a (code) comment here with that information? That might not be immediately obvious if someone were reading the source file as-is.
src/runtime/bootstrap-lazy.ts
Outdated
| dataStyles.innerHTML = SLOT_FB_CSS; | ||
| dataStyles.setAttribute('data-styles', ''); | ||
| head.insertBefore(dataStyles, metaCharset ? metaCharset.nextSibling : head.firstChild); |
There was a problem hiding this comment.
For my own understanding, why do we hoist this out of this conditional?
There was a problem hiding this comment.
Because the styles for slot-fb should not be contingently created and applied based on the invisiblePrehydration config option. So, we always create and insert the style element, but will continue to only inject the invisiblePrehydration styles based on that config value.
Also added a quick comment in the code to help clarify that a bit.
There was a problem hiding this comment.
Can you expound on that for me? invisiblePrehydration is true by default, which meant we were setting the innerHTML and data-styles by default for most folks only if hydratedClass or hydratedAttribute were set (or both). In fact, before invisibleHydration was added (a3d2928), this section looked like the following in ac49d7c:
if (BUILD.hydratedClass || BUILD.hydratedAttribute) {
visibilityStyle.innerHTML = cmpTags + HYDRATED_CSS;
visibilityStyle.setAttribute('data-styles', '');
head.insertBefore(visibilityStyle, metaCharset ? metaCharset.nextSibling : head.firstChild);
}There was a problem hiding this comment.
That sill happens. So now, if you have a component using a slot outside the Shadow DOM (i.e. scoped or no encapsulation) and have the conditions for invisiblePrehydration, you get styles like the following:
slot-fb {
display: contents
}
slot-fb[hidden] {
display: none
}
my-component {
visibility:hidden
}
.hydrated {
visibility:inherit
}
src/runtime/styles.ts
Outdated
| styleContainerNode.insertBefore(styleElm, styleContainerNode.querySelector('link')); | ||
| } | ||
|
|
||
| styleElm.innerHTML += SLOT_FB_CSS; |
There was a problem hiding this comment.
For my own understanding, why do we add this here?
There was a problem hiding this comment.
This is how we style the slot-fb element for CE builds. This appends the slot-fb styles to the style element in the DOM. Added a code comment as well
There was a problem hiding this comment.
This probably ties directly into my question above (GH won't let me link it since I haven't submitted the review yet):
Double checking - why should we always add this style to DOM, even if a component doesn't have any slots? I think that's still lost on me, even with the added comment
How do we know this is a slot-fb element?
There was a problem hiding this comment.
You're right, we shouldn't. For some reason didn't realize we actually know if we need to apply this for each component. Updated to wrap this in a conditional based on CMP_FLAGS.hasSlotRelocation
| expect(document.querySelector('prehydrated-styles').innerHTML).toEqual('<div>prehydrated-styles</div>'); | ||
|
|
||
| expect(document.head.querySelectorAll('style[data-styles]').length).toEqual(0); | ||
| expect(document.head.querySelectorAll('style[data-styles]').length).toEqual(1); |
There was a problem hiding this comment.
Previously in these tests, checking for style[data-styles] was the only way to differentiate between invisible-prehydration being on/off. Can we update these tests to evaluate the content of that selector as well?
There was a problem hiding this comment.
Oh, meant to mention this on my initial comment review. I tried to do this, but at least one of the tests would fail when checking the content. But, if you ran the failing test(s) on their own, they would pass. So, there's something weird with multiple tests running that are related. These tests use a component and script from a different build, so maybe something with that?
But I also tried updating the tests so they each had their own component, but ran into basically the same issue so the elements in the DOM head may not be getting created correctly between tests.
Let me know if you have any ideas and I can try them out.
src/runtime/bootstrap-lazy.ts
Outdated
|
|
||
| // These style should always be constructed and inserted into the DOM | ||
| // We'll conditionally add some more styles later on | ||
| dataStyles.innerHTML = SLOT_FB_CSS; |
There was a problem hiding this comment.
Double checking - why should we always add this style to DOM, even if a component doesn't have any slots? I think that's still lost on me, even with the added comment
There was a problem hiding this comment.
We shouldn't. Didn't realize we know specifically if any components are using slots outside the Shadow DOM. So, I added a boolean that will be set true if any components in the lazy build do that and that is used to conditionally add the slot-fb styles to the stylesheet in the DOM head.
src/runtime/bootstrap-lazy.ts
Outdated
| dataStyles.innerHTML = SLOT_FB_CSS; | ||
| dataStyles.setAttribute('data-styles', ''); | ||
| head.insertBefore(dataStyles, metaCharset ? metaCharset.nextSibling : head.firstChild); |
There was a problem hiding this comment.
Can you expound on that for me? invisiblePrehydration is true by default, which meant we were setting the innerHTML and data-styles by default for most folks only if hydratedClass or hydratedAttribute were set (or both). In fact, before invisibleHydration was added (a3d2928), this section looked like the following in ac49d7c:
if (BUILD.hydratedClass || BUILD.hydratedAttribute) {
visibilityStyle.innerHTML = cmpTags + HYDRATED_CSS;
visibilityStyle.setAttribute('data-styles', '');
head.insertBefore(visibilityStyle, metaCharset ? metaCharset.nextSibling : head.firstChild);
}
src/runtime/styles.ts
Outdated
| styleContainerNode.insertBefore(styleElm, styleContainerNode.querySelector('link')); | ||
| } | ||
|
|
||
| styleElm.innerHTML += SLOT_FB_CSS; |
There was a problem hiding this comment.
This probably ties directly into my question above (GH won't let me link it since I haven't submitted the review yet):
Double checking - why should we always add this style to DOM, even if a component doesn't have any slots? I think that's still lost on me, even with the added comment
How do we know this is a slot-fb element?
What is the current behavior?
Stencil wraps slot fallback content in a
slot-fbelement when we patch slot behavior in non-shadow components. This can cause issues with styles likedisplay: flexthat target slotted elements.Fixes: #2937
What is the new behavior?
This adds a global style to set
display: contentson allslot-fbelements. This is the same style that gets set on theslotelements in the native shadow DOM.Does this introduce a breaking change?
Testing
Manual testing
Confirmed the fix in the reproduction in the linked issue
Automated testing
Other information