Skip to content

Commit

Permalink
fix(ssr): make isInSSRComponentSetup state sharable across copies of Vue
Browse files Browse the repository at this point in the history
This also fixes the issue when rendering async components in
the SFC playground with SSR enabled.
  • Loading branch information
yyx990803 committed Dec 12, 2023
1 parent b010fcf commit e04d821
Showing 1 changed file with 30 additions and 17 deletions.
47 changes: 30 additions & 17 deletions packages/runtime-core/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) => {
Expand Down Expand Up @@ -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)
Expand All @@ -709,7 +721,8 @@ export function setupComponent(
const setupResult = isStateful
? setupStatefulComponent(instance, isSSR)
: undefined
isInSSRComponentSetup = false

isSSR && setInSSRSetupState(false)
return setupResult
}

Expand Down

0 comments on commit e04d821

Please sign in to comment.