UNPKG

nuxt-vitalizer

Version:
70 lines (69 loc) 2.36 kB
// @license MIT import { createStaticVNode, ref, onMounted, defineComponent, getCurrentInstance } from "vue"; import { useNuxtApp } from "#imports"; import { getFragmentHTML } from "#app/components/utils"; import { delayHydrationOptions } from "#build/module/nuxt-vitalizer"; export default defineComponent({ setup(_, { slots }) { const nuxtApp = useNuxtApp(); const instance = getCurrentInstance(); const supportsIdleCallback = import.meta.client ? "requestIdleCallback" in window : false; const shouldRender = ref(import.meta.server || !supportsIdleCallback || !nuxtApp.isHydrating); let vnode; if (import.meta.client && !shouldRender.value) { if (instance.vnode.el) { const fragment = getFragmentHTML(instance.vnode.el, false) ?? []; vnode = createStaticVNode(fragment.join(""), fragment.length); } onMounted(async () => { const triggers = [idleListener(), eventListeners()]; nuxtApp._delayHydrationPromise ??= Promise.race( triggers.map((t) => t.promise) ).finally(() => { for (const t of triggers) t.cleanup(); }); await nuxtApp._delayHydrationPromise; shouldRender.value = true; }); } return () => shouldRender.value ? slots.default?.() : vnode; } }); function eventListeners() { const abortController = new AbortController(); const promise = new Promise((resolve) => { const listener = (e) => { for (const e2 of delayHydrationOptions.hydrateOnEvents) window.removeEventListener(e2, listener); requestAnimationFrame(() => resolve(e)); }; for (const e of delayHydrationOptions.hydrateOnEvents) { window.addEventListener(e, listener, { capture: true, once: true, passive: true, signal: abortController.signal }); } }); return { promise, cleanup: () => abortController.abort() }; } function idleListener() { let idleId; const promise = new Promise((resolve) => { const timeoutDelay = () => { setTimeout(() => { requestAnimationFrame(() => resolve()); }, delayHydrationOptions.postIdleTimeout); }; idleId = requestIdleCallback(timeoutDelay, { timeout: delayHydrationOptions.idleCallbackTimeout }); }); return { promise, cleanup: () => cancelIdleCallback(idleId) }; }