refactor: split current instance logic to separate file

This commit is contained in:
Evan You 2024-12-05 21:25:16 +08:00
parent 4baaa7bca3
commit ee7a93df27
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
2 changed files with 83 additions and 74 deletions

View File

@ -66,7 +66,6 @@ import {
NOOP,
ShapeFlags,
extend,
getGlobalThis,
isArray,
isBuiltInTag,
isFunction,
@ -76,7 +75,6 @@ import {
import type { SuspenseBoundary } from './components/Suspense'
import type { CompilerOptions } from '@vue/compiler-core'
import { markAttrsAccessed } from './componentRenderUtils'
import { currentRenderingInstance } from './componentRenderContext'
import { endMeasure, startMeasure } from './profiling'
import { convertLegacyRenderFn } from './compat/renderFn'
import {
@ -96,6 +94,13 @@ import type { DefineComponent } from './apiDefineComponent'
import { markAsyncBoundary } from './helpers/useId'
import { isAsyncWrapper } from './apiAsyncComponent'
import type { RendererElement } from './renderer'
import {
setCurrentInstance,
setInSSRSetupState,
unsetCurrentInstance,
} from './componentCurrentInstance'
export * from './componentCurrentInstance'
export type Data = Record<string, unknown>
@ -761,76 +766,6 @@ export function createComponentInstance(
return instance
}
export let currentInstance: ComponentInternalInstance | null = null
export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
currentInstance || currentRenderingInstance
let internalSetCurrentInstance: (
instance: ComponentInternalInstance | null,
) => void
let setInSSRSetupState: (state: boolean) => void
/**
* The following makes getCurrentInstance() usage across multiple copies of Vue
* work. Some cases of how this can happen are summarized in #7590. In principle
* the duplication should be avoided, but in practice there are often cases
* where the user is unable to resolve on their own, especially in complicated
* SSR setups.
*
* Note this fix is technically incomplete, as we still rely on other singletons
* for effectScope and global reactive dependency maps. However, it does make
* some of the most common cases work. It also warns if the duplication is
* found during browser execution.
*/
if (__SSR__) {
type Setter = (v: any) => void
const g = getGlobalThis()
const registerGlobalSetter = (key: string, setter: Setter) => {
let setters: Setter[]
if (!(setters = g[key])) setters = g[key] = []
setters.push(setter)
return (v: any) => {
if (setters.length > 1) setters.forEach(set => set(v))
else setters[0](v)
}
}
internalSetCurrentInstance = registerGlobalSetter(
`__VUE_INSTANCE_SETTERS__`,
v => (currentInstance = v),
)
// also make `isInSSRComponentSetup` sharable across copies of Vue.
// this is needed in the SFC playground when SSRing async components, since
// we have to load both the runtime and the server-renderer from CDNs, they
// contain duplicated copies of Vue runtime code.
setInSSRSetupState = registerGlobalSetter(
`__VUE_SSR_SETTERS__`,
v => (isInSSRComponentSetup = v),
)
} else {
internalSetCurrentInstance = i => {
currentInstance = i
}
setInSSRSetupState = v => {
isInSSRComponentSetup = v
}
}
export const setCurrentInstance = (instance: ComponentInternalInstance) => {
const prev = currentInstance
internalSetCurrentInstance(instance)
instance.scope.on()
return (): void => {
instance.scope.off()
internalSetCurrentInstance(prev)
}
}
export const unsetCurrentInstance = (): void => {
currentInstance && currentInstance.scope.off()
internalSetCurrentInstance(null)
}
export function validateComponentName(
name: string,
{ isNativeTag }: AppConfig,
@ -848,8 +783,6 @@ export function isStatefulComponent(
return instance.vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
}
export let isInSSRComponentSetup = false
export function setupComponent(
instance: ComponentInternalInstance,
isSSR = false,

View File

@ -0,0 +1,76 @@
import { getGlobalThis } from '@vue/shared'
import type { ComponentInternalInstance } from './component'
import { currentRenderingInstance } from './componentRenderContext'
export let currentInstance: ComponentInternalInstance | null = null
export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
currentInstance || currentRenderingInstance
export let isInSSRComponentSetup = false
export let setInSSRSetupState: (state: boolean) => void
let internalSetCurrentInstance: (
instance: ComponentInternalInstance | null,
) => void
/**
* The following makes getCurrentInstance() usage across multiple copies of Vue
* work. Some cases of how this can happen are summarized in #7590. In principle
* the duplication should be avoided, but in practice there are often cases
* where the user is unable to resolve on their own, especially in complicated
* SSR setups.
*
* Note this fix is technically incomplete, as we still rely on other singletons
* for effectScope and global reactive dependency maps. However, it does make
* some of the most common cases work. It also warns if the duplication is
* found during browser execution.
*/
if (__SSR__) {
type Setter = (v: any) => void
const g = getGlobalThis()
const registerGlobalSetter = (key: string, setter: Setter) => {
let setters: Setter[]
if (!(setters = g[key])) setters = g[key] = []
setters.push(setter)
return (v: any) => {
if (setters.length > 1) setters.forEach(set => set(v))
else setters[0](v)
}
}
internalSetCurrentInstance = registerGlobalSetter(
`__VUE_INSTANCE_SETTERS__`,
v => (currentInstance = v),
)
// also make `isInSSRComponentSetup` sharable across copies of Vue.
// this is needed in the SFC playground when SSRing async components, since
// we have to load both the runtime and the server-renderer from CDNs, they
// contain duplicated copies of Vue runtime code.
setInSSRSetupState = registerGlobalSetter(
`__VUE_SSR_SETTERS__`,
v => (isInSSRComponentSetup = v),
)
} else {
internalSetCurrentInstance = i => {
currentInstance = i
}
setInSSRSetupState = v => {
isInSSRComponentSetup = v
}
}
export const setCurrentInstance = (instance: ComponentInternalInstance) => {
const prev = currentInstance
internalSetCurrentInstance(instance)
instance.scope.on()
return (): void => {
instance.scope.off()
internalSetCurrentInstance(prev)
}
}
export const unsetCurrentInstance = (): void => {
currentInstance && currentInstance.scope.off()
internalSetCurrentInstance(null)
}