core icon indicating copy to clipboard operation
core copied to clipboard

v-text and v-html and may be other built-in (custom may be too) directives on custom component with slot in SSR

Open max5432112345 opened this issue 3 years ago • 11 comments

Vue version

3

Link to minimal reproduction

Vue 3 https://stackblitz.com/edit/github-lf1exv?terminal=dev

Nuxt 3 https://github.com/max5432112345/nuxt-error-2/

Steps to reproduce

If use v-text on custom component with slot when in SPA text is displayed in page but in SSR not displayed (hot reload only sometime make it to display but after refresh page disappear).

Index.vue

<template>
  <div>
    <CustomText v-text="'test'" />
     <CustomText> TEST </CustomText>
  </div>
</template>

CustomText.vue

<template>
  <span>
    <slot name="default" />
  </span>
</template>

What is expected?

We certainly want behaviour similar on SSR vs SPA when using v-text

What is actually happening?

In vue 2 it produced early warnings (Hydration children mismatch) when used v-text without inner text (and I add $nbsp; to bypass that) but now no errors or warnings. Now in vue 3 it not permit to use inner text and v-text together.

In that situation it not show errors or warnings like vue 2:

System Info

vue 3
linux

Any additional comments?

https://github.com/nuxt/nuxt.js/issues/14530

max5432112345 avatar Aug 09 '22 18:08 max5432112345

@yyx990803 v-html the same story.

max5432112345 avatar Aug 11 '22 06:08 max5432112345

@yyx990803

mittci avatar Nov 15 '22 08:11 mittci

The root cause is that directives with children overwrite (e.g. v-html & v-text) are not working with Component yet in SSR. here is a workaround

edison1105 avatar Nov 29 '22 07:11 edison1105

@edison1105 Can we get any ETA for this issue?

wvffle avatar Feb 05 '23 15:02 wvffle

+ 1

vampics avatar Feb 13 '23 13:02 vampics

  • This problem is still present

nimens55 avatar Mar 15 '23 18:03 nimens55

see #6553 and https://github.com/vuejs/core/issues/6553#issuecomment-1232468857

edison1105 avatar Apr 24 '23 05:04 edison1105

My use case:

I want to create a JSON-LD script tag with metadata. I want to use data passed to a component as props.

No workaround is available for this AFAIK.

rivatove avatar Jul 18 '23 13:07 rivatove

Here is my workaround:

/**
 * This is similar to `component(:is="tag")`, except that it also works in SSR.
 *
 * See:
 * - https://discord.com/channels/473401852243869706/1152225826910244955/1152225826910244955
 * - https://stackblitz.com/edit/github-gs1ptn
 * - https://github.com/vuejs/core/issues/6553#issuecomment-1232468857
 * - https://github.com/vuejs/core/issues/6435
 * - https://play.vuejs.org/#__SSR__eNp9UctOwzAQ/BXLl7RSlR64hbQSVJUA8RL0hjlEybZ1SWzLXpdIVf4dP5ISJMCHaDM7O57xnuiVUunRAs1ojtCoukBYMkFIXvFjKFy5sgZls4EWSYbuu2A0QTCYMErmkT2P9Hw+EslNqblCYgCtcv+8UVIjGalttWxIks5XsgkuEq8Qp5Z0RgfYm+vRs8qJ7EnXC8RJaEOjgm1ha0fwvpSWymRvzm2LyfvMQ8HNJDSmkUSIdpgWZDIliz4zIftJ4jIls4HjDxcC9M3m4T6LyqnXDar+dNNLX3YO6H4GQVNKseW79GCkcGmCJKOly8dr0E8KuRSG0Wy4jNGiruXnXcBQW+gvcTN7KD9+wQ+m9RijzxoM6CMweu5hoXeAsb1+fXSeR81GVrZ27H+aL2Bkbb3HSLu2onK2R7zg9jZshovdxqxbBGGGUN7o8DKe7fblV/tX9G+7F+lFmHMPSrsvfIzfCg==
 */
export default defineComponent({
  props: {
    tag: {
      type: String,
      required: true,
    },
    html: {
      type: String,
      required: true,
    },
  },

  setup(props, { slots }) {
    return () => h(props.tag, { innerHTML: props.html });
  },
});

rudolfbyker avatar Sep 15 '23 16:09 rudolfbyker

Not that hard to make your own v-html directive that works SSR. Here is mine:

  nuxtApp.vueApp.directive('thtml', {
    mounted: (el: HTMLElement, binding: any, vnode: any) => {
      el.innerHTML = binding.value;
    },
    getSSRProps(binding: any) {
      return {
        innerHTML: binding.value
      }
    }
  })

oppianmatt avatar Dec 06 '23 11:12 oppianmatt

But v-html does not work on custom components even in SPA mode, not just SSR, see example here.

Expected output should be:

<div class="component"><div class="wrap"><div class="inner">Inner</div></div></div>

But it is:

<div class="component"><div class="wrap"><div class="wrap2"><div class="inner">Inner</div></div></div></div>

There is an eslint rule because of this. Maybe this means that this is a more general bug/limitation of Vue?

mitar avatar Mar 18 '24 13:03 mitar