ionic-team / stencil

A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
https://stenciljs.com
Other
12.59k stars 789 forks source link

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

Closed fdeneux closed 4 months ago

fdeneux commented 3 years ago

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

william-will-angi commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

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 commented 3 years ago

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

william-will-angi commented 3 years ago

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:

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 commented 3 years ago

@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 commented 3 years ago

@4aficiona2 Unfortunately, we never found a solution

4aficiona2 commented 3 years ago

@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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 2 years ago

@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.

christian-bromann commented 4 months ago

@fdeneux thanks for raising the issue and sorry for providing such a delayed response to it. We have been shipped a lot of bug fixes especially around SSR and slot management. Unfortunately I can't get any of the reproduction cases to work for me anymore. I will go ahead and close the issue hoping that it has been resolved since this h as been posted. That said, I am happy to take a look if this bug still exists and can be reproduced on a new example using latest Stencil.

Thank you!