1
1
import { ComponentInternalInstance } from './component'
2
2
import { devtoolsComponentUpdated } from './devtools'
3
- import { isRenderingCompiledSlot } from './helpers/renderSlot'
4
- import { closeBlock , openBlock } from './vnode'
3
+ import { setBlockTracking } from './vnode'
5
4
6
5
/**
7
6
* mark the current rendering instance for asset resolution (e.g.
@@ -56,6 +55,14 @@ export function popScopeId() {
56
55
*/
57
56
export const withScopeId = ( _id : string ) => withCtx
58
57
58
+ export type ContextualRenderFn = {
59
+ ( ...args : any [ ] ) : any
60
+ _n : boolean /* already normalized */
61
+ _c : boolean /* compiled */
62
+ _d : boolean /* disableTracking */
63
+ _ns : boolean /* nonScoped */
64
+ }
65
+
59
66
/**
60
67
* Wrap a slot function to memoize current rendering instance
61
68
* @private compiler helper
@@ -66,18 +73,26 @@ export function withCtx(
66
73
isNonScopedSlot ?: boolean // __COMPAT__ only
67
74
) {
68
75
if ( ! ctx ) return fn
69
- const renderFnWithContext = ( ...args : any [ ] ) => {
76
+
77
+ // already normalized
78
+ if ( ( fn as ContextualRenderFn ) . _n ) {
79
+ return fn
80
+ }
81
+
82
+ const renderFnWithContext : ContextualRenderFn = ( ...args : any [ ] ) => {
70
83
// If a user calls a compiled slot inside a template expression (#1745), it
71
- // can mess up block tracking, so by default we need to push a null block to
72
- // avoid that. This isn't necessary if rendering a compiled `<slot>`.
73
- if ( ! isRenderingCompiledSlot ) {
74
- openBlock ( true /* null block that disables tracking */ )
84
+ // can mess up block tracking, so by default we disable block tracking and
85
+ // force bail out when invoking a compiled slot (indicated by the ._d flag).
86
+ // This isn't necessary if rendering a compiled `<slot>`, so we flip the
87
+ // ._d flag off when invoking the wrapped fn inside `renderSlot`.
88
+ if ( renderFnWithContext . _d ) {
89
+ setBlockTracking ( - 1 )
75
90
}
76
91
const prevInstance = setCurrentRenderingInstance ( ctx )
77
92
const res = fn ( ...args )
78
93
setCurrentRenderingInstance ( prevInstance )
79
- if ( ! isRenderingCompiledSlot ) {
80
- closeBlock ( )
94
+ if ( renderFnWithContext . _d ) {
95
+ setBlockTracking ( 1 )
81
96
}
82
97
83
98
if ( __DEV__ || __FEATURE_PROD_DEVTOOLS__ ) {
@@ -86,13 +101,18 @@ export function withCtx(
86
101
87
102
return res
88
103
}
89
- // mark this as a compiled slot function.
104
+
105
+ // mark normalized to avoid duplicated wrapping
106
+ renderFnWithContext . _n = true
107
+ // mark this as compiled by default
90
108
// this is used in vnode.ts -> normalizeChildren() to set the slot
91
109
// rendering flag.
92
- // also used to cache the normalized results to avoid repeated normalization
93
- renderFnWithContext . _c = renderFnWithContext
110
+ renderFnWithContext . _c = true
111
+ // disable block tracking by default
112
+ renderFnWithContext . _d = true
113
+ // compat build only flag to distinguish scoped slots from non-scoped ones
94
114
if ( __COMPAT__ && isNonScopedSlot ) {
95
- renderFnWithContext . _nonScoped = true
115
+ renderFnWithContext . _ns = true
96
116
}
97
117
return renderFnWithContext
98
118
}
0 commit comments