Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | 16x 688x 382x 306x 306x 472x 472x 194x 194x 278x 110x 102x 102x 168x 168x 64x 64x 64x 104x 298x 354x 555x 555x 657x 657x 484x 173x 555x 431x 87x 344x 344x 344x 344x 344x 339x 331x 13x 13x 331x 331x 554x 554x 24x 18x 31x 31x 31x 31x 31x 31x 38x 20x 76x 76x 56x 492x 15x 15x 15x | import {
type App,
type VNode,
createApp,
createVNode,
ssrContextKey,
ssrUtils,
} from '@vue/runtime-dom'
import { NOOP, isPromise, isString } from '@vue/shared'
import { type SSRBuffer, type SSRContext, renderComponentVNode } from './render'
const { isVNode } = ssrUtils
function nestedUnrollBuffer(
buffer: SSRBuffer,
parentRet: string,
startIndex: number,
): Promise<string> | string {
if (!buffer.hasAsync) {
return parentRet + unrollBufferSync(buffer)
}
let ret = parentRet
for (let i = startIndex; i < buffer.length; i += 1) {
const item = buffer[i]
if (isString(item)) {
ret += item
continue
}
if (isPromise(item)) {
return item.then(nestedItem => {
buffer[i] = nestedItem
return nestedUnrollBuffer(buffer, ret, i)
})
}
const result = nestedUnrollBuffer(item, ret, 0)
if (isPromise(result)) {
return result.then(nestedItem => {
buffer[i] = nestedItem
return nestedUnrollBuffer(buffer, '', i)
})
}
ret = result
}
return ret
}
export function unrollBuffer(buffer: SSRBuffer): Promise<string> | string {
return nestedUnrollBuffer(buffer, '', 0)
}
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)
let buffer: SSRBuffer | undefined
let result: string
try {
buffer = await renderComponentVNode(vnode)
result = await unrollBuffer(buffer)
await resolveTeleports(context)
} catch (err) {
cleanupFailedRender(buffer, context)
throw err
}
stopWatchers(context)
return result
}
export function stopWatchers(context: SSRContext, start = 0): void {
const handles = context.__watcherHandles
if (handles) {
for (let i = start; i < handles.length; i++) {
handles[i]()
}
}
}
/**
* Stops watchers without masking the render error. Components after the
* failure point are still in flight and can register watchers once the render
* has settled, so those are stopped when they finish.
* Cleanup errors here have already been reported by the watcher.
*/
export function cleanupFailedRender(
buffer: SSRBuffer | undefined,
context: SSRContext,
): void {
const stopped = context.__watcherHandles ? context.__watcherHandles.length : 0
try {
stopWatchers(context)
} catch {}
;(async () => {
if (buffer) await settleBuffer(buffer)
for (const key in context.__teleportBuffers) {
await settleBuffer(context.__teleportBuffers[key])
}
stopWatchers(context, stopped)
})().catch(NOOP)
}
async function settleBuffer(buffer: SSRBuffer): Promise<void> {
if (!buffer.hasAsync) return
for (let item of buffer) {
try {
if (isPromise(item)) item = await item
if (!isString(item)) await settleBuffer(item)
} catch {}
}
}
export async function resolveTeleports(context: SSRContext): Promise<void> {
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(
context.__teleportBuffers[key],
)
}
}
}
|