fix(ssr): properly update currentRenderingInstance state during ssr
fix #2863
This commit is contained in:
parent
9036f88d83
commit
8c3c14a0ff
@ -9,11 +9,23 @@ import { closeBlock, openBlock } from './vnode'
|
|||||||
export let currentRenderingInstance: ComponentInternalInstance | null = null
|
export let currentRenderingInstance: ComponentInternalInstance | null = null
|
||||||
export let currentScopeId: string | null = null
|
export let currentScopeId: string | null = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: rendering calls maybe nested. The function returns the parent rendering
|
||||||
|
* instance if present, which should be restored after the render is done:
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* const prev = setCurrentRenderingInstance(i)
|
||||||
|
* // ...render
|
||||||
|
* setCurrentRenderingInstance(prev)
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export function setCurrentRenderingInstance(
|
export function setCurrentRenderingInstance(
|
||||||
instance: ComponentInternalInstance | null
|
instance: ComponentInternalInstance | null
|
||||||
) {
|
): ComponentInternalInstance | null {
|
||||||
|
const prev = currentRenderingInstance
|
||||||
currentRenderingInstance = instance
|
currentRenderingInstance = instance
|
||||||
currentScopeId = (instance && instance.type.__scopeId) || null
|
currentScopeId = (instance && instance.type.__scopeId) || null
|
||||||
|
return prev
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,8 +52,7 @@ export function withCtx(
|
|||||||
if (!isRenderingCompiledSlot) {
|
if (!isRenderingCompiledSlot) {
|
||||||
openBlock(true /* null block that disables tracking */)
|
openBlock(true /* null block that disables tracking */)
|
||||||
}
|
}
|
||||||
const prevInstance = currentRenderingInstance
|
const prevInstance = setCurrentRenderingInstance(ctx)
|
||||||
setCurrentRenderingInstance(ctx)
|
|
||||||
const res = fn(...args)
|
const res = fn(...args)
|
||||||
setCurrentRenderingInstance(prevInstance)
|
setCurrentRenderingInstance(prevInstance)
|
||||||
if (!isRenderingCompiledSlot) {
|
if (!isRenderingCompiledSlot) {
|
||||||
|
@ -53,7 +53,7 @@ export function renderComponentRoot(
|
|||||||
} = instance
|
} = instance
|
||||||
|
|
||||||
let result
|
let result
|
||||||
setCurrentRenderingInstance(instance)
|
const prev = setCurrentRenderingInstance(instance)
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
accessedAttrs = false
|
accessedAttrs = false
|
||||||
}
|
}
|
||||||
@ -207,7 +207,7 @@ export function renderComponentRoot(
|
|||||||
result = createVNode(Comment)
|
result = createVNode(Comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentRenderingInstance(null)
|
setCurrentRenderingInstance(prev)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,9 @@ import {
|
|||||||
withCtx,
|
withCtx,
|
||||||
KeepAlive,
|
KeepAlive,
|
||||||
Transition,
|
Transition,
|
||||||
watchEffect
|
watchEffect,
|
||||||
|
createVNode,
|
||||||
|
resolveDynamicComponent
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { escapeHtml } from '@vue/shared'
|
import { escapeHtml } from '@vue/shared'
|
||||||
import { renderToString } from '../src/renderToString'
|
import { renderToString } from '../src/renderToString'
|
||||||
@ -19,6 +21,7 @@ import { renderToStream as _renderToStream } from '../src/renderToStream'
|
|||||||
import { ssrRenderSlot, SSRSlot } from '../src/helpers/ssrRenderSlot'
|
import { ssrRenderSlot, SSRSlot } from '../src/helpers/ssrRenderSlot'
|
||||||
import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent'
|
import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent'
|
||||||
import { Readable } from 'stream'
|
import { Readable } from 'stream'
|
||||||
|
import { ssrRenderVNode } from '../src'
|
||||||
|
|
||||||
const promisifyStream = (stream: Readable) => {
|
const promisifyStream = (stream: Readable) => {
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
@ -824,5 +827,34 @@ function testRender(type: string, render: typeof renderToString) {
|
|||||||
})
|
})
|
||||||
expect(await render(app)).toBe('<!---->')
|
expect(await render(app)).toBe('<!---->')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #2863
|
||||||
|
test('assets should be resolved correctly', async () => {
|
||||||
|
expect(
|
||||||
|
await render(
|
||||||
|
createApp({
|
||||||
|
components: {
|
||||||
|
A: {
|
||||||
|
ssrRender(_ctx, _push) {
|
||||||
|
_push(`<div>A</div>`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
B: {
|
||||||
|
render: () => h('div', 'B')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ssrRender(_ctx, _push, _parent) {
|
||||||
|
const A: any = resolveComponent('A')
|
||||||
|
_push(ssrRenderComponent(A, null, null, _parent))
|
||||||
|
ssrRenderVNode(
|
||||||
|
_push,
|
||||||
|
createVNode(resolveDynamicComponent('B'), null, null),
|
||||||
|
_parent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).toBe(`<div>A</div><div>B</div>`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ function renderComponentSubTree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set current rendering instance for asset resolution
|
// set current rendering instance for asset resolution
|
||||||
setCurrentRenderingInstance(instance)
|
const prev = setCurrentRenderingInstance(instance)
|
||||||
ssrRender(
|
ssrRender(
|
||||||
instance.proxy,
|
instance.proxy,
|
||||||
push,
|
push,
|
||||||
@ -151,7 +151,7 @@ function renderComponentSubTree(
|
|||||||
instance.data,
|
instance.data,
|
||||||
instance.ctx
|
instance.ctx
|
||||||
)
|
)
|
||||||
setCurrentRenderingInstance(null)
|
setCurrentRenderingInstance(prev)
|
||||||
} else if (instance.render && instance.render !== NOOP) {
|
} else if (instance.render && instance.render !== NOOP) {
|
||||||
renderVNode(
|
renderVNode(
|
||||||
push,
|
push,
|
||||||
|
Loading…
Reference in New Issue
Block a user