fix: ssr improvement + static vnode rendering

This commit is contained in:
Julien Huang 2024-04-13 11:06:09 +02:00
parent cfb6660fcd
commit e4c9940269

View File

@ -1,39 +1,62 @@
import { createStaticVNode, defineComponent, getCurrentInstance, h, onBeforeUnmount, onMounted, ref } from 'vue'
import { createStaticVNode, defineComponent, getCurrentInstance, h, onBeforeUnmount, onMounted, ref, createVNode } from 'vue'
import type { Component, Ref, VNode } from 'vue'
// import ClientOnly from '#app/components/client-only'
import { useObserver } from '#app/utils'
import { getFragmentHTML } from '#app/components/utils'
import { useNuxtApp } from '#app/nuxt'
// todo find a better way to do it ?
function elementIsVisibleInViewport(el: Element) {
const { top, left, bottom, right } = el.getBoundingClientRect();
const { innerHeight, innerWidth } = window;
return ((top > 0 && top < innerHeight) ||
(bottom > 0 && bottom < innerHeight)) &&
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
}
/* @__NO_SIDE_EFFECTS__ */
export const createLazyIOClientPage = (componentLoader: Component) => {
return defineComponent({
inheritAttrs: false,
setup (_, { attrs }) {
setup(_, { attrs }) {
if (import.meta.server) {
return h('div', {}, [
h(componentLoader, attrs)
])
}
const nuxt = useNuxtApp()
const instance = getCurrentInstance()!
let vnode: VNode | null = null
if (import.meta.client && nuxt.isHydrating && instance.vnode?.el) {
vnode = createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1)
}
const isIntersecting = ref(false)
const el: Ref<Element | null> = ref(null)
let unobserve: (() => void) | null = null
onMounted(() => {
const observer = useObserver()
unobserve = observer!.observe(el.value as Element, () => {
isIntersecting.value = true
unobserve?.()
unobserve = null
// todo can be refactored
if (instance.vnode.el && nuxt.isHydrating) {
isIntersecting.value = elementIsVisibleInViewport(instance.vnode.el as Element)
}
if (!isIntersecting.value) {
onMounted(() => {
const observer = useObserver()
unobserve = observer!.observe(el.value as Element, () => {
isIntersecting.value = true
unobserve?.()
unobserve = null
})
})
})
}
onBeforeUnmount(() => {
unobserve?.()
unobserve = null
})
return () => h('div', { ref: el }, [
isIntersecting.value ? h(componentLoader, attrs) : vnode,
])
return () => {
return h('div', { ref: el }, [
isIntersecting.value ? h(componentLoader, attrs) : (instance.vnode.el && nuxt.isHydrating) ? createVNode(createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1)) : null,
])
}
},
})
}
@ -42,7 +65,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => {
export const createLazyNetworkClientPage = (componentLoader: Component) => {
return defineComponent({
inheritAttrs: false,
setup (_, { attrs }) {
setup(_, { attrs }) {
const nuxt = useNuxtApp()
const instance = getCurrentInstance()!
let vnode: VNode | null = null