-
Notifications
You must be signed in to change notification settings - Fork 785
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): relocate slotted content when slot parent element tag changes #5120
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/style/test/optimize-css.spec.ts | 23 |
src/compiler/output-targets/dist-lazy/generate-lazy-module.ts | 22 |
src/compiler/prerender/prerender-main.ts | 22 |
src/testing/puppeteer/puppeteer-element.ts | 22 |
src/runtime/client-hydrate.ts | 20 |
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/prerender/prerender-queue.ts | 13 |
src/compiler/sys/in-memory-fs.ts | 13 |
src/runtime/connected-callback.ts | 13 |
Our most common errors
Typescript Error Code | Count |
---|---|
TS2345 | 399 |
TS2322 | 374 |
TS18048 | 286 |
TS18047 | 101 |
TS2722 | 37 |
TS2532 | 30 |
TS2531 | 23 |
TS2454 | 14 |
TS2352 | 13 |
TS2790 | 10 |
TS2769 | 8 |
TS2538 | 8 |
TS2416 | 6 |
TS2344 | 5 |
TS2493 | 3 |
TS2488 | 2 |
TS18046 | 2 |
TS2684 | 1 |
TS2430 | 1 |
Unused exports report
There are 14 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 | 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 | 61 | satisfies |
src/compiler/types/validate-primary-package-output-target.ts | 61 | Record |
src/testing/puppeteer/puppeteer-declarations.ts | 485 | WaitForEventOptions |
src/compiler/sys/fetch/write-fetch-success.ts | 7 | writeFetchSuccessSync |
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.
Couple notes
// // this child node in the old element is from another component | ||
// // remove this node from the old slot's parent | ||
// childNode.remove(); |
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 chunk has been commented out for a while. I've tried uncommenting it a few times in different issues and haven't noticed any change in behavior so figured we just get rid of it to avoid future confusion
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'm in favor of this 👍
@@ -1027,7 +1064,7 @@ render() { | |||
// has a different next sibling or parent relocated | |||
|
|||
if (nodeToRelocate !== insertBeforeNode) { | |||
if (!nodeToRelocate['s-hn'] && nodeToRelocate['s-ol']) { | |||
if (!BUILD.experimentalSlotFixes && !nodeToRelocate['s-hn'] && nodeToRelocate['s-ol']) { |
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.
Idea is that this whole block will go away once the slot fix flag is defaulted. Setting s-hn
for elements from index.html
actually causes some weird behavior when putting nodes back since it won't relocate a node to the same host node (which we actually want in some scenarios).
I didn't see any negative consequences from removing this while playing around with things, and all our automated tests still pass so feel like we're okay to do 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.
2 non-blocking nits
// // this child node in the old element is from another component | ||
// // remove this node from the old slot's parent | ||
// childNode.remove(); |
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'm in favor of 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.
Code LGTM 👍
I was not quite able to reproduce the fixed using a starter project:
❯ ls -ls node_modules/@stencil/
total 0
0 lrwxr-xr-x@ 1 christian.bromann wheel 67 Dec 4 09:37 core -> ../../../../../Users/christian.bromann/Sites/Ionic/projects/stencil
❯ npm start
> s5120@0.0.1 start
> stencil build --dev --watch --serve
[48:18.8] @stencil/core
[48:18.9] [LOCAL DEV] v4.8.0-dev.1701711877.75dbaa0 🦀
[48:19.6] build, s5120, dev mode, started ...
[48:19.6] transpile started ...
[48:20.6] transpile finished in 1.04 s
[48:20.6] copy started ...
[48:20.6] generate lazy + source maps started ...
[48:20.6] copy finished (0 files) in 14 ms
[48:20.8] generate lazy + source maps finished in 184 ms
[48:20.8] build finished, watching for changes...
in 1.24 s
[48:20.8] http://localhost:3333/
This should not be blocking the PR from being merged.
👍
Co-authored-by: Ryan Waskiewicz <ryanwaskiewicz@gmail.com>
@christian-bromann Oops, should've mentioned in the test steps that you need to have // stencil.config.ts
extras: {
experimentalSlotFixes: true
} That could be why you weren't seeing the correct order after clicking the button. I'll update the steps for posterity. |
@tanner-reits I was able to verify the expected behavior after adding |
Released in |
What is the current behavior?
Stencil can re-render incorrectly when content is slotted in from the "implementation layer" (i.e. from
index.html
) and aslot
s parent element tag changes (e.g. fromp
tospan
). This is only an issue when using slots outside the Shadow DOM.The issue is caused by our vDOM algorithm relocating slotted content back to its original location when it determines that a child node has changed. When this happens, we call
putBackInOriginalLocation()
which will relocate a node back to where it was original defined. But, this can result in the node no being re-relocated if it was put back into a location inside another Stencil element that has already gone through its render cycle. In this case, the node will stay in its original location rather than being relocated through the DOM elements again.Fixes: #4284 #3913
What is the new behavior?
Instead of using
putBackInOriginalLocation()
when we identify changed nodes, this PR introduces a new method,relocateToHostRoot()
. This method will move all nodes that were slotted into the changed node to the root of the element currently being rendered. So, when we enter therenderVdom()
method for the component, it will be able to relocate any slotted content back to its new location.Does this introduce a breaking change?
Testing
Manual testing
Two test cases can be reproduced using the repros from the linked issues and a build of this branch. These cases are also covered by e2e test.
A third test case can be created similar to the following (testing same behavior as first two, just more complex):
extras.experimentalSlotFixes
in the Stencil configsrc/index.html
to have the followingbody
span
tag in thebase-cmp
component.span
tag after clicking the button. All "statically slotted" content will also render in the expected order ("yooo", "howdy", "hello")Automated testing
All existing unit & e2e tests continue to pass. Also added new e2e tests for the reproduction cases in the linked issues.
Other information
Only available with the
experimentalSlotFixes
extra flag enabled.