2022-10-03 14:14:55 +00:00
|
|
|
import { ref, onMounted, defineComponent, createElementBlock, h, createElementVNode } from 'vue'
|
2021-11-15 11:57:38 +00:00
|
|
|
|
|
|
|
export default defineComponent({
|
|
|
|
name: 'ClientOnly',
|
2022-11-14 10:27:57 +00:00
|
|
|
inheritAttrs: false,
|
2021-11-15 11:57:38 +00:00
|
|
|
// eslint-disable-next-line vue/require-prop-types
|
|
|
|
props: ['fallback', 'placeholder', 'placeholderTag', 'fallbackTag'],
|
2022-11-14 10:27:57 +00:00
|
|
|
setup (_, { slots, attrs }) {
|
2021-11-15 11:57:38 +00:00
|
|
|
const mounted = ref(false)
|
|
|
|
onMounted(() => { mounted.value = true })
|
|
|
|
return (props) => {
|
|
|
|
if (mounted.value) { return slots.default?.() }
|
|
|
|
const slot = slots.fallback || slots.placeholder
|
|
|
|
if (slot) { return slot() }
|
|
|
|
const fallbackStr = props.fallback || props.placeholder || ''
|
|
|
|
const fallbackTag = props.fallbackTag || props.placeholderTag || 'span'
|
2022-11-14 10:27:57 +00:00
|
|
|
return createElementBlock(fallbackTag, attrs, fallbackStr)
|
2021-11-15 11:57:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2022-04-19 19:13:55 +00:00
|
|
|
|
2022-09-07 08:31:11 +00:00
|
|
|
const cache = new WeakMap()
|
|
|
|
|
2022-04-19 19:13:55 +00:00
|
|
|
export function createClientOnly (component) {
|
2022-09-07 08:31:11 +00:00
|
|
|
if (cache.has(component)) {
|
|
|
|
return cache.get(component)
|
|
|
|
}
|
|
|
|
|
2022-09-06 07:40:25 +00:00
|
|
|
const clone = { ...component }
|
|
|
|
|
|
|
|
if (clone.render) {
|
2022-08-03 11:49:09 +00:00
|
|
|
// override the component render (non script setup component)
|
2022-09-06 07:40:25 +00:00
|
|
|
clone.render = (ctx, ...args) => {
|
2022-10-03 14:14:55 +00:00
|
|
|
if (ctx.mounted$) {
|
|
|
|
const res = component.render(ctx, ...args)
|
|
|
|
return (res.children === null || typeof res.children === 'string')
|
|
|
|
? createElementVNode(res.type, res.props, res.children, res.patchFlag, res.dynamicProps, res.shapeFlag)
|
|
|
|
: h(res)
|
|
|
|
} else {
|
|
|
|
return h('div', ctx.$attrs ?? ctx._.attrs)
|
|
|
|
}
|
2022-08-02 15:05:02 +00:00
|
|
|
}
|
2022-09-06 07:40:25 +00:00
|
|
|
} else if (clone.template) {
|
2022-08-02 15:05:02 +00:00
|
|
|
// handle runtime-compiler template
|
2022-09-06 07:40:25 +00:00
|
|
|
clone.template = `
|
|
|
|
<template v-if="mounted$">${component.template}</template>
|
2022-08-02 15:05:02 +00:00
|
|
|
<template v-else><div></div></template>
|
|
|
|
`
|
|
|
|
}
|
|
|
|
|
2022-09-06 07:40:25 +00:00
|
|
|
clone.setup = (props, ctx) => {
|
|
|
|
const mounted$ = ref(false)
|
|
|
|
onMounted(() => { mounted$.value = true })
|
|
|
|
|
|
|
|
return Promise.resolve(component.setup?.(props, ctx) || {})
|
|
|
|
.then((setupState) => {
|
|
|
|
return typeof setupState !== 'function'
|
|
|
|
? { ...setupState, mounted$ }
|
|
|
|
: (...args) => {
|
2022-10-03 14:14:55 +00:00
|
|
|
if (mounted$.value) {
|
|
|
|
const res = setupState(...args)
|
|
|
|
return (res.children === null || typeof res.children === 'string')
|
|
|
|
? createElementVNode(res.type, res.props, res.children, res.patchFlag, res.dynamicProps, res.shapeFlag)
|
|
|
|
: h(res)
|
|
|
|
} else {
|
|
|
|
return h('div', ctx.attrs)
|
|
|
|
}
|
2022-09-06 07:40:25 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-09-07 08:31:11 +00:00
|
|
|
cache.set(component, clone)
|
|
|
|
|
2022-09-06 07:40:25 +00:00
|
|
|
return clone
|
2022-04-19 19:13:55 +00:00
|
|
|
}
|