refactor(ssr): extract buffer resolving and resolvePortals (#771)
This commit is contained in:
parent
20afd4093d
commit
047844cfb8
@ -67,9 +67,11 @@ function createBuffer() {
|
|||||||
let hasAsync = false
|
let hasAsync = false
|
||||||
const buffer: SSRBuffer = []
|
const buffer: SSRBuffer = []
|
||||||
return {
|
return {
|
||||||
buffer,
|
getBuffer(): ResolvedSSRBuffer | Promise<ResolvedSSRBuffer> {
|
||||||
hasAsync() {
|
// If the current component's buffer contains any Promise from async children,
|
||||||
return hasAsync
|
// then it must return a Promise too. Otherwise this is a component that
|
||||||
|
// contains only sync children so we can avoid the async book-keeping overhead.
|
||||||
|
return hasAsync ? Promise.all(buffer) : (buffer as ResolvedSSRBuffer)
|
||||||
},
|
},
|
||||||
push(item: SSRBufferItem) {
|
push(item: SSRBufferItem) {
|
||||||
const isStringItem = isString(item)
|
const isStringItem = isString(item)
|
||||||
@ -104,28 +106,19 @@ export async function renderToString(
|
|||||||
input: App | VNode,
|
input: App | VNode,
|
||||||
context: SSRContext = {}
|
context: SSRContext = {}
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
let buffer: ResolvedSSRBuffer
|
|
||||||
if (isVNode(input)) {
|
if (isVNode(input)) {
|
||||||
// raw vnode, wrap with app (for context)
|
// raw vnode, wrap with app (for context)
|
||||||
return renderToString(createApp({ render: () => input }), context)
|
return renderToString(createApp({ render: () => input }), context)
|
||||||
} else {
|
|
||||||
// rendering an app
|
|
||||||
const vnode = createVNode(input._component, input._props)
|
|
||||||
vnode.appContext = input._context
|
|
||||||
// provide the ssr context to the tree
|
|
||||||
input.provide(ssrContextKey, context)
|
|
||||||
buffer = await renderComponentVNode(vnode)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve portals
|
// rendering an app
|
||||||
if (context.__portalBuffers) {
|
const vnode = createVNode(input._component, input._props)
|
||||||
context.portals = context.portals || {}
|
vnode.appContext = input._context
|
||||||
for (const key in context.__portalBuffers) {
|
// provide the ssr context to the tree
|
||||||
// note: it's OK to await sequentially here because the Promises were
|
input.provide(ssrContextKey, context)
|
||||||
// created eagerly in parallel.
|
const buffer = await renderComponentVNode(vnode)
|
||||||
context.portals[key] = unrollBuffer(await context.__portalBuffers[key])
|
|
||||||
}
|
await resolvePortals(context)
|
||||||
}
|
|
||||||
|
|
||||||
return unrollBuffer(buffer)
|
return unrollBuffer(buffer)
|
||||||
}
|
}
|
||||||
@ -201,7 +194,7 @@ function renderComponentSubTree(
|
|||||||
instance: ComponentInternalInstance
|
instance: ComponentInternalInstance
|
||||||
): ResolvedSSRBuffer | Promise<ResolvedSSRBuffer> {
|
): ResolvedSSRBuffer | Promise<ResolvedSSRBuffer> {
|
||||||
const comp = instance.type as Component
|
const comp = instance.type as Component
|
||||||
const { buffer, push, hasAsync } = createBuffer()
|
const { getBuffer, push } = createBuffer()
|
||||||
if (isFunction(comp)) {
|
if (isFunction(comp)) {
|
||||||
renderVNode(push, renderComponentRoot(instance), instance)
|
renderVNode(push, renderComponentRoot(instance), instance)
|
||||||
} else {
|
} else {
|
||||||
@ -225,10 +218,7 @@ function renderComponentSubTree(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the current component's buffer contains any Promise from async children,
|
return getBuffer()
|
||||||
// then it must return a Promise too. Otherwise this is a component that
|
|
||||||
// contains only sync children so we can avoid the async book-keeping overhead.
|
|
||||||
return hasAsync() ? Promise.all(buffer) : (buffer as ResolvedSSRBuffer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderVNode(
|
function renderVNode(
|
||||||
@ -349,7 +339,7 @@ function renderPortal(
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
const { buffer, push, hasAsync } = createBuffer()
|
const { getBuffer, push } = createBuffer()
|
||||||
renderVNodeChildren(
|
renderVNodeChildren(
|
||||||
push,
|
push,
|
||||||
vnode.children as VNodeArrayChildren,
|
vnode.children as VNodeArrayChildren,
|
||||||
@ -360,7 +350,17 @@ function renderPortal(
|
|||||||
] as SSRContext
|
] as SSRContext
|
||||||
const portalBuffers =
|
const portalBuffers =
|
||||||
context.__portalBuffers || (context.__portalBuffers = {})
|
context.__portalBuffers || (context.__portalBuffers = {})
|
||||||
portalBuffers[target] = hasAsync()
|
|
||||||
? Promise.all(buffer)
|
portalBuffers[target] = getBuffer()
|
||||||
: (buffer as ResolvedSSRBuffer)
|
}
|
||||||
|
|
||||||
|
async function resolvePortals(context: SSRContext) {
|
||||||
|
if (context.__portalBuffers) {
|
||||||
|
context.portals = context.portals || {}
|
||||||
|
for (const key in context.__portalBuffers) {
|
||||||
|
// note: it's OK to await sequentially here because the Promises were
|
||||||
|
// created eagerly in parallel.
|
||||||
|
context.portals[key] = unrollBuffer(await context.__portalBuffers[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user