chore: update components with documentation

This commit is contained in:
tbitw2549 2024-08-30 00:04:39 +03:00
parent 67d3cadcb2
commit 74231878ea
2 changed files with 41 additions and 12 deletions

View File

@ -1,5 +1,6 @@
import { defineAsyncComponent, defineComponent, h, hydrateOnIdle, hydrateOnInteraction, hydrateOnMediaQuery, hydrateOnVisible, ref, watch } from 'vue' import { defineAsyncComponent, defineComponent, getCurrentInstance, h, hydrateOnIdle, hydrateOnInteraction, hydrateOnMediaQuery, hydrateOnVisible, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import type { AsyncComponentLoader, HydrationStrategy } from 'vue' import type { AsyncComponentLoader, HydrationStrategy } from 'vue'
import { onNuxtReady, useNuxtApp } from '#app'
/* @__NO_SIDE_EFFECTS__ */ /* @__NO_SIDE_EFFECTS__ */
export const createLazyIOComponent = (loader: AsyncComponentLoader) => { export const createLazyIOComponent = (loader: AsyncComponentLoader) => {
@ -9,7 +10,12 @@ export const createLazyIOComponent = (loader: AsyncComponentLoader) => {
if (import.meta.server) { if (import.meta.server) {
return () => h(defineAsyncComponent(loader), attrs) return () => h(defineAsyncComponent(loader), attrs)
} }
return () => h(defineAsyncComponent({ loader, hydrate: hydrateOnVisible(attrs.hydrate as IntersectionObserverInit | undefined) })) const ready = ref(false)
const nuxt = useNuxtApp()
const instance = getCurrentInstance()!
onNuxtReady(() => ready.value = true)
// This is a hack to prevent hydration mismatches for all hydration strategies
return () => ready.value ? h(defineAsyncComponent({ loader, hydrate: hydrateOnVisible(attrs.hydrate as IntersectionObserverInit | undefined) })) : nuxt.isHydrating && instance.vnode.el ? h('div', attrs) : null
}, },
}) })
} }
@ -22,7 +28,12 @@ export const createLazyNetworkComponent = (loader: AsyncComponentLoader) => {
if (import.meta.server) { if (import.meta.server) {
return () => h(defineAsyncComponent(loader), attrs) return () => h(defineAsyncComponent(loader), attrs)
} }
return () => h(defineAsyncComponent({ loader, hydrate: hydrateOnIdle(attrs.hydrate as number | undefined) })) const ready = ref(false)
const nuxt = useNuxtApp()
const instance = getCurrentInstance()!
onNuxtReady(() => ready.value = true)
// This one seems to work fine due to the intended use case
return () => ready.value ? h(defineAsyncComponent({ loader, hydrate: hydrateOnIdle(attrs.hydrate as number | undefined) })) : nuxt.isHydrating && instance.vnode.el ? h('div', attrs) : null
}, },
}) })
} }
@ -35,8 +46,12 @@ export const createLazyEventComponent = (loader: AsyncComponentLoader) => {
if (import.meta.server) { if (import.meta.server) {
return () => h(defineAsyncComponent(loader), attrs) return () => h(defineAsyncComponent(loader), attrs)
} }
const ready = ref(false)
const nuxt = useNuxtApp()
const instance = getCurrentInstance()!
onNuxtReady(() => ready.value = true)
const events: Array<keyof HTMLElementEventMap> = attrs.hydrate as Array<keyof HTMLElementEventMap> ?? ['mouseover'] const events: Array<keyof HTMLElementEventMap> = attrs.hydrate as Array<keyof HTMLElementEventMap> ?? ['mouseover']
return () => h(defineAsyncComponent({ loader, hydrate: hydrateOnInteraction(events) })) return () => ready.value ? h(defineAsyncComponent({ loader, hydrate: hydrateOnInteraction(events) })) : nuxt.isHydrating && instance.vnode.el ? h('div', attrs) : null
}, },
}) })
} }
@ -49,7 +64,12 @@ export const createLazyMediaComponent = (loader: AsyncComponentLoader) => {
if (import.meta.server) { if (import.meta.server) {
return () => h(defineAsyncComponent(loader), attrs) return () => h(defineAsyncComponent(loader), attrs)
} }
return () => h(defineAsyncComponent({ loader, hydrate: hydrateOnMediaQuery(attrs.hydrate ?? '(min-width: 1px)') })) const ready = ref(false)
const nuxt = useNuxtApp()
const instance = getCurrentInstance()!
onNuxtReady(() => ready.value = true)
// This one, unlike others, can cause a hydration mismatch even a whole minute after the page loads. Given a query of min-width: 1200px, with a small window, the moment the window expands to at least 1200 it hydrates and causes a hydration mismatch.
return () => ready.value ? h(defineAsyncComponent({ loader, hydrate: hydrateOnMediaQuery(attrs.hydrate ?? '(min-width: 1px)') })) : nuxt.isHydrating && instance.vnode.el ? h('div', attrs) : null
}, },
}) })
} }
@ -62,12 +82,21 @@ export const createLazyIfComponent = (loader: AsyncComponentLoader) => {
if (import.meta.server) { if (import.meta.server) {
return () => h(defineAsyncComponent(loader), attrs) return () => h(defineAsyncComponent(loader), attrs)
} }
const ready = ref(false)
const nuxt = useNuxtApp()
const instance = getCurrentInstance()!
onNuxtReady(() => ready.value = true)
const shouldHydrate = ref(!!(attrs.hydrate ?? true)) const shouldHydrate = ref(!!(attrs.hydrate ?? true))
const strategy: HydrationStrategy = (hydrate) => { const strategy: HydrationStrategy = (hydrate) => {
if (!shouldHydrate.value) {
const unwatch = watch(shouldHydrate, () => hydrate(), { once: true }) const unwatch = watch(shouldHydrate, () => hydrate(), { once: true })
return () => unwatch() return () => unwatch()
} }
return () => h(defineAsyncComponent({ loader, hydrate: strategy })) hydrate()
return () => {}
}
// This one seems to work fine whenever the hydration condition is achieved at client side. For example, a hydration condition of a ref greater than 2 with a button to increment causes no hydration mismatch after 3 presses of the button.
return () => ready.value ? h(defineAsyncComponent({ loader, hydrate: strategy })) : nuxt.isHydrating && instance.vnode.el ? h('div', attrs) : null
}, },
}) })
} }

View File

@ -2698,8 +2698,8 @@ describe('lazy import components', () => {
expect(await page.locator('body').getByText('This shouldn\'t be visible at first with network!').all()).toHaveLength(1) expect(await page.locator('body').getByText('This shouldn\'t be visible at first with network!').all()).toHaveLength(1)
expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(1) expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(1)
expect(await page.locator('body').getByText('This should be visible at first with events!').all()).toHaveLength(2) expect(await page.locator('body').getByText('This should be visible at first with events!').all()).toHaveLength(2)
// The default value is immediately truthy // The default value is immediately truthy, however, there is a hydration mismatch without the hack
//expect(await page.locator('body').getByText('This should be visible at first with conditions!').all()).toHaveLength(2) expect(await page.locator('body').getByText('This should be visible at first with conditions!').all()).toHaveLength(2)
const component = page.locator('#lazyevent') const component = page.locator('#lazyevent')
const rect = (await component.boundingBox())! const rect = (await component.boundingBox())!
await page.mouse.move(rect.x + rect.width / 2, rect.y + rect.height / 2) await page.mouse.move(rect.x + rect.width / 2, rect.y + rect.height / 2)
@ -2707,11 +2707,11 @@ describe('lazy import components', () => {
expect(await page.locator('body').getByText('This shouldn\'t be visible at first with events!').all()).toHaveLength(1) expect(await page.locator('body').getByText('This shouldn\'t be visible at first with events!').all()).toHaveLength(1)
await page.locator('#conditionbutton').click() await page.locator('#conditionbutton').click()
await page.waitForLoadState('networkidle') await page.waitForLoadState('networkidle')
//expect(await page.locator('body').getByText('This shouldn\'t be visible at first with conditions!').all()).toHaveLength(2) expect(await page.locator('body').getByText('This shouldn\'t be visible at first with conditions!').all()).toHaveLength(2)
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight))
await page.waitForLoadState('networkidle') await page.waitForLoadState('networkidle')
expect(await page.locator('body').getByText('This shouldn\'t be visible at first with viewport!').all()).toHaveLength(1) expect(await page.locator('body').getByText('This shouldn\'t be visible at first with viewport!').all()).toHaveLength(1)
//expect(await page.locator('body').getByText('This should never be visible!').all()).toHaveLength(1) expect(await page.locator('body').getByText('This should always be visible!').all()).toHaveLength(1)
await page.close() await page.close()
}) })