fix(compat): do not auto invoke scoped slots when accessed via $slots
#10875
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The problem
If the component has a render function and uses
this.$slots.name
expression somewhere, this usage might throw ifname
is used as a scoped slot and the data the slot passes is destructured.Why this happens?
If
RENDER_FUNCTION
compat feature is enabled and the component is using a render function (_compatWrapped
), all$slots.name
accesses will be intercepted by a proxy which will auto-invoke the corresponding function with no arguments:core/packages/runtime-core/src/compat/instance.ts
Lines 96 to 105 in c0c9432
If these arguments are destructured by a component user, this weird runtime error will occur:
(destructured parameter) is undefined
in Firefox orCannot destructure property '<property name>' of 'undefined' as it is undefined
in Chromium.The fix
This PR attempts to resolve the issue by avoiding invoking the slot if it has
_ns
(non-scoped slot) flag.Real-world examples
I'm trying to migrate to Vue 3 a legacy project with
[email protected]
using@vue/compat
. This line, for example, is only intending to check the slot presence, but ends up invoking it with no arguments andundefined
is ended up being destructured in user code.The other one: TypeError: Cannot destructure property 'element' of 'undefined' as it is undefined SortableJS/vue.draggable.next#122
I think this fix should not break the existing code which is written and used correctly because
$slots.name
)$slots
or$scopedSlots
respectively (whichvuetify
actually does).