This repository has been archived by the owner on Apr 6, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
client-only.mjs
75 lines (66 loc) · 2.42 KB
/
client-only.mjs
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
import { ref, onMounted, defineComponent, createElementBlock, h, createElementVNode } from 'vue'
export default defineComponent({
name: 'ClientOnly',
inheritAttrs: false,
// eslint-disable-next-line vue/require-prop-types
props: ['fallback', 'placeholder', 'placeholderTag', 'fallbackTag'],
setup (_, { slots, attrs }) {
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'
return createElementBlock(fallbackTag, attrs, fallbackStr)
}
}
})
const cache = new WeakMap()
export function createClientOnly (component) {
if (cache.has(component)) {
return cache.get(component)
}
const clone = { ...component }
if (clone.render) {
// override the component render (non script setup component)
clone.render = (ctx, ...args) => {
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)
}
}
} else if (clone.template) {
// handle runtime-compiler template
clone.template = `
<template v-if="mounted$">${component.template}</template>
<template v-else><div></div></template>
`
}
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) => {
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)
}
}
})
}
cache.set(component, clone)
return clone
}