vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
46.66k stars 8.18k forks source link

TypeError: When using template around template slot #11521

Open Disservin opened 1 month ago

Disservin commented 1 month ago

Vue version

3.4.35

Link to minimal reproduction

https://play.vuejs.org/#eNqFkk1PwzAMhv9KFA4DabRChcvoQIB2gAMgxjESqlp3ZLRJlY8yaep/x0k/VqQybonfx4n92nt6V1VBbYEuaKxTxStDNBhb3TDBy0oqQx5kWV2QXMmSzILQ31zC7JqJOGxTEMaLgbIqEgN4IyT2YHtsk/AchwND59ToVIqcb4KtlgL/3zuY0RRhXoB6qQyXQjO6IF5xWlIU8vvJx4yyMO/j6SekXxPxrd65GKOvCjSoGhgdNJOoDZhWXq2fYYfnQSxlZgukj4hvoGVhXY0tdm9FhmWPOF/to3eRi827Xu0MCN035Qp1ZON5RtFT59NfrR/KjYLI5zHRoIsuZ3KAx4aT8dof8KgLaYhISlgyypFi1GVisJtdi44mx0T3q1+D43vza236ren0PbEa1viRJk3HdQATuBgaH/TicuBOz/5fub6tXiH1Oc+xNf/WbZBBntgCbey4MXni2h/ivTXhgRx7MBFo93zCrI8alBs7ehUFl0F0RZsfhdgklw==

Steps to reproduce

Add another template around the template slot

<template>
  <Comp>
      <template #item>
        <slot />
      </template>
  </Comp>
</template>

so that it looks like this

<template>
  <Comp>
    <template v-if="slots?.default">
      <template #item>
        <slot />
      </template>
    </template>
  </Comp>
</template>
TypeError: Cannot read properties of undefined (reading 'type')

What is expected?

No type error, or an error saying that this syntax isn't support (i'm not sure if this is actually supposed to work?)

What is actually happening?

TypeError: Cannot read properties of undefined (reading 'type')
    at getMemoedVNodeCall (compiler-sfc.esm-browser.js:17146:12)
    at createChildrenCodegenNode (compiler-sfc.esm-browser.js:22946:23)
    at createCodegenNodeForBranch (compiler-sfc.esm-browser.js:22892:7)
    at Array.<anonymous> (compiler-sfc.esm-browser.js:22782:32)
    at traverseNode (compiler-sfc.esm-browser.js:18413:15)
    at traverseChildren (compiler-sfc.esm-browser.js:18365:5)
    at traverseNode (compiler-sfc.esm-browser.js:18407:7)
    at transform (compiler-sfc.esm-browser.js:18302:3)

System Info

No response

Any additional comments?

No response

Disservin commented 1 month ago

Workaround just specify the v-if on the slot directly.

    <template #item v-if="slots?.default">
      <slot />
    </template>
Disservin commented 1 month ago

However, there's a drawback that the Component which exposes the item slot still see's a slot being passed, which I wouldn't expect since the v-if condition is false.

Vue Playground

(View the console)

jh-leong commented 1 month ago

However, there's a drawback that the Component which exposes the item slot still see's a slot being passed, which I wouldn't expect since the v-if condition is false.

Vue Playground

(View the console)

You should get the specific slot by the key corresponding to that slot's name, like useSlots().item (Playground).

Disservin commented 1 month ago

However, there's a drawback that the Component which exposes the item slot still see's a slot being passed, which I wouldn't expect since the v-if condition is false. Vue Playground (View the console)

You should get the specific slot by the key corresponding to that slot's name, like useSlots().item (Playground).

Ah yes, it is indeed empty. I only got confused because the slots object wasn't empty image

but the specific item slot is empty so all is well

edison1105 commented 1 month ago

I think this is an incorrect use of slot

Disservin commented 1 month ago

Yeah I wasn't entirely sure if this is a valid use.. has it always been like this in the past ? Dunno how I can go further back in the playground..

jacekkarczmarczyk commented 1 month ago

For the following code:

    <my-component-with-hint-slot>
      <template v-if="true">
        <template #hint>hint</template>
      </template>
    </my-component-with-hint-slot>

in Vue 2 I'm getting "<template v-slot> can only appear at the root level inside the receiving component" error from the compiler, I have also eslint warning 'v-slot' directive must be owned by a custom element, but 'template' is not, so I'm pretty sure it was always like this, maybe just the produced errors were different in different versions of Vue

Disservin commented 1 month ago

Ah I think this "<template v-slot> can only appear at the root level inside the receiving component" would be nice to have. Current core code doesn't have this. I had a look at the source and the code is failing during the transform already before even vSlot.ts is reached (where I think this warning should be emitted from?)

edison1105 commented 1 month ago

Ah I think this "<template v-slot> can only appear at the root level inside the receiving component" would be nice to have. Current core code doesn't have this. I had a look at the source and the code is failing during the transform already before even vSlot.ts is reached (where I think this warning should be emitted from?)

I agree with this. We need to emit user-friendly error at compile phase to align with vue2

Disservin commented 1 month ago

Yes that'd be nice, after going through the vue2 source there were a couple more warnings which don't exist in that form in vue3 but I haven't checked which of these need to be ported to vue3.