ssrRenderSlot.ts 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import { ComponentInternalInstance, Slots } from 'vue'
  2. import { Props, PushFn, renderVNodeChildren, SSRBufferItem } from '../render'
  3. import { isArray } from '@vue/shared'
  4. export type SSRSlots = Record<string, SSRSlot>
  5. export type SSRSlot = (
  6. props: Props,
  7. push: PushFn,
  8. parentComponent: ComponentInternalInstance | null,
  9. scopeId: string | null
  10. ) => void
  11. export function ssrRenderSlot(
  12. slots: Slots | SSRSlots,
  13. slotName: string,
  14. slotProps: Props,
  15. fallbackRenderFn: (() => void) | null,
  16. push: PushFn,
  17. parentComponent: ComponentInternalInstance,
  18. slotScopeId?: string
  19. ) {
  20. // template-compiled slots are always rendered as fragments
  21. push(`<!--[-->`)
  22. const slotFn = slots[slotName]
  23. if (slotFn) {
  24. const slotBuffer: SSRBufferItem[] = []
  25. const bufferedPush = (item: SSRBufferItem) => {
  26. slotBuffer.push(item)
  27. }
  28. const ret = slotFn(
  29. slotProps,
  30. bufferedPush,
  31. parentComponent,
  32. slotScopeId ? ' ' + slotScopeId : ''
  33. )
  34. if (isArray(ret)) {
  35. // normal slot
  36. renderVNodeChildren(push, ret, parentComponent, slotScopeId)
  37. } else {
  38. // ssr slot.
  39. // check if the slot renders all comments, in which case use the fallback
  40. let isEmptySlot = true
  41. for (let i = 0; i < slotBuffer.length; i++) {
  42. if (!isComment(slotBuffer[i])) {
  43. isEmptySlot = false
  44. break
  45. }
  46. }
  47. if (isEmptySlot) {
  48. if (fallbackRenderFn) {
  49. fallbackRenderFn()
  50. }
  51. } else {
  52. for (let i = 0; i < slotBuffer.length; i++) {
  53. push(slotBuffer[i])
  54. }
  55. }
  56. }
  57. } else if (fallbackRenderFn) {
  58. fallbackRenderFn()
  59. }
  60. push(`<!--]-->`)
  61. }
  62. const commentRE = /^<!--.*-->$/
  63. function isComment(item: SSRBufferItem) {
  64. return typeof item === 'string' && commentRE.test(item)
  65. }