| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- import { ComponentInternalInstance } from './component'
- import { devtoolsComponentUpdated } from './devtools'
- import { setBlockTracking } from './vnode'
- /**
- * mark the current rendering instance for asset resolution (e.g.
- * resolveComponent, resolveDirective) during render
- */
- export let currentRenderingInstance: ComponentInternalInstance | null = null
- export let currentScopeId: string | null = null
- /**
- * Note: rendering calls maybe nested. The function returns the parent rendering
- * instance if present, which should be restored after the render is done:
- *
- * ```js
- * const prev = setCurrentRenderingInstance(i)
- * // ...render
- * setCurrentRenderingInstance(prev)
- * ```
- */
- export function setCurrentRenderingInstance(
- instance: ComponentInternalInstance | null
- ): ComponentInternalInstance | null {
- const prev = currentRenderingInstance
- currentRenderingInstance = instance
- currentScopeId = (instance && instance.type.__scopeId) || null
- // v2 pre-compiled components uses _scopeId instead of __scopeId
- if (__COMPAT__ && !currentScopeId) {
- currentScopeId = (instance && (instance.type as any)._scopeId) || null
- }
- return prev
- }
- /**
- * Set scope id when creating hoisted vnodes.
- * @private compiler helper
- */
- export function pushScopeId(id: string | null) {
- currentScopeId = id
- }
- /**
- * Technically we no longer need this after 3.0.8 but we need to keep the same
- * API for backwards compat w/ code generated by compilers.
- * @private
- */
- export function popScopeId() {
- currentScopeId = null
- }
- /**
- * Only for backwards compat
- * @private
- */
- export const withScopeId = (_id: string) => withCtx
- export type ContextualRenderFn = {
- (...args: any[]): any
- _n: boolean /* already normalized */
- _c: boolean /* compiled */
- _d: boolean /* disableTracking */
- _ns: boolean /* nonScoped */
- }
- /**
- * Wrap a slot function to memoize current rendering instance
- * @private compiler helper
- */
- export function withCtx(
- fn: Function,
- ctx: ComponentInternalInstance | null = currentRenderingInstance,
- isNonScopedSlot?: boolean // __COMPAT__ only
- ) {
- if (!ctx) return fn
- // already normalized
- if ((fn as ContextualRenderFn)._n) {
- return fn
- }
- const renderFnWithContext: ContextualRenderFn = (...args: any[]) => {
- // If a user calls a compiled slot inside a template expression (#1745), it
- // can mess up block tracking, so by default we disable block tracking and
- // force bail out when invoking a compiled slot (indicated by the ._d flag).
- // This isn't necessary if rendering a compiled `<slot>`, so we flip the
- // ._d flag off when invoking the wrapped fn inside `renderSlot`.
- if (renderFnWithContext._d) {
- setBlockTracking(-1)
- }
- const prevInstance = setCurrentRenderingInstance(ctx)
- let res
- try {
- res = fn(...args)
- } finally {
- setCurrentRenderingInstance(prevInstance)
- if (renderFnWithContext._d) {
- setBlockTracking(1)
- }
- }
- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
- devtoolsComponentUpdated(ctx)
- }
- return res
- }
- // mark normalized to avoid duplicated wrapping
- renderFnWithContext._n = true
- // mark this as compiled by default
- // this is used in vnode.ts -> normalizeChildren() to set the slot
- // rendering flag.
- renderFnWithContext._c = true
- // disable block tracking by default
- renderFnWithContext._d = true
- // compat build only flag to distinguish scoped slots from non-scoped ones
- if (__COMPAT__ && isNonScopedSlot) {
- renderFnWithContext._ns = true
- }
- return renderFnWithContext
- }
|