All files / server-renderer/src/helpers ssrRenderSlot.ts

100% Statements 31/31
100% Branches 14/14
100% Functions 4/4
100% Lines 29/29

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  10x 10x                   10x                   43x 43x                 43x     10x                 43x 43x 34x 34x 45x   34x           34x   3x       31x 31x 41x 22x 22x     31x 9x 3x     22x 30x       9x 3x       10x   41x            
import { ComponentInternalInstance, Slots } from 'vue'
import { Props, PushFn, renderVNodeChildren, SSRBufferItem } from '../render'
import { isArray } from '@vue/shared'
 
export type SSRSlots = Record<string, SSRSlot>
export type SSRSlot = (
  props: Props,
  push: PushFn,
  parentComponent: ComponentInternalInstance | null,
  scopeId: string | null
) => void
 
export function ssrRenderSlot(
  slots: Slots | SSRSlots,
  slotName: string,
  slotProps: Props,
  fallbackRenderFn: (() => void) | null,
  push: PushFn,
  parentComponent: ComponentInternalInstance,
  slotScopeId?: string
) {
  // template-compiled slots are always rendered as fragments
  push(`<!--[-->`)
  ssrRenderSlotInner(
    slots,
    slotName,
    slotProps,
    fallbackRenderFn,
    push,
    parentComponent,
    slotScopeId
  )
  push(`<!--]-->`)
}
 
export function ssrRenderSlotInner(
  slots: Slots | SSRSlots,
  slotName: string,
  slotProps: Props,
  fallbackRenderFn: (() => void) | null,
  push: PushFn,
  parentComponent: ComponentInternalInstance,
  slotScopeId?: string
) {
  const slotFn = slots[slotName]
  if (slotFn) {
    const slotBuffer: SSRBufferItem[] = []
    const bufferedPush = (item: SSRBufferItem) => {
      slotBuffer.push(item)
    }
    const ret = slotFn(
      slotProps,
      bufferedPush,
      parentComponent,
      slotScopeId ? ' ' + slotScopeId : ''
    )
    if (isArray(ret)) {
      // normal slot
      renderVNodeChildren(push, ret, parentComponent, slotScopeId)
    } else {
      // ssr slot.
      // check if the slot renders all comments, in which case use the fallback
      let isEmptySlot = true
      for (let i = 0; i < slotBuffer.length; i++) {
        if (!isComment(slotBuffer[i])) {
          isEmptySlot = false
          break
        }
      }
      if (isEmptySlot) {
        if (fallbackRenderFn) {
          fallbackRenderFn()
        }
      } else {
        for (let i = 0; i < slotBuffer.length; i++) {
          push(slotBuffer[i])
        }
      }
    }
  } else if (fallbackRenderFn) {
    fallbackRenderFn()
  }
}
 
const commentRE = /<!--[^]*?-->/gm
function isComment(item: SSRBufferItem) {
  return (
    typeof item === 'string' &&
    commentRE.test(item) &&
    !item.replace(commentRE, '').trim()
  )
}