| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- import {
- type App,
- type VNode,
- createApp,
- createVNode,
- ssrContextKey,
- ssrUtils,
- } from 'vue'
- import { isPromise, isString } from '@vue/shared'
- import { type SSRBuffer, type SSRContext, renderComponentVNode } from './render'
- const { isVNode } = ssrUtils
- async function unrollBuffer(buffer: SSRBuffer): Promise<string> {
- if (buffer.hasAsync) {
- let ret = ''
- for (let i = 0; i < buffer.length; i++) {
- let item = buffer[i]
- if (isPromise(item)) {
- item = await item
- }
- if (isString(item)) {
- ret += item
- } else {
- ret += await unrollBuffer(item)
- }
- }
- return ret
- } else {
- // sync buffer can be more efficiently unrolled without unnecessary await
- // ticks
- return unrollBufferSync(buffer)
- }
- }
- function unrollBufferSync(buffer: SSRBuffer): string {
- let ret = ''
- for (let i = 0; i < buffer.length; i++) {
- let item = buffer[i]
- if (isString(item)) {
- ret += item
- } else {
- // since this is a sync buffer, child buffers are never promises
- ret += unrollBufferSync(item as SSRBuffer)
- }
- }
- return ret
- }
- export async function renderToString(
- input: App | VNode,
- context: SSRContext = {},
- ): Promise<string> {
- if (isVNode(input)) {
- // raw vnode, wrap with app (for context)
- return renderToString(createApp({ render: () => input }), context)
- }
- // 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)
- const result = await unrollBuffer(buffer as SSRBuffer)
- await resolveTeleports(context)
- if (context.__watcherHandles) {
- for (const unwatch of context.__watcherHandles) {
- unwatch()
- }
- }
- return result
- }
- export async function resolveTeleports(context: SSRContext) {
- if (context.__teleportBuffers) {
- context.teleports = context.teleports || {}
- for (const key in context.__teleportBuffers) {
- // note: it's OK to await sequentially here because the Promises were
- // created eagerly in parallel.
- context.teleports[key] = await unrollBuffer(
- await Promise.all([context.__teleportBuffers[key]]),
- )
- }
- }
- }
|