-
Notifications
You must be signed in to change notification settings - Fork 7
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
Hydration is incorrect as some attributes are missing in the SSR HTML #34
Comments
I believe we can make it a little better by doing something like this attachPropsToRenderer(): void {
const customElementConstructor = getCustomElementConstructor(this.litElementTagName);
const props = this.litElementVnode.props;
if (props && this.renderer) {
for (const [key, value] of Object.entries(props)) {
// check if this is a reactive property
if (
customElementConstructor !== null && // The element exists
typeof customElementConstructor !== "string" && // It's not just a string
key in customElementConstructor.prototype && // The property we're looking for is on the prototype
["boolean", "function", "object"].includes(typeof value) // It's a value that doesn't render as an attribute
) {
this.renderer.setProperty(key, value);
} else {
this.renderer.setAttribute(key, value);
}
}
}
} This solves the basic issue, and the accordion component in the playground does not need to be reflected any more, but I'm not sure it's perfect. |
I don't think the Maybe it's also a matter of how Nuxt handles props/attributes for custom elements. I see only attributes are added as props here, would it make sense to pass in all props here? nuxt-ssr-lit/src/runtime/components/LitWrapperServer.ts Lines 109 to 115 in 4b72344
|
This broadly seems to work in the cases we have so far. I'm going to add more tests to see if I can cover the range of what is going on |
I think rendering out properties (that may or may not be reflected in attributes) as attributes always may cause issues related to #30 I think the underlying problem here is that the client-side render of the Lit component seems to happen incorrectly. When Vue/Nuxt renders the component like @augustjk correct me if my hunch is wrong here |
Hmm.. I think in principle that makes sense. For server rendering, setting property on the element only makes sense for generating the shadow dom, and the generated markup of the element should just contain the attributes, including any reflected properties. As @prashantpalikhe pointed out, the problem could lie more in how vdom node on the client side maps to the custom element. We did notice the vdom node did have all the props but wasn't setting them on the actual custom element on the client once loaded. Perhaps the difference in client/server behavior of the wrapper confuses Vue/Nuxt that it doesn't know the custom element generated from the |
I've added a test component based on one we have at Maersk that is showing the hydration and SSR issue in #35 (my-step-indicator). The outer component, which was wrapped in the The first error says The second error message is a side-effect of this as it's trying to hydrate something that doesn't match. |
The hydration error I think steps from the conditional render in |
@augustjk yes, in this case |
Is it specifically Vue/Nuxt not being able to provide array props to the element? That's odd! |
When looking a bit into the hydration issue earlier, I had noticed a strange situation where the custom element was instantiated was Vue and therefore passed in all the props while NOT using the SSR. But while using the SSR, the custom element was instantiated as soon as the custom element definition arrived on the browser. And the call stack showed nothing else. The first call in the call stack was UPDATE: This was not related to the issue. But did help me eventually get in the right direction. Check my comment below for the newer findings. |
So I dived into this further, investigating how Vue applies props to the custom elements while hydrating an SSR-ed application. And I found out that Vue does not apply props to components during hydration. You can see here that only props named IMO, this is the reason why we noticed that during Lit's hydration, the Lit components were instantiated without correct values (only default values). We got around this issue by rendering all props as attributes. But I think that's not always desirable (explicitly set by component authors to not reflect as an attribute) and in the case of complex data types, like array/objects, not possible either. But if we were to apply the props for custom elements during hydration on Vue's side, then the issue gets resolved. We do need to defer Lit's hydration until Vue's hydration is complete. But that's very simple to achieve by adding a I tried @steveworkman 's branch by making these modifications, including patching Vue's source code to apply props for custom elements during hydration, and the issue is resolved. Would be great to discuss this further with a Vue dev. to get their insight into this. |
@steveworkman I think this issue can be closed now, now that Vue has fixed the bug, right? |
Yes, fixed in 3.4.36 |
Describe the bug
Given a simple element with a label
This renders on the server without the
label
attribute as it's been set as a DOM property.When hydration comes around client-side, the component does not know what the value of
label
is as it's not been set as an attribute on the HTMLExpected behavior
Attributes needed for hydration should be rendered in the HTML response
Additional context
This could be a component issue, as setting a property to
reflect: true
resolves this for that component. However, I don't think that's reasonable for things like a label on a button. There's a lot of information in https://lit.dev/docs/components/properties/ but it's not clear what should happen with SSR.The text was updated successfully, but these errors were encountered: