Skip to content
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

SSR with Vue.js when using slots: The client-side rendered virtual DOM tree is not matching server-rendered content #2905

Open
fdeneux opened this issue May 12, 2021 · 13 comments
Labels
Resolution: Refine This PR is marked for Jira refinement. We're not working on it - we're talking it through. slot-related

Comments

@fdeneux
Copy link

fdeneux commented May 12, 2021

Stencil version:

 @stencil/core@2.5.2

I'm submitting a:
[x] bug report
[ ] feature request
[ ] support request

Current behavior:
Putting content in the Stencil component's slot in Vue.js throws an error on hydrate.

Expected behavior:
The client-side rendered virtual DOM tree should match the server-rendered content.

Steps to reproduce:

  1. Create a Stencil component with a <slot />.
  2. Setup a Nuxt.js or Vue.js project with SSR.
  3. Use the Stencil component in a Vue.js component and put some content in the slot.
  4. SSR the Vue.js page/component.

Related code:

Stencil component

import { Component, Host, h } from '@stencil/core';

@Component({
  tag: 'bs-slot-component',
  shadow: false,
  scoped: true,
})
export class SlotComponent {
  render() {
    return (
      <Host>
        <slot />
      </Host>
    );
  }
}

Vue.js component

<template>
  <bs-slot-component>
    <div>Content in slot</div>
  </bs-slot-component>
</template>

Nuxt.js module to hydrate Stencil components

import { renderToString } from 'path/to/hydrate';

export default function() {
  this.nuxt.hook('render:route', async (_, page) => {
    const render = await renderToString(page.html);
    page.html = render.html;
  })
}

Other information:
Possible cause might be Stencil updating HTML comments on hydrate.

image

@ionitron-bot ionitron-bot bot added the triage label May 12, 2021
@fdeneux fdeneux changed the title Vue.js hydrate SSR with Vue.js when using slots: The client-side rendered virtual DOM tree is not matching server-rendered content May 12, 2021
@william-will-angi
Copy link

We are also running into this issue for our use case. Have you found any workaround? I've tried playing with some of the renderToString options, but have been unsuccessful so far.

@fdeneux
Copy link
Author

fdeneux commented Aug 26, 2021

@william-will-angi we tried as well, but no workaround at the moment. We either render some components client-side only, or migrate Stencil components to Vue.js to be able to use slots when SSR.

@splitinfinities
Copy link
Contributor

Hey there, thank you for the patience, and thank you for reporting this. I'm curious if someone could put together a reproduction repo in Github? That would help us research this problem sooner than later.

@splitinfinities
Copy link
Contributor

Oh, also, can you confirm for me if you're using the Vue bindings for the Stencil component?

@william-will-angi
Copy link

Hi @splitinfinities thank you for the reply!

I have created a repro here: https://github.com/william-will-angi/nuxt-stencil-example

You can repro by:

  • cd component-library
  • npm i && npm run build && npm link
  • cd ../nuxt-app
  • npm i && npm link component library
  • npm run dev

If you follow these steps, you will see something similar to the attached screenshot.

I am not using the Vue bindings in this repro, however I did try in my downstream project and had the same results.
Screen Shot 2021-08-26 at 10 12 57 AM

@4aficiona2
Copy link

4aficiona2 commented Nov 2, 2021

@fdeneux @william-will-angi Did you find a solution to get this working with Nuxt/Stencil and could @splitinfinities you reproduce this issue?

We (@feerglas) noticed the same behavior with our setup and have the same issue.
We use ...

"nuxt": "^2.15.7"

which uses Stencil Components created with

"@stencil/core": "~2.9.0"

@william-will-angi
Copy link

@4aficiona2 Unfortunately, we never found a solution

@4aficiona2
Copy link

4aficiona2 commented Nov 2, 2021

@william-will-angi Hm, this is not what we hoped to hear ;)

We noticed that the hydration in @11ty/eleventy 11ty seems to work fine (and without throwing any errors). Have you tried other SSR solutions?

@william-will-angi
Copy link

william-will-angi commented Nov 2, 2021

For us, this drawback was enough to have us put our stencil efforts on pause. Through my research, I did come across this github issue mentioning @skatejs/ssr, but we decided we didn't want to spend any more effort. Would be curious if you find another alternative that works though!

Edit: forgot the link to the issue

@feerglas
Copy link

feerglas commented Nov 3, 2021

hi @splitinfinities, just in case, i made a sample repo where i did use vue-server-renderer to render stencil generated web components in an express server. as far as i can tell, server-side hydration works as expected there. Is this probably an indication that the problem is not caused by failure from stencil and not from vue, but from nuxt?

https://github.com/feerglas/vuessr

@fdeneux
Copy link
Author

fdeneux commented Nov 4, 2021

Thank you @feerglas, but your sample repo isn't really a Vue.js app, it doesn't mount a Vue.js instance on the front-end for re-hydration. My original issue was discovered on a Vue.js app, Nuxt.js just makes it easy to test with SSR.

@johnjenkins
Copy link
Contributor

johnjenkins commented Nov 18, 2021

I've not looked into this issue, but I'm gonna guess it's something around how stencil renders it's pretend "<slot />" during non-shadowDom client renders.

In order to re-create slot behaviour, outside of shadowDom, stencil uses empty text nodes as placeholders for where the slot would normally be. With this, it maintains an unobtrusive anchor for where slotted content should go whilst maintaining a bunch of other meta about the slot too.

My guess is, nuxt constructs a bunch of nodes using the server hydrated html which doesn't account for empty text nodes - so when the client renders some extra empty text nodes it decides there's a mis-match.

I know nothing of nuxt, but if there was a way to make it more relaxed about empty text nodes then it should work.
Another solution would be to change empty text nodes to empty comments in the stencil renderer - at least they can be represented in server rendered output?

@feerglas
Copy link

@fdeneux you are totally right, this example does not use client-side re-hydration. It was just to show to server-side hydration is not an issue.

@rwaskiewicz rwaskiewicz added Resolution: Needs Investigation This PR or Issue should be investigated from the Stencil team and removed Feature: SSR labels Mar 25, 2022
@rwaskiewicz rwaskiewicz added slot-related and removed Resolution: Needs Investigation This PR or Issue should be investigated from the Stencil team labels Sep 6, 2023
@rwaskiewicz rwaskiewicz added the Resolution: Refine This PR is marked for Jira refinement. We're not working on it - we're talking it through. label Sep 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Refine This PR is marked for Jira refinement. We're not working on it - we're talking it through. slot-related
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants