From e04d821422102446704e223c03e50d26cbb1fe69 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 12 Dec 2023 21:34:40 +0800 Subject: [PATCH] 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. --- packages/runtime-core/src/component.ts | 47 ++++++++++++++++---------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index b0f3bf82e..8e82c74c5 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -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 }