isPromise,
isString,
isVoidTag,
- ShapeFlags
+ ShapeFlags,
+ isArray
} from '@vue/shared'
import { ssrRenderAttrs } from './helpers/ssrRenderAttrs'
import { ssrCompile } from './helpers/ssrCompile'
normalizeSuspenseChildren
} = ssrUtils
-export type SSRBuffer = SSRBufferItem[]
+export type SSRBuffer = SSRBufferItem[] & { hasAsync?: boolean }
export type SSRBufferItem = string | SSRBuffer | Promise<SSRBuffer>
export type PushFn = (item: SSRBufferItem) => void
export type Props = Record<string, unknown>
buffer.push(item)
}
appendable = isStringItem
+ if (isPromise(item) || (isArray(item) && item.hasAsync)) {
+ // promise, or child buffer with async, mark as async.
+ // this allows skipping unnecessary await ticks during unroll stage
+ buffer.hasAsync = true
+ }
}
}
}
buffer: SSRBuffer,
stream: Readable
): Promise<void> {
+ if (buffer.hasAsync) {
+ for (let i = 0; i < buffer.length; i++) {
+ let item = buffer[i]
+ if (isPromise(item)) {
+ item = await item
+ }
+ if (isString(item)) {
+ stream.push(item)
+ } else {
+ await unrollBuffer(item, stream)
+ }
+ }
+ } else {
+ // sync buffer can be more efficiently unrolled without unnecessary await
+ // ticks
+ unrollBufferSync(buffer, stream)
+ }
+}
+
+function unrollBufferSync(buffer: SSRBuffer, stream: Readable) {
for (let i = 0; i < buffer.length; i++) {
let item = buffer[i]
- if (isPromise(item)) {
- item = await item
- }
if (isString(item)) {
stream.push(item)
} else {
- await unrollBuffer(item, stream)
+ // since this is a sync buffer, child buffers are never promises
+ unrollBufferSync(item as SSRBuffer, stream)
}
}
}
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 (isPromise(item)) {
- item = await item
- }
if (isString(item)) {
ret += item
} else {
- ret += await unrollBuffer(item as SSRBuffer)
+ // since this is a sync buffer, child buffers are never promises
+ ret += unrollBufferSync(item as SSRBuffer)
}
}
return ret