]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(ssr): make isInSSRComponentSetup state sharable across copies of Vue
authorEvan You <yyx990803@gmail.com>
Tue, 12 Dec 2023 13:34:40 +0000 (21:34 +0800)
committerEvan You <yyx990803@gmail.com>
Tue, 12 Dec 2023 13:37:52 +0000 (21:37 +0800)
This also fixes the issue when rendering async components in
the SFC playground with SSR enabled.

packages/runtime-core/src/component.ts

index b0f3bf82ea861e8fdc6228487ba8d1d49df4336b..8e82c74c5f1e49b884477748caad127cb9ddca94 100644 (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
 }