Преглед изворни кода

fix(runtime-core): avoid the proxy object polluting the slots of the internal instance (#3698)

fix #3695
HcySunYang пре 4 година
родитељ
комит
4ce0df6ef1

+ 2 - 1
packages/runtime-core/src/componentRenderContext.ts

@@ -89,7 +89,8 @@ export function withCtx(
   // mark this as a compiled slot function.
   // mark this as a compiled slot function.
   // this is used in vnode.ts -> normalizeChildren() to set the slot
   // this is used in vnode.ts -> normalizeChildren() to set the slot
   // rendering flag.
   // rendering flag.
-  renderFnWithContext._c = true
+  // also used to cache the normalized results to avoid repeated normalization
+  renderFnWithContext._c = renderFnWithContext
   if (__COMPAT__ && isNonScopedSlot) {
   if (__COMPAT__ && isNonScopedSlot) {
     renderFnWithContext._nonScoped = true
     renderFnWithContext._nonScoped = true
   }
   }

+ 7 - 3
packages/runtime-core/src/componentSlots.ts

@@ -20,6 +20,7 @@ import { isKeepAlive } from './components/KeepAlive'
 import { withCtx } from './componentRenderContext'
 import { withCtx } from './componentRenderContext'
 import { isHmrUpdating } from './hmr'
 import { isHmrUpdating } from './hmr'
 import { DeprecationTypes, isCompatEnabled } from './compat/compatConfig'
 import { DeprecationTypes, isCompatEnabled } from './compat/compatConfig'
+import { toRaw } from '@vue/reactivity'
 
 
 export type Slot = (...args: any[]) => VNode[]
 export type Slot = (...args: any[]) => VNode[]
 
 
@@ -62,7 +63,8 @@ const normalizeSlot = (
   rawSlot: Function,
   rawSlot: Function,
   ctx: ComponentInternalInstance | null | undefined
   ctx: ComponentInternalInstance | null | undefined
 ): Slot =>
 ): Slot =>
-  withCtx((props: any) => {
+  (rawSlot as any)._c ||
+  (withCtx((props: any) => {
     if (__DEV__ && currentInstance) {
     if (__DEV__ && currentInstance) {
       warn(
       warn(
         `Slot "${key}" invoked outside of the render function: ` +
         `Slot "${key}" invoked outside of the render function: ` +
@@ -71,7 +73,7 @@ const normalizeSlot = (
       )
       )
     }
     }
     return normalizeSlotValue(rawSlot(props))
     return normalizeSlotValue(rawSlot(props))
-  }, ctx) as Slot
+  }, ctx) as Slot)
 
 
 const normalizeObjectSlots = (
 const normalizeObjectSlots = (
   rawSlots: RawSlots,
   rawSlots: RawSlots,
@@ -128,7 +130,9 @@ export const initSlots = (
   if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
   if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
     const type = (children as RawSlots)._
     const type = (children as RawSlots)._
     if (type) {
     if (type) {
-      instance.slots = children as InternalSlots
+      // users can get the shallow readonly version of the slots object through `this.$slots`,
+      // we should avoid the proxy object polluting the slots of the internal instance
+      instance.slots = toRaw(children as InternalSlots)
       // make compiler marker non-enumerable
       // make compiler marker non-enumerable
       def(children as InternalSlots, '_', type)
       def(children as InternalSlots, '_', type)
     } else {
     } else {