]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): disable block tracking when calling compiled slot function in...
authorEvan You <yyx990803@gmail.com>
Fri, 21 Aug 2020 16:47:45 +0000 (12:47 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 21 Aug 2020 16:47:45 +0000 (12:47 -0400)
fix #1745, fix #1918

packages/runtime-core/src/helpers/renderSlot.ts
packages/runtime-core/src/helpers/withRenderContext.ts
packages/runtime-core/src/vnode.ts

index 68e1edcbe3cc552693512b8754eee3ee01710f92..be6dbba4a4275ed29684deba0166a0ee04f6430e 100644 (file)
@@ -10,7 +10,7 @@ import {
 import { PatchFlags, SlotFlags } from '@vue/shared'
 import { warn } from '../warning'
 
-export let shouldTrackInSlotRendering = 0
+export let isRenderingCompiledSlot = 0
 
 /**
  * Compiler runtime helper for rendering `<slot/>`
@@ -39,7 +39,7 @@ export function renderSlot(
   // invocation interfering with template-based block tracking, but in
   // `renderSlot` we can be sure that it's template-based so we can force
   // enable it.
-  shouldTrackInSlotRendering++
+  isRenderingCompiledSlot++
   const rendered = (openBlock(),
   createBlock(
     Fragment,
@@ -49,6 +49,6 @@ export function renderSlot(
       ? PatchFlags.STABLE_FRAGMENT
       : PatchFlags.BAIL
   ))
-  shouldTrackInSlotRendering--
+  isRenderingCompiledSlot--
   return rendered
 }
index bf1541fa11ab16e79e70e3bd1b29d4c4abdb3b01..4ac273f50b0949eaffea3dec5dd297cfef4d7b09 100644 (file)
@@ -4,7 +4,8 @@ import {
   currentRenderingInstance
 } from '../componentRenderUtils'
 import { ComponentInternalInstance } from '../component'
-import { setBlockTracking } from '../vnode'
+import { isRenderingCompiledSlot } from './renderSlot'
+import { closeBlock, openBlock } from '../vnode'
 
 /**
  * Wrap a slot function to memoize current rendering instance
@@ -16,15 +17,19 @@ export function withCtx(
 ) {
   if (!ctx) return fn
   return function renderFnWithContext() {
-    // By default, compiled slots disables block tracking since the user may
-    // call it inside a template expression (#1745). It should only track when
-    // it's called by a template `<slot>`.
-    setBlockTracking(-1)
+    // If a user calls a compiled slot inside a template expression (#1745), it
+    // can mess up block tracking, so by default we need to push a null block to
+    // avoid that. This isn't necessary if rendering a compiled `<slot>`.
+    if (!isRenderingCompiledSlot) {
+      openBlock(true /* null block that disables tracking */)
+    }
     const owner = currentRenderingInstance
     setCurrentRenderingInstance(ctx)
     const res = fn.apply(null, arguments as any)
     setCurrentRenderingInstance(owner)
-    setBlockTracking(1)
+    if (!isRenderingCompiledSlot) {
+      closeBlock()
+    }
     return res
   }
 }
index 8eadedca27ff585f726620aef3c5acded89cae24..efdd2b1114b76a64b4dedeb2a4a0c19bb27cbd48 100644 (file)
@@ -36,7 +36,6 @@ import { currentRenderingInstance } from './componentRenderUtils'
 import { RendererNode, RendererElement } from './renderer'
 import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
 import { hmrDirtyComponents } from './hmr'
-import { shouldTrackInSlotRendering } from './helpers/renderSlot'
 
 export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
   __isFragment: true
@@ -153,7 +152,7 @@ export interface VNode<
 // can divide a template into nested blocks, and within each block the node
 // structure would be stable. This allows us to skip most children diffing
 // and only worry about the dynamic nodes (indicated by patch flags).
-const blockStack: (VNode[] | null)[] = []
+export const blockStack: (VNode[] | null)[] = []
 let currentBlock: VNode[] | null = null
 
 /**
@@ -176,6 +175,11 @@ export function openBlock(disableTracking = false) {
   blockStack.push((currentBlock = disableTracking ? null : []))
 }
 
+export function closeBlock() {
+  blockStack.pop()
+  currentBlock = blockStack[blockStack.length - 1] || null
+}
+
 // Whether we should be tracking dynamic child nodes inside a block.
 // Only tracks when this value is > 0
 // We are not using a simple boolean because this value may need to be
@@ -227,8 +231,7 @@ export function createBlock(
   // save current block children on the block vnode
   vnode.dynamicChildren = currentBlock || EMPTY_ARR
   // close block
-  blockStack.pop()
-  currentBlock = blockStack[blockStack.length - 1] || null
+  closeBlock()
   // a block is always going to be patched, so track it as a child of its
   // parent block
   if (currentBlock) {
@@ -403,7 +406,7 @@ function _createVNode(
   normalizeChildren(vnode, children)
 
   if (
-    (shouldTrack > 0 || shouldTrackInSlotRendering > 0) &&
+    shouldTrack > 0 &&
     // avoid a block node from tracking itself
     !isBlockNode &&
     // has current parent block