let hasAsync = false
const buffer: SSRBuffer = []
return {
- buffer,
- hasAsync() {
- return hasAsync
+ getBuffer(): ResolvedSSRBuffer | Promise<ResolvedSSRBuffer> {
+ // If the current component's buffer contains any Promise from async children,
+ // 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) {
const isStringItem = isString(item)
input: App | VNode,
context: SSRContext = {}
): Promise<string> {
- let buffer: ResolvedSSRBuffer
if (isVNode(input)) {
// raw vnode, wrap with app (for 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
- 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])
- }
- }
+ // 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)
+ const buffer = await renderComponentVNode(vnode)
+
+ await resolvePortals(context)
return unrollBuffer(buffer)
}
instance: ComponentInternalInstance
): ResolvedSSRBuffer | Promise<ResolvedSSRBuffer> {
const comp = instance.type as Component
- const { buffer, push, hasAsync } = createBuffer()
+ const { getBuffer, push } = createBuffer()
if (isFunction(comp)) {
renderVNode(push, renderComponentRoot(instance), instance)
} else {
)
}
}
- // If the current component's buffer contains any Promise from async children,
- // 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)
+ return getBuffer()
}
function renderVNode(
return []
}
- const { buffer, push, hasAsync } = createBuffer()
+ const { getBuffer, push } = createBuffer()
renderVNodeChildren(
push,
vnode.children as VNodeArrayChildren,
] as SSRContext
const portalBuffers =
context.__portalBuffers || (context.__portalBuffers = {})
- portalBuffers[target] = hasAsync()
- ? Promise.all(buffer)
- : (buffer as ResolvedSSRBuffer)
+
+ portalBuffers[target] = getBuffer()
+}
+
+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])
+ }
+ }
}