fix(ssr): make isInSSRComponentSetup state sharable across copies of Vue

This also fixes the issue when rendering async components in
the SFC playground with SSR enabled.
This commit is contained in:
Evan You 2023-12-12 21:34:40 +08:00
parent b010fcfc5c
commit e04d821422
1 changed files with 30 additions and 17 deletions

View File

@ -630,13 +630,10 @@ export let currentInstance: ComponentInternalInstance | null = null
export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
currentInstance || currentRenderingInstance
type GlobalInstanceSetter = ((
let internalSetCurrentInstance: (
instance: ComponentInternalInstance | null
) => void) & { version?: string }
let internalSetCurrentInstance: GlobalInstanceSetter
let globalCurrentInstanceSetters: GlobalInstanceSetter[]
let settersKey = '__VUE_INSTANCE_SETTERS__'
) => void
let setInSSRSetupState: (state: boolean) => void
/**
* The following makes getCurrentInstance() usage across multiple copies of Vue
@ -651,21 +648,36 @@ let settersKey = '__VUE_INSTANCE_SETTERS__'
* found during browser execution.
*/
if (__SSR__) {
if (!(globalCurrentInstanceSetters = getGlobalThis()[settersKey])) {
globalCurrentInstanceSetters = getGlobalThis()[settersKey] = []
}
globalCurrentInstanceSetters.push(i => (currentInstance = i))
internalSetCurrentInstance = instance => {
if (globalCurrentInstanceSetters.length > 1) {
globalCurrentInstanceSetters.forEach(s => s(instance))
} else {
globalCurrentInstanceSetters[0](instance)
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) => {
@ -699,7 +711,7 @@ export function setupComponent(
instance: ComponentInternalInstance,
isSSR = false
) {
isInSSRComponentSetup = isSSR
isSSR && setInSSRSetupState(isSSR)
const { props, children } = instance.vnode
const isStateful = isStatefulComponent(instance)
@ -709,7 +721,8 @@ export function setupComponent(
const setupResult = isStateful
? setupStatefulComponent(instance, isSSR)
: undefined
isInSSRComponentSetup = false
isSSR && setInSSRSetupState(false)
return setupResult
}