From 9f629ad45a4c31c2678182d90b634ee8807d19b1 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 24 Mar 2024 19:30:58 +0200 Subject: [PATCH 001/123] feat: lazy hydration --- packages/nuxt/src/components/runtime/client-io-component.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/nuxt/src/components/runtime/client-io-component.ts diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -0,0 +1 @@ + From d64d78fde8a01ed6cee05ad7d3a72cb5b6b39c96 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 17:36:36 +0000 Subject: [PATCH 002/123] [autofix.ci] apply automated fixes --- packages/nuxt/src/components/runtime/client-io-component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index 8b137891791f..e69de29bb2d1 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -1 +0,0 @@ - From 9ac1261662342fe544a9772ee8f88174ff344d8a Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 24 Mar 2024 19:41:29 +0200 Subject: [PATCH 003/123] feat: client-io-component.ts barebones functionality --- .../components/runtime/client-io-component.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index e69de29bb2d1..babcdc33ebc4 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -0,0 +1,24 @@ +import { defineComponent } from "vue" +export default defineComponent({ + setup() { + const data = ref(null); + const isIntersecting = ref(false); + const target = ref(null); + let observer: Ref = ref(null) + onMounted(() => { + const observer = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + isIntersecting.value = true; + observer.unobserve(target.value); + } + }); + }); + observer.observe(target.value); + }); + + return { + isIntersecting + }; + } +}); From 84b0a71b8c2fb6b67457b5122e340e9c1999070d Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 24 Mar 2024 19:45:47 +0200 Subject: [PATCH 004/123] feat: provide an emit --- packages/nuxt/src/components/runtime/client-io-component.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index babcdc33ebc4..b1de3244a215 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -1,5 +1,6 @@ import { defineComponent } from "vue" export default defineComponent({ + emits: ['intersected'], setup() { const data = ref(null); const isIntersecting = ref(false); @@ -10,6 +11,7 @@ export default defineComponent({ entries.forEach(entry => { if (entry.isIntersecting) { isIntersecting.value = true; + emit('intersected'); observer.unobserve(target.value); } }); From ae2bb27ac0235f1effb8852f981532764374497f Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 24 Mar 2024 19:46:43 +0200 Subject: [PATCH 005/123] fix: provide ref --- packages/nuxt/src/components/runtime/client-io-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index b1de3244a215..6403e3e2117f 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -1,4 +1,4 @@ -import { defineComponent } from "vue" +import { defineComponent, ref } from "vue" export default defineComponent({ emits: ['intersected'], setup() { From 6a32dc1c9edbed4248b08e9513092025318bbc56 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 24 Mar 2024 19:52:16 +0200 Subject: [PATCH 006/123] fix: client-io-component.ts --- .../components/runtime/client-io-component.ts | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index 6403e3e2117f..cb941d8aaba8 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -1,26 +1,32 @@ -import { defineComponent, ref } from "vue" +import { ref, onMounted, onUnmounted, defineComponent } from 'vue'; + export default defineComponent({ - emits: ['intersected'], - setup() { - const data = ref(null); - const isIntersecting = ref(false); - const target = ref(null); - let observer: Ref = ref(null) - onMounted(() => { - const observer = new IntersectionObserver(entries => { - entries.forEach(entry => { - if (entry.isIntersecting) { - isIntersecting.value = true; - emit('intersected'); - observer.unobserve(target.value); - } - }); + setup(props, { emit }) { + const intersectionTarget = ref(null); + let observer = null; + + const intersectionCallback = (entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + emit('intersect'); + observer.unobserve(entry.target); + } }); - observer.observe(target.value); + }; + + onMounted(() => { + observer = new IntersectionObserver(intersectionCallback); + observer.observe(intersectionTarget.value); + }); + + onUnmounted(() => { + if (observer) { + observer.disconnect(); + } }); return { - isIntersecting + intersectionTarget }; } }); From 932d1436880ee936891f4264e288ef19bd2f64e0 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 17:54:31 +0000 Subject: [PATCH 007/123] [autofix.ci] apply automated fixes --- .../components/runtime/client-io-component.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index cb941d8aaba8..e8f07a47c786 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -1,32 +1,32 @@ -import { ref, onMounted, onUnmounted, defineComponent } from 'vue'; +import { defineComponent, onMounted, onUnmounted, ref } from 'vue' export default defineComponent({ - setup(props, { emit }) { - const intersectionTarget = ref(null); - let observer = null; + setup (props, { emit }) { + const intersectionTarget = ref(null) + let observer = null const intersectionCallback = (entries) => { - entries.forEach(entry => { + entries.forEach((entry) => { if (entry.isIntersecting) { - emit('intersect'); - observer.unobserve(entry.target); + emit('intersect') + observer.unobserve(entry.target) } - }); - }; + }) + } onMounted(() => { - observer = new IntersectionObserver(intersectionCallback); - observer.observe(intersectionTarget.value); - }); + observer = new IntersectionObserver(intersectionCallback) + observer.observe(intersectionTarget.value) + }) onUnmounted(() => { if (observer) { - observer.disconnect(); + observer.disconnect() } - }); + }) return { intersectionTarget - }; + } } -}); +}) From cb221ed57941f0a7fe8dab1ace634d30dc962d3b Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 24 Mar 2024 22:24:55 +0200 Subject: [PATCH 008/123] types: client-io-component.ts --- packages/nuxt/src/components/runtime/client-io-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index e8f07a47c786..081e2d82a7ab 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -3,7 +3,7 @@ import { defineComponent, onMounted, onUnmounted, ref } from 'vue' export default defineComponent({ setup (props, { emit }) { const intersectionTarget = ref(null) - let observer = null + let observer: IntersectionObserver | null = null const intersectionCallback = (entries) => { entries.forEach((entry) => { From 2ac2a975e05b533d1c037150d88b727fb44d7cc2 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 24 Mar 2024 23:08:51 +0200 Subject: [PATCH 009/123] fix: proper intersection callback type --- packages/nuxt/src/components/runtime/client-io-component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index 081e2d82a7ab..d7b1e7273b21 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -2,10 +2,10 @@ import { defineComponent, onMounted, onUnmounted, ref } from 'vue' export default defineComponent({ setup (props, { emit }) { - const intersectionTarget = ref(null) + const intersectionTarget: Ref = ref(null) let observer: IntersectionObserver | null = null - const intersectionCallback = (entries) => { + const intersectionCallback: IntersectionObserverCallback = (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { emit('intersect') @@ -16,7 +16,7 @@ export default defineComponent({ onMounted(() => { observer = new IntersectionObserver(intersectionCallback) - observer.observe(intersectionTarget.value) + observer.observe(intersectionTarget.value as Element) }) onUnmounted(() => { From d94436b9c4e13444059a1d09bf09188a217b89e4 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 24 Mar 2024 23:15:02 +0200 Subject: [PATCH 010/123] fix: import type Ref and provide emit --- packages/nuxt/src/components/runtime/client-io-component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index d7b1e7273b21..f367d8252d01 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -1,6 +1,8 @@ import { defineComponent, onMounted, onUnmounted, ref } from 'vue' +import type { Ref } from "vue" export default defineComponent({ + emits: ['intersect'], setup (props, { emit }) { const intersectionTarget: Ref = ref(null) let observer: IntersectionObserver | null = null @@ -9,7 +11,7 @@ export default defineComponent({ entries.forEach((entry) => { if (entry.isIntersecting) { emit('intersect') - observer.unobserve(entry.target) + observer!.unobserve(entry.target) } }) } From 85b4d6932bc18c5658b5cd855fcdd204b47e7812 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 21:17:18 +0000 Subject: [PATCH 011/123] [autofix.ci] apply automated fixes --- packages/nuxt/src/components/runtime/client-io-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index f367d8252d01..98b523e341f9 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -1,5 +1,5 @@ import { defineComponent, onMounted, onUnmounted, ref } from 'vue' -import type { Ref } from "vue" +import type { Ref } from 'vue' export default defineComponent({ emits: ['intersect'], From 624188a7cff39c976fffadc6309f10a72028ce8f Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 25 Mar 2024 15:06:53 +0200 Subject: [PATCH 012/123] feat: extract useObserver --- packages/nuxt/src/app/components/nuxt-link.ts | 44 +------------------ 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/packages/nuxt/src/app/components/nuxt-link.ts b/packages/nuxt/src/app/components/nuxt-link.ts index 659001884b3d..cbc0f5d20618 100644 --- a/packages/nuxt/src/app/components/nuxt-link.ts +++ b/packages/nuxt/src/app/components/nuxt-link.ts @@ -14,6 +14,7 @@ import { onNuxtReady } from '../composables/ready' import { navigateTo, useRouter } from '../composables/router' import { useNuxtApp, useRuntimeConfig } from '../nuxt' import { cancelIdleCallback, requestIdleCallback } from '../compat/idle-callback' +import { useObserver } from "../utils" // @ts-expect-error virtual file import { nuxtLinkDefaults } from '#build/nuxt.config.mjs' @@ -403,49 +404,6 @@ function applyTrailingSlashBehavior (to: string, trailingSlash: NuxtLinkOptions[ } // --- Prefetching utils --- -type CallbackFn = () => void -type ObserveFn = (element: Element, callback: CallbackFn) => () => void - -function useObserver (): { observe: ObserveFn } | undefined { - if (import.meta.server) { return } - - const nuxtApp = useNuxtApp() - if (nuxtApp._observer) { - return nuxtApp._observer - } - - let observer: IntersectionObserver | null = null - - const callbacks = new Map() - - const observe: ObserveFn = (element, callback) => { - if (!observer) { - observer = new IntersectionObserver((entries) => { - for (const entry of entries) { - const callback = callbacks.get(entry.target) - const isVisible = entry.isIntersecting || entry.intersectionRatio > 0 - if (isVisible && callback) { callback() } - } - }) - } - callbacks.set(element, callback) - observer.observe(element) - return () => { - callbacks.delete(element) - observer!.unobserve(element) - if (callbacks.size === 0) { - observer!.disconnect() - observer = null - } - } - } - - const _observer = nuxtApp._observer = { - observe - } - - return _observer -} function isSlowConnection () { if (import.meta.server) { return } From f039dfd09f6ebf7618d346ab045a6bf1cf994029 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 25 Mar 2024 15:07:52 +0200 Subject: [PATCH 013/123] feat: provide exported function --- packages/nuxt/src/app/utils.ts | 61 ++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/packages/nuxt/src/app/utils.ts b/packages/nuxt/src/app/utils.ts index 4cc2040ad9a3..2dd929f23ebf 100644 --- a/packages/nuxt/src/app/utils.ts +++ b/packages/nuxt/src/app/utils.ts @@ -1,3 +1,64 @@ +import type { + AllowedComponentProps, + AnchorHTMLAttributes, + ComputedRef, + DefineComponent, + InjectionKey, PropType, + VNodeProps +} from 'vue' +import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, provide, ref, resolveComponent } from 'vue' +import type { RouteLocation, RouteLocationRaw, Router, RouterLinkProps } from '#vue-router' +import { hasProtocol, joinURL, parseQuery, parseURL, withTrailingSlash, withoutTrailingSlash } from 'ufo' +import { preloadRouteComponents } from './composables/preload' +import { onNuxtReady } from './composables/ready' +import { navigateTo, useRouter } from './composables/router' +import { useNuxtApp, useRuntimeConfig } from './nuxt' +import { cancelIdleCallback, requestIdleCallback } from './idle-callback' + export function toArray (value: T | T[]): T[] { return Array.isArray(value) ? value : [value] } + +export type CallbackFn = () => void +type ObserveFn = (element: Element, callback: CallbackFn) => () => void + +function useObserver (): { observe: ObserveFn } | undefined { + if (import.meta.server) { return } + + const nuxtApp = useNuxtApp() + if (nuxtApp._observer) { + return nuxtApp._observer + } + + let observer: IntersectionObserver | null = null + + const callbacks = new Map() + + const observe: ObserveFn = (element, callback) => { + if (!observer) { + observer = new IntersectionObserver((entries) => { + for (const entry of entries) { + const callback = callbacks.get(entry.target) + const isVisible = entry.isIntersecting || entry.intersectionRatio > 0 + if (isVisible && callback) { callback() } + } + }) + } + callbacks.set(element, callback) + observer.observe(element) + return () => { + callbacks.delete(element) + observer!.unobserve(element) + if (callbacks.size === 0) { + observer!.disconnect() + observer = null + } + } + } + + const _observer = nuxtApp._observer = { + observe + } + + return _observer +} From 7d2f3455112e7ae73473090e4a88354e42597a14 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 25 Mar 2024 15:12:09 +0200 Subject: [PATCH 014/123] fix: remove unnecessary imports --- packages/nuxt/src/app/utils.ts | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/packages/nuxt/src/app/utils.ts b/packages/nuxt/src/app/utils.ts index 2dd929f23ebf..4d5d2c3ae857 100644 --- a/packages/nuxt/src/app/utils.ts +++ b/packages/nuxt/src/app/utils.ts @@ -1,19 +1,4 @@ -import type { - AllowedComponentProps, - AnchorHTMLAttributes, - ComputedRef, - DefineComponent, - InjectionKey, PropType, - VNodeProps -} from 'vue' -import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, provide, ref, resolveComponent } from 'vue' -import type { RouteLocation, RouteLocationRaw, Router, RouterLinkProps } from '#vue-router' -import { hasProtocol, joinURL, parseQuery, parseURL, withTrailingSlash, withoutTrailingSlash } from 'ufo' -import { preloadRouteComponents } from './composables/preload' -import { onNuxtReady } from './composables/ready' -import { navigateTo, useRouter } from './composables/router' -import { useNuxtApp, useRuntimeConfig } from './nuxt' -import { cancelIdleCallback, requestIdleCallback } from './idle-callback' +import { useNuxtApp } from './nuxt' export function toArray (value: T | T[]): T[] { return Array.isArray(value) ? value : [value] From f51c9362ce1c4681e05047b6f04152f3962c6e8e Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 25 Mar 2024 15:15:11 +0200 Subject: [PATCH 015/123] fix: export function as opposed to type --- packages/nuxt/src/app/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/app/utils.ts b/packages/nuxt/src/app/utils.ts index 4d5d2c3ae857..2bd768f257e4 100644 --- a/packages/nuxt/src/app/utils.ts +++ b/packages/nuxt/src/app/utils.ts @@ -4,10 +4,10 @@ export function toArray (value: T | T[]): T[] { return Array.isArray(value) ? value : [value] } -export type CallbackFn = () => void +type CallbackFn = () => void type ObserveFn = (element: Element, callback: CallbackFn) => () => void -function useObserver (): { observe: ObserveFn } | undefined { +export function useObserver (): { observe: ObserveFn } | undefined { if (import.meta.server) { return } const nuxtApp = useNuxtApp() From b3b16762022562ff38da11d5b98aa82f28a114e8 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 13:17:29 +0000 Subject: [PATCH 016/123] [autofix.ci] apply automated fixes --- packages/nuxt/src/app/components/nuxt-link.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/app/components/nuxt-link.ts b/packages/nuxt/src/app/components/nuxt-link.ts index cbc0f5d20618..59adede3ada8 100644 --- a/packages/nuxt/src/app/components/nuxt-link.ts +++ b/packages/nuxt/src/app/components/nuxt-link.ts @@ -14,7 +14,7 @@ import { onNuxtReady } from '../composables/ready' import { navigateTo, useRouter } from '../composables/router' import { useNuxtApp, useRuntimeConfig } from '../nuxt' import { cancelIdleCallback, requestIdleCallback } from '../compat/idle-callback' -import { useObserver } from "../utils" +import { useObserver } from '../utils' // @ts-expect-error virtual file import { nuxtLinkDefaults } from '#build/nuxt.config.mjs' From 966c17be720593d35d1d911b487eb8dc2141c481 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 25 Mar 2024 19:19:35 +0200 Subject: [PATCH 017/123] fix: provide a proper wrapper for IO with the comp --- .../components/runtime/client-io-component.ts | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index 98b523e341f9..0015a8804c97 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -1,34 +1,38 @@ -import { defineComponent, onMounted, onUnmounted, ref } from 'vue' -import type { Ref } from 'vue' +import { defineComponent, h, ref, onMounted, onBeforeUnmount } from 'vue' +import type { Component, Ref } from "vue" +import ClientOnly from '#app/components/client-only' +import { useObserver } from "#app/utils" -export default defineComponent({ - emits: ['intersect'], - setup (props, { emit }) { - const intersectionTarget: Ref = ref(null) - let observer: IntersectionObserver | null = null - - const intersectionCallback: IntersectionObserverCallback = (entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - emit('intersect') - observer!.unobserve(entry.target) - } +export const createLazyIOClientPage = (componentLoader: Component) => { + return defineComponent({ + inheritAttrs: false, + setup (_, { attrs }) { + const isIntersecting = ref(false); + const el: Ref = ref(null); + let unobserve: (() => void) | null = null + 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 }, [ + h(ClientOnly, undefined, { + default: () => { + if (isIntersecting.value) { + return h(componentLoader, attrs); + } else { + return null; + } + } + }) + ]); } - - onMounted(() => { - observer = new IntersectionObserver(intersectionCallback) - observer.observe(intersectionTarget.value as Element) - }) - - onUnmounted(() => { - if (observer) { - observer.disconnect() - } - }) - - return { - intersectionTarget - } - } -}) + }); +}; From f6ba2255e6fe8a268148156cf3df1585d66f7558 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 25 Mar 2024 19:21:01 +0200 Subject: [PATCH 018/123] fix: ensure observer is not undefined --- packages/nuxt/src/components/runtime/client-io-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index 0015a8804c97..c3856b6747e3 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -12,7 +12,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { let unobserve: (() => void) | null = null onMounted(() => { const observer = useObserver() - unobserve = observer.observe(el.value as Element, () => { + unobserve = observer!.observe(el.value as Element, () => { isIntersecting.value = true unobserve?.() unobserve = null From 1e16b4a0886e93cd7b617d54a0661e445cc207d0 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 17:23:25 +0000 Subject: [PATCH 019/123] [autofix.ci] apply automated fixes --- .../components/runtime/client-io-component.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-io-component.ts index c3856b6747e3..dab60611f32e 100644 --- a/packages/nuxt/src/components/runtime/client-io-component.ts +++ b/packages/nuxt/src/components/runtime/client-io-component.ts @@ -1,14 +1,14 @@ -import { defineComponent, h, ref, onMounted, onBeforeUnmount } from 'vue' -import type { Component, Ref } from "vue" +import { defineComponent, h, onBeforeUnmount, onMounted, ref } from 'vue' +import type { Component, Ref } from 'vue' import ClientOnly from '#app/components/client-only' -import { useObserver } from "#app/utils" +import { useObserver } from '#app/utils' export const createLazyIOClientPage = (componentLoader: Component) => { return defineComponent({ inheritAttrs: false, setup (_, { attrs }) { - const isIntersecting = ref(false); - const el: Ref = ref(null); + const isIntersecting = ref(false) + const el: Ref = ref(null) let unobserve: (() => void) | null = null onMounted(() => { const observer = useObserver() @@ -17,7 +17,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { unobserve?.() unobserve = null }) - }); + }) onBeforeUnmount(() => { unobserve?.() unobserve = null @@ -26,13 +26,13 @@ export const createLazyIOClientPage = (componentLoader: Component) => { h(ClientOnly, undefined, { default: () => { if (isIntersecting.value) { - return h(componentLoader, attrs); + return h(componentLoader, attrs) } else { - return null; + return null } } }) - ]); + ]) } - }); -}; + }) +} From 600f55d2a35fc3d1d44baf5bf48d152558c9aca1 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Tue, 26 Mar 2024 16:20:49 +0200 Subject: [PATCH 020/123] wip: rename client-io-component.ts to client-delayed-component.ts for future wrappers --- .../{client-io-component.ts => client-delayed-component.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/nuxt/src/components/runtime/{client-io-component.ts => client-delayed-component.ts} (100%) diff --git a/packages/nuxt/src/components/runtime/client-io-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts similarity index 100% rename from packages/nuxt/src/components/runtime/client-io-component.ts rename to packages/nuxt/src/components/runtime/client-delayed-component.ts From 66938bc152bf911d7a039cfb4fe41b0dfe7ad997 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 07:24:28 +0000 Subject: [PATCH 021/123] [autofix.ci] apply automated fixes --- packages/nuxt/src/app/utils.ts | 2 +- .../nuxt/src/components/runtime/client-delayed-component.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/nuxt/src/app/utils.ts b/packages/nuxt/src/app/utils.ts index 2bd768f257e4..a46715cb2109 100644 --- a/packages/nuxt/src/app/utils.ts +++ b/packages/nuxt/src/app/utils.ts @@ -42,7 +42,7 @@ export function useObserver (): { observe: ObserveFn } | undefined { } const _observer = nuxtApp._observer = { - observe + observe, } return _observer diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index dab60611f32e..e50ef9849a5b 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -30,9 +30,9 @@ export const createLazyIOClientPage = (componentLoader: Component) => { } else { return null } - } - }) + }, + }), ]) - } + }, }) } From 20a32b2200b0ec631af8021332e996da57eebccd Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 17:19:59 +0300 Subject: [PATCH 022/123] wip: provide hardcoded check to test delayed hydration runtime comp --- packages/nuxt/src/components/loader.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index 628638ffad14..8c74efd0e157 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -21,7 +21,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { const exclude = options.transform?.exclude || [] const include = options.transform?.include || [] const serverComponentRuntime = resolve(distDir, 'components/runtime/server-component') - + const clientDelayedComponentRuntime = resolve(distDir, 'components/runtime/client-delayed-component') return { name: 'nuxt:components-loader', enforce: 'post', @@ -72,9 +72,17 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { } if (lazy) { - imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) - identifier += '_lazy' - imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`) + // Temporary hardcoded check to verify runtime functionality + if (name === "DelayedWrapperTestComponent") { + imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) + imports.add(`const ${identifier} = createLazyIOClientPage(${JSON.stringify(name)})`) + identifier += '_delayedIO' + } + else { + imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) + identifier += '_lazy' + imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`) + } } else { imports.add(genImport(component.filePath, [{ name: component._raw ? 'default' : component.export, as: identifier }])) From 816ba111b4caa2e043bedb730d0befb7b32cda9a Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 14:22:13 +0000 Subject: [PATCH 023/123] [autofix.ci] apply automated fixes --- packages/nuxt/src/components/loader.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index 8c74efd0e157..00f3139aa7c9 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -73,12 +73,11 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { if (lazy) { // Temporary hardcoded check to verify runtime functionality - if (name === "DelayedWrapperTestComponent") { - imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) - imports.add(`const ${identifier} = createLazyIOClientPage(${JSON.stringify(name)})`) - identifier += '_delayedIO' - } - else { + if (name === 'DelayedWrapperTestComponent') { + imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) + imports.add(`const ${identifier} = createLazyIOClientPage(${JSON.stringify(name)})`) + identifier += '_delayedIO' + } else { imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) identifier += '_lazy' imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`) From 6c683e0b6eaeca01e2158c2bf77a31dc7e7c4f20 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 17:37:18 +0300 Subject: [PATCH 024/123] wip: add comp to lazy-import-components --- test/fixtures/basic/pages/lazy-import-components/index.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/fixtures/basic/pages/lazy-import-components/index.vue b/test/fixtures/basic/pages/lazy-import-components/index.vue index 0f46fc9dfc61..e57695045f21 100644 --- a/test/fixtures/basic/pages/lazy-import-components/index.vue +++ b/test/fixtures/basic/pages/lazy-import-components/index.vue @@ -3,5 +3,7 @@ +
This is a very tall div
+ This shouldn't be visible at first! From 998c1ba5513826019769ee6cc3451467e50411f7 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 14:39:42 +0000 Subject: [PATCH 025/123] [autofix.ci] apply automated fixes --- test/fixtures/basic/pages/lazy-import-components/index.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/fixtures/basic/pages/lazy-import-components/index.vue b/test/fixtures/basic/pages/lazy-import-components/index.vue index e57695045f21..1760bbd4fb27 100644 --- a/test/fixtures/basic/pages/lazy-import-components/index.vue +++ b/test/fixtures/basic/pages/lazy-import-components/index.vue @@ -3,7 +3,9 @@ -
This is a very tall div
+
+ This is a very tall div +
This shouldn't be visible at first! From 4cc9efe563598339453988db236e09bfeb89d6b4 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 17:59:41 +0300 Subject: [PATCH 026/123] wip: add initial lazy load check --- test/basic.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/basic.test.ts b/test/basic.test.ts index 9e5983c4c422..2bd13d73f092 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2562,4 +2562,8 @@ describe('lazy import components', () => { it('lazy load named component with mode server', () => { expect(html).toContain('lazy-named-comp-server') }) + + it('lazy load delayed hydration comps at the right time', () => { + expect(html).not.toContain("This shouldn't be visible at first!") + }) }) From d209a02492cc6feacb85f262abdeaa925d2873dc Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 15:02:03 +0000 Subject: [PATCH 027/123] [autofix.ci] apply automated fixes --- test/basic.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 2bd13d73f092..b0c7787d6d84 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2562,8 +2562,8 @@ describe('lazy import components', () => { it('lazy load named component with mode server', () => { expect(html).toContain('lazy-named-comp-server') }) - + it('lazy load delayed hydration comps at the right time', () => { - expect(html).not.toContain("This shouldn't be visible at first!") + expect(html).not.toContain('This shouldn\'t be visible at first!') }) }) From 88bae15ad7ed1e5c1e0c3ec6607931baea9160d9 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 18:52:27 +0300 Subject: [PATCH 028/123] wip: testing page text getting --- test/basic.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/basic.test.ts b/test/basic.test.ts index b0c7787d6d84..170e7dd73a04 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2565,5 +2565,7 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', () => { expect(html).not.toContain('This shouldn\'t be visible at first!') + const { page } = await renderPage('/lazy-import-components') + expect(page.locator('body').getByText('This shouldn\'t be visible at first!')).not.toBeDefined() }) }) From 00a68bd7ff3951095d3fd1cc557da89fbbe14558 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 18:56:25 +0300 Subject: [PATCH 029/123] fix: async --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 170e7dd73a04..d7ea4053e154 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2563,7 +2563,7 @@ describe('lazy import components', () => { expect(html).toContain('lazy-named-comp-server') }) - it('lazy load delayed hydration comps at the right time', () => { + it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') expect(page.locator('body').getByText('This shouldn\'t be visible at first!')).not.toBeDefined() From 10f7f22c828f4189d9c2c403fac8836df06d1dfd Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 19:03:15 +0300 Subject: [PATCH 030/123] fix: check for count --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index d7ea4053e154..c4eed1289105 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2566,6 +2566,6 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') - expect(page.locator('body').getByText('This shouldn\'t be visible at first!')).not.toBeDefined() + expect(page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) }) }) From 84b2333cf567014809edc83390734c7938de9bf7 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 19:09:35 +0300 Subject: [PATCH 031/123] fix: await --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index c4eed1289105..a5a42fca1043 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2566,6 +2566,6 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') - expect(page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) + expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) }) }) From d89e70e065dadb6157a4a78b82e1378e6f9b698a Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 19:18:09 +0300 Subject: [PATCH 032/123] Create DelayedWrapperTestComponent.vue --- .../basic/components/DelayedWrapperTestComponent.vue | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test/fixtures/basic/components/DelayedWrapperTestComponent.vue diff --git a/test/fixtures/basic/components/DelayedWrapperTestComponent.vue b/test/fixtures/basic/components/DelayedWrapperTestComponent.vue new file mode 100644 index 000000000000..d42e68faf42c --- /dev/null +++ b/test/fixtures/basic/components/DelayedWrapperTestComponent.vue @@ -0,0 +1,5 @@ + From 4b0d88c54e6e794b1badb7f159918305954ea457 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 19:18:47 +0300 Subject: [PATCH 033/123] refactor: use a component to test transform --- test/fixtures/basic/pages/lazy-import-components/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/basic/pages/lazy-import-components/index.vue b/test/fixtures/basic/pages/lazy-import-components/index.vue index 1760bbd4fb27..c1cd4ce9f699 100644 --- a/test/fixtures/basic/pages/lazy-import-components/index.vue +++ b/test/fixtures/basic/pages/lazy-import-components/index.vue @@ -6,6 +6,6 @@
This is a very tall div
- This shouldn't be visible at first! + From 2236f7856621068c5feb0acd09f74b95b61c25b5 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:21:16 +0000 Subject: [PATCH 034/123] [autofix.ci] apply automated fixes --- test/fixtures/basic/pages/lazy-import-components/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/basic/pages/lazy-import-components/index.vue b/test/fixtures/basic/pages/lazy-import-components/index.vue index c1cd4ce9f699..eafa6d837576 100644 --- a/test/fixtures/basic/pages/lazy-import-components/index.vue +++ b/test/fixtures/basic/pages/lazy-import-components/index.vue @@ -6,6 +6,6 @@
This is a very tall div
- + From 36dc73152f69e84fcd76347eec6d6bd77f88aedf Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 19:28:58 +0300 Subject: [PATCH 035/123] fix: append identifier before import --- packages/nuxt/src/components/loader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index 00f3139aa7c9..129a229bc0c2 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -75,8 +75,8 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { // Temporary hardcoded check to verify runtime functionality if (name === 'DelayedWrapperTestComponent') { imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) - imports.add(`const ${identifier} = createLazyIOClientPage(${JSON.stringify(name)})`) identifier += '_delayedIO' + imports.add(`const ${identifier} = createLazyIOClientPage(${JSON.stringify(name)})`) } else { imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) identifier += '_lazy' From dd36a181401b660349b7d2a52243701928cc0f63 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 19:58:33 +0300 Subject: [PATCH 036/123] wip: add scrolling to test for delayed hydration --- test/basic.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/basic.test.ts b/test/basic.test.ts index a5a42fca1043..fef26e99f3b8 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2567,5 +2567,9 @@ describe('lazy import components', () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) + await page.evaluate(()=>{ + window.scrollTo(0, document.body.scrollHeight) + }) + expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) }) }) From bd7ca85fb4e03c83e474fc36956b50e4ce4d911d Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:00:52 +0000 Subject: [PATCH 037/123] [autofix.ci] apply automated fixes --- test/basic.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index fef26e99f3b8..8757d8cca1c2 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2567,9 +2567,9 @@ describe('lazy import components', () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) - await page.evaluate(()=>{ - window.scrollTo(0, document.body.scrollHeight) - }) + await page.evaluate(() => { + window.scrollTo(0, document.body.scrollHeight) + }) expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) }) }) From 5653d9e255780ae5a8c5cfd6607f361710e85a02 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 8 Apr 2024 20:16:18 +0300 Subject: [PATCH 038/123] wip: retrying through mouse.wheel --- test/basic.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 8757d8cca1c2..36ea3c7197b5 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2567,9 +2567,7 @@ describe('lazy import components', () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) - await page.evaluate(() => { - window.scrollTo(0, document.body.scrollHeight) - }) + await page.mouse.wheel(0,4000) expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) }) }) From 26f2e4e7d1b9cbb6bb836d040666b4552c0d2146 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:18:37 +0000 Subject: [PATCH 039/123] [autofix.ci] apply automated fixes --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 36ea3c7197b5..a7d010d04b5e 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2567,7 +2567,7 @@ describe('lazy import components', () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) - await page.mouse.wheel(0,4000) + await page.mouse.wheel(0, 4000) expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) }) }) From 988a99b771a64d30b7cf4e411bea26690d0822fe Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Tue, 9 Apr 2024 21:49:02 +0300 Subject: [PATCH 040/123] fix: don't use the default that is used for slots --- .../components/runtime/client-delayed-component.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index e50ef9849a5b..a7b9595eaf7e 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -23,15 +23,9 @@ export const createLazyIOClientPage = (componentLoader: Component) => { unobserve = null }) return () => h('div', { ref: el }, [ - h(ClientOnly, undefined, { - default: () => { - if (isIntersecting.value) { - return h(componentLoader, attrs) - } else { - return null - } - }, - }), + h(ClientOnly, undefined, [ + isIntersecting.value ? h(componentLoader, attrs) : null + ]), ]) }, }) From 669fcee81bfa33b0c68cb28ae91c960ab18d8283 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 18:51:50 +0000 Subject: [PATCH 041/123] [autofix.ci] apply automated fixes --- .../nuxt/src/components/runtime/client-delayed-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index a7b9595eaf7e..0a538df3b738 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -24,7 +24,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { }) return () => h('div', { ref: el }, [ h(ClientOnly, undefined, [ - isIntersecting.value ? h(componentLoader, attrs) : null + isIntersecting.value ? h(componentLoader, attrs) : null, ]), ]) }, From 9b94d100a2e46aab8986c531317a236ddfc32280 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Tue, 9 Apr 2024 22:01:37 +0300 Subject: [PATCH 042/123] chore: retrying without ClientOnly --- .../nuxt/src/components/runtime/client-delayed-component.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 0a538df3b738..60c1e6a5b954 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -1,6 +1,6 @@ import { defineComponent, h, onBeforeUnmount, onMounted, ref } from 'vue' import type { Component, Ref } from 'vue' -import ClientOnly from '#app/components/client-only' +// import ClientOnly from '#app/components/client-only' import { useObserver } from '#app/utils' export const createLazyIOClientPage = (componentLoader: Component) => { @@ -23,9 +23,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { unobserve = null }) return () => h('div', { ref: el }, [ - h(ClientOnly, undefined, [ - isIntersecting.value ? h(componentLoader, attrs) : null, - ]), + isIntersecting.value ? h(componentLoader, attrs) : null, ]) }, }) From 3a8b1f3b75a99ae7c401141310e98093ecace839 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Tue, 9 Apr 2024 22:04:39 +0300 Subject: [PATCH 043/123] chore: rerunning tests From 59edd16fce71078c525ec3479598271dd9ab87cb Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Tue, 9 Apr 2024 22:12:57 +0300 Subject: [PATCH 044/123] chore: mark no side effects --- packages/nuxt/src/components/runtime/client-delayed-component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 60c1e6a5b954..a0b115edf945 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -3,6 +3,7 @@ import type { Component, Ref } from 'vue' // import ClientOnly from '#app/components/client-only' import { useObserver } from '#app/utils' +/* @__NO_SIDE_EFFECTS__ */ export const createLazyIOClientPage = (componentLoader: Component) => { return defineComponent({ inheritAttrs: false, From d4bca6cd5769908bb9e325d224a316e9415dbc5c Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Tue, 9 Apr 2024 22:24:48 +0300 Subject: [PATCH 045/123] refactor: use page.evaluate --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index a7d010d04b5e..5de13d028bf2 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2567,7 +2567,7 @@ describe('lazy import components', () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) - await page.mouse.wheel(0, 4000) + await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) }) }) From b3250e4a46814403f40d21bb76ff81fcf1a747b5 Mon Sep 17 00:00:00 2001 From: julien huang Date: Tue, 9 Apr 2024 21:55:27 +0200 Subject: [PATCH 046/123] fix(nuxt): send the component loader and not the name --- packages/nuxt/src/components/loader.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index 129a229bc0c2..fa92433bf00b 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -74,9 +74,10 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { if (lazy) { // Temporary hardcoded check to verify runtime functionality if (name === 'DelayedWrapperTestComponent') { + imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) identifier += '_delayedIO' - imports.add(`const ${identifier} = createLazyIOClientPage(${JSON.stringify(name)})`) + imports.add(`const ${identifier} = createLazyIOClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath)}))`) } else { imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) identifier += '_lazy' From 8c1c23a422a78514b5a5bb8f2174d4495a9b64f7 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Tue, 9 Apr 2024 23:47:41 +0300 Subject: [PATCH 047/123] chore: trying to resolve default --- packages/nuxt/src/components/loader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index fa92433bf00b..46aba7711723 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -77,7 +77,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) identifier += '_delayedIO' - imports.add(`const ${identifier} = createLazyIOClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath)}))`) + imports.add(`const ${identifier} = createLazyIOClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)))`) } else { imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) identifier += '_lazy' From 45e49c5beb96ecf2f07462846dd7204910637dd8 Mon Sep 17 00:00:00 2001 From: julien huang Date: Tue, 9 Apr 2024 23:10:31 +0200 Subject: [PATCH 048/123] test: wait for network idle --- test/basic.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 5de13d028bf2..a3597b8dbc08 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2544,7 +2544,7 @@ describe('import components', () => { }) }) -describe('lazy import components', () => { +describe.only('lazy import components', () => { let html = '' it.sequential('fetch lazy-import-components page', async () => { @@ -2568,6 +2568,7 @@ describe('lazy import components', () => { const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) + await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) }) }) From 382bc93efea8bb625e38862b5d54bc5112d7558d Mon Sep 17 00:00:00 2001 From: julien huang Date: Tue, 9 Apr 2024 23:14:44 +0200 Subject: [PATCH 049/123] test: remove only --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index a3597b8dbc08..9b9046902a7c 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2544,7 +2544,7 @@ describe('import components', () => { }) }) -describe.only('lazy import components', () => { +describe('lazy import components', () => { let html = '' it.sequential('fetch lazy-import-components page', async () => { From 503b560d9b3264a70dc2b550bd3f1b5f5f7d9ce5 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Wed, 10 Apr 2024 10:00:38 +0300 Subject: [PATCH 050/123] wip: network idle based delayed component --- .../runtime/client-delayed-component.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index a0b115edf945..af37ff6b05df 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -29,3 +29,28 @@ export const createLazyIOClientPage = (componentLoader: Component) => { }, }) } + +/* @__NO_SIDE_EFFECTS__ */ +export const createLazyNetworkClientPage = (componentLoader: Component) => { + return defineComponent({ + inheritAttrs: false, + setup (_, { attrs }) { + const isIdle = ref(false) + let idleHandle: number | null = null + onMounted(() => { + idleHandle = requestIdleCallback(() => { + isIdle.value = true + cancelIdleCallback(idleHandle) + idleHandle = null + }) + }) + onBeforeUnmount(() => { + if (idleHandle) { + cancelIdleCallback(idleHandle) + idleHandle = null + } + }) + return () => isIdle.value ? h(componentLoader, attrs) : null, + }, + }) +} From 2df20ac6813b18e3b28cab7addbfb546cd864969 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Wed, 10 Apr 2024 10:02:39 +0300 Subject: [PATCH 051/123] fix: remove comma --- .../nuxt/src/components/runtime/client-delayed-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index af37ff6b05df..95f079963452 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -50,7 +50,7 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { idleHandle = null } }) - return () => isIdle.value ? h(componentLoader, attrs) : null, + return () => isIdle.value ? h(componentLoader, attrs) : null }, }) } From effebbb02f91429eba13f98942a58dc404836aac Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Wed, 10 Apr 2024 10:32:26 +0300 Subject: [PATCH 052/123] fix: strict types --- .../nuxt/src/components/runtime/client-delayed-component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 95f079963452..c14f92d412ec 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -40,13 +40,13 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { onMounted(() => { idleHandle = requestIdleCallback(() => { isIdle.value = true - cancelIdleCallback(idleHandle) + cancelIdleCallback(idleHandle as unknown as number) idleHandle = null }) }) onBeforeUnmount(() => { if (idleHandle) { - cancelIdleCallback(idleHandle) + cancelIdleCallback(idleHandle as unknown as number) idleHandle = null } }) From 2375650c36e7e38c83b018a650af1d8575919fb3 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Thu, 11 Apr 2024 00:02:48 +0300 Subject: [PATCH 053/123] feat: support lazy hydration on SSR --- .../runtime/client-delayed-component.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index c14f92d412ec..c899bd3e1d34 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -1,13 +1,20 @@ -import { defineComponent, h, onBeforeUnmount, onMounted, ref } from 'vue' +import { defineComponent, h, onBeforeUnmount, onMounted, ref, getCurrentInstance, createStaticVNode } from 'vue' import type { Component, Ref } from 'vue' // import ClientOnly from '#app/components/client-only' import { useObserver } from '#app/utils' +import { getFragmentHTML } from '#app/components/utils' /* @__NO_SIDE_EFFECTS__ */ export const createLazyIOClientPage = (componentLoader: Component) => { return defineComponent({ inheritAttrs: false, setup (_, { attrs }) { + const nuxt = useNuxtApp() + const instance = getCurrentInstance()! + let vnode = null + if (import.meta.client && nuxt.isHydrating) { + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el), 1) + } const isIntersecting = ref(false) const el: Ref = ref(null) let unobserve: (() => void) | null = null @@ -24,7 +31,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { unobserve = null }) return () => h('div', { ref: el }, [ - isIntersecting.value ? h(componentLoader, attrs) : null, + isIntersecting.value ? h(componentLoader, attrs) : vnode, ]) }, }) @@ -35,6 +42,12 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { return defineComponent({ inheritAttrs: false, setup (_, { attrs }) { + const nuxt = useNuxtApp() + const instance = getCurrentInstance()! + let vnode = null + if (import.meta.client && nuxt.isHydrating) { + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el), 1) + } const isIdle = ref(false) let idleHandle: number | null = null onMounted(() => { @@ -50,7 +63,7 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { idleHandle = null } }) - return () => isIdle.value ? h(componentLoader, attrs) : null + return () => isIdle.value ? h(componentLoader, attrs) : vnode }, }) } From 31002ecc2d832f439a332c82cb6e099601304435 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:05:11 +0000 Subject: [PATCH 054/123] [autofix.ci] apply automated fixes --- .../nuxt/src/components/runtime/client-delayed-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index c899bd3e1d34..24a6c5d65e5a 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -1,4 +1,4 @@ -import { defineComponent, h, onBeforeUnmount, onMounted, ref, getCurrentInstance, createStaticVNode } from 'vue' +import { createStaticVNode, defineComponent, getCurrentInstance, h, onBeforeUnmount, onMounted, ref } from 'vue' import type { Component, Ref } from 'vue' // import ClientOnly from '#app/components/client-only' import { useObserver } from '#app/utils' From 580d9bd4635a557c4993557333d05c942f917958 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Thu, 11 Apr 2024 00:06:49 +0300 Subject: [PATCH 055/123] fix: import useNuxtApp and provide types --- .../nuxt/src/components/runtime/client-delayed-component.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 24a6c5d65e5a..5ce547db5635 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -3,6 +3,7 @@ import type { Component, Ref } 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' /* @__NO_SIDE_EFFECTS__ */ export const createLazyIOClientPage = (componentLoader: Component) => { @@ -11,7 +12,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { setup (_, { attrs }) { const nuxt = useNuxtApp() const instance = getCurrentInstance()! - let vnode = null + let vnode: string | null = null if (import.meta.client && nuxt.isHydrating) { vnode = createStaticVNode(getFragmentHTML(instance.vnode.el), 1) } @@ -44,7 +45,7 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { setup (_, { attrs }) { const nuxt = useNuxtApp() const instance = getCurrentInstance()! - let vnode = null + let vnode: string | null = null if (import.meta.client && nuxt.isHydrating) { vnode = createStaticVNode(getFragmentHTML(instance.vnode.el), 1) } From e2d0350698afdd7e939f94f0597731501259e010 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Thu, 11 Apr 2024 00:10:54 +0300 Subject: [PATCH 056/123] fix: use VNode type --- .../nuxt/src/components/runtime/client-delayed-component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 5ce547db5635..1acf7daac3cc 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -1,5 +1,5 @@ import { createStaticVNode, defineComponent, getCurrentInstance, h, onBeforeUnmount, onMounted, ref } from 'vue' -import type { Component, Ref } 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' @@ -12,7 +12,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { setup (_, { attrs }) { const nuxt = useNuxtApp() const instance = getCurrentInstance()! - let vnode: string | null = null + let vnode: VNode | null = null if (import.meta.client && nuxt.isHydrating) { vnode = createStaticVNode(getFragmentHTML(instance.vnode.el), 1) } @@ -45,7 +45,7 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { setup (_, { attrs }) { const nuxt = useNuxtApp() const instance = getCurrentInstance()! - let vnode: string | null = null + let vnode: VNode | null = null if (import.meta.client && nuxt.isHydrating) { vnode = createStaticVNode(getFragmentHTML(instance.vnode.el), 1) } From dc6d92277336c584b9f22c228ab94231b9adb328 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Thu, 11 Apr 2024 00:13:22 +0300 Subject: [PATCH 057/123] fix: join the fragments --- .../nuxt/src/components/runtime/client-delayed-component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 1acf7daac3cc..00099624805a 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -14,7 +14,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { const instance = getCurrentInstance()! let vnode: VNode | null = null if (import.meta.client && nuxt.isHydrating) { - vnode = createStaticVNode(getFragmentHTML(instance.vnode.el), 1) + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el).join(''), 1) } const isIntersecting = ref(false) const el: Ref = ref(null) @@ -47,7 +47,7 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { const instance = getCurrentInstance()! let vnode: VNode | null = null if (import.meta.client && nuxt.isHydrating) { - vnode = createStaticVNode(getFragmentHTML(instance.vnode.el), 1) + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el).join(''), 1) } const isIdle = ref(false) let idleHandle: number | null = null From 2ee3cf53eebbfc31ab4def9882d03854efd10125 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Thu, 11 Apr 2024 00:16:39 +0300 Subject: [PATCH 058/123] fix: verify none null --- .../src/components/runtime/client-delayed-component.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 00099624805a..177819c34fa4 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -13,8 +13,8 @@ export const createLazyIOClientPage = (componentLoader: Component) => { const nuxt = useNuxtApp() const instance = getCurrentInstance()! let vnode: VNode | null = null - if (import.meta.client && nuxt.isHydrating) { - vnode = createStaticVNode(getFragmentHTML(instance.vnode.el).join(''), 1) + if (import.meta.client && nuxt.isHydrating && instance.vnode?.el) { + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el).join('') || '', 1) } const isIntersecting = ref(false) const el: Ref = ref(null) @@ -46,8 +46,8 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { const nuxt = useNuxtApp() const instance = getCurrentInstance()! let vnode: VNode | null = null - if (import.meta.client && nuxt.isHydrating) { - vnode = createStaticVNode(getFragmentHTML(instance.vnode.el).join(''), 1) + if (import.meta.client && nuxt.isHydrating && instance.vnode?.el) { + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el).join('') || '', 1) } const isIdle = ref(false) let idleHandle: number | null = null From 8555cec97d27eb6c27a2c1f2182d3d5e316cb290 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Thu, 11 Apr 2024 00:20:34 +0300 Subject: [PATCH 059/123] fix: ensure el itself isn't null --- .../nuxt/src/components/runtime/client-delayed-component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 177819c34fa4..c2751450a504 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -14,7 +14,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { const instance = getCurrentInstance()! let vnode: VNode | null = null if (import.meta.client && nuxt.isHydrating && instance.vnode?.el) { - vnode = createStaticVNode(getFragmentHTML(instance.vnode.el).join('') || '', 1) + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true).join('') || '', 1) } const isIntersecting = ref(false) const el: Ref = ref(null) @@ -47,7 +47,7 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { const instance = getCurrentInstance()! let vnode: VNode | null = null if (import.meta.client && nuxt.isHydrating && instance.vnode?.el) { - vnode = createStaticVNode(getFragmentHTML(instance.vnode.el).join('') || '', 1) + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true).join('') || '', 1) } const isIdle = ref(false) let idleHandle: number | null = null From cb7fc3f873b5c3dbbe0f3df00f16c920cda0425a Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Thu, 11 Apr 2024 00:33:42 +0300 Subject: [PATCH 060/123] chore: rerunning tests From cfb6660fcd17dacb496a32f213751a1b316fb409 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Thu, 11 Apr 2024 00:42:29 +0300 Subject: [PATCH 061/123] fix: missing question marks --- .../nuxt/src/components/runtime/client-delayed-component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index c2751450a504..9ab87f6e6d83 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -14,7 +14,7 @@ export const createLazyIOClientPage = (componentLoader: Component) => { 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) + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1) } const isIntersecting = ref(false) const el: Ref = ref(null) @@ -47,7 +47,7 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { 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) + vnode = createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1) } const isIdle = ref(false) let idleHandle: number | null = null From e4c99402697374df6356f268529c987c7428bbed Mon Sep 17 00:00:00 2001 From: Julien Huang Date: Sat, 13 Apr 2024 11:06:09 +0200 Subject: [PATCH 062/123] fix: ssr improvement + static vnode rendering --- .../runtime/client-delayed-component.ts | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 9ab87f6e6d83..30760ae44067 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -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 = 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 From 5c300a4698a4daba7994d3166442a3b0233aa16f Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 10:38:41 +0000 Subject: [PATCH 063/123] [autofix.ci] apply automated fixes --- .../runtime/client-delayed-component.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 30760ae44067..7cb67d17fc2c 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -1,4 +1,4 @@ -import { createStaticVNode, defineComponent, getCurrentInstance, h, onBeforeUnmount, onMounted, ref, createVNode } from 'vue' +import { createStaticVNode, createVNode, defineComponent, getCurrentInstance, h, onBeforeUnmount, onMounted, ref } from 'vue' import type { Component, Ref, VNode } from 'vue' // import ClientOnly from '#app/components/client-only' import { useObserver } from '#app/utils' @@ -6,24 +6,22 @@ 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; +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) + h(componentLoader, attrs), ]) } @@ -65,7 +63,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 From 7821e7f441d442df0b8f51652cb49215294b8064 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sat, 13 Apr 2024 19:05:47 +0300 Subject: [PATCH 064/123] feat(schema): add experimental lazy hydration option --- packages/schema/src/config/experimental.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/schema/src/config/experimental.ts b/packages/schema/src/config/experimental.ts index 19403cc38eb6..6ec7eb1e5641 100644 --- a/packages/schema/src/config/experimental.ts +++ b/packages/schema/src/config/experimental.ts @@ -204,6 +204,13 @@ export default defineUntypedSchema({ }, }, + /** + * Experimental built-in delayed component hydration + * + * This enables components to lazily hydrate when needed, improving performance for sites with components below-the-fold + */ + componentLazyHydration: false, + /** * Config schema support * @see [Nuxt Issue #15592](https://github.com/nuxt/nuxt/issues/15592) From 162908aac09b87977f77845d5cd25489107b6d59 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 16:08:11 +0000 Subject: [PATCH 065/123] [autofix.ci] apply automated fixes --- packages/schema/src/config/experimental.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/schema/src/config/experimental.ts b/packages/schema/src/config/experimental.ts index 6ec7eb1e5641..081a38518695 100644 --- a/packages/schema/src/config/experimental.ts +++ b/packages/schema/src/config/experimental.ts @@ -206,11 +206,11 @@ export default defineUntypedSchema({ /** * Experimental built-in delayed component hydration - * + * * This enables components to lazily hydrate when needed, improving performance for sites with components below-the-fold - */ + */ componentLazyHydration: false, - + /** * Config schema support * @see [Nuxt Issue #15592](https://github.com/nuxt/nuxt/issues/15592) From fd0adea17935fe6b18edd95bb343d2dc4d614836 Mon Sep 17 00:00:00 2001 From: julien huang Date: Sat, 13 Apr 2024 20:14:36 +0200 Subject: [PATCH 066/123] fix: return render function and not vnode directly --- .../nuxt/src/components/runtime/client-delayed-component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 7cb67d17fc2c..e5a17a9808b3 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -18,9 +18,9 @@ function elementIsVisibleInViewport (el: Element) { export const createLazyIOClientPage = (componentLoader: Component) => { return defineComponent({ inheritAttrs: false, - setup (_, { attrs }) { + setup (_, { attrs }) { if (import.meta.server) { - return h('div', {}, [ + return () => h('div', {}, [ h(componentLoader, attrs), ]) } From 13949edeb35abfa1b7f4a2ea6d8fca958b880a9e Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sat, 13 Apr 2024 22:37:03 +0300 Subject: [PATCH 067/123] wip: wait for response with the component --- test/basic.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 7836bc369b49..eee6462fa66a 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2572,9 +2572,10 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') - expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(0) + expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) + const response = page.waitForResponse(response => response.url().includes("DelayedWrapperTestComponent") && response.status() === 200) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) + const resolvedResponse = await response await page.waitForLoadState('networkidle') - expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) }) }) From 9b8d33babfe154dc44260d13205a0c1d0c937370 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sat, 13 Apr 2024 22:39:23 +0300 Subject: [PATCH 068/123] fix: remove unused var --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index eee6462fa66a..24854e23cc86 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2575,7 +2575,7 @@ describe('lazy import components', () => { expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) const response = page.waitForResponse(response => response.url().includes("DelayedWrapperTestComponent") && response.status() === 200) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) - const resolvedResponse = await response + await response await page.waitForLoadState('networkidle') }) }) From 8eaf057ffe9e015d90575cbc7769da529e3b8b3e Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 19:41:39 +0000 Subject: [PATCH 069/123] [autofix.ci] apply automated fixes --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 24854e23cc86..080d62de3088 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2573,7 +2573,7 @@ describe('lazy import components', () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) - const response = page.waitForResponse(response => response.url().includes("DelayedWrapperTestComponent") && response.status() === 200) + const response = page.waitForResponse(response => response.url().includes('DelayedWrapperTestComponent') && response.status() === 200) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await response await page.waitForLoadState('networkidle') From 0cb15c6bbda6234bb1c53983b2a84ab55d1565e8 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 14 Apr 2024 12:53:49 +0300 Subject: [PATCH 070/123] chore: remove wait for load state --- test/basic.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 080d62de3088..88604092b618 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2576,6 +2576,5 @@ describe('lazy import components', () => { const response = page.waitForResponse(response => response.url().includes('DelayedWrapperTestComponent') && response.status() === 200) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await response - await page.waitForLoadState('networkidle') }) }) From 850287bf189ff401748884d763ee8e1fadc40640 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 14 Apr 2024 14:04:45 +0300 Subject: [PATCH 071/123] fix: remove the preload for SSR render of delayed hydration --- .../basic/server/plugins/basicRenderDelayedHydration.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts diff --git a/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts b/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts new file mode 100644 index 000000000000..2aa6ac3b6344 --- /dev/null +++ b/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts @@ -0,0 +1,5 @@ +export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook("render:html", (html, {event})=>{ + html.head = html.head.map((headSection:string)=>headSection.replace(/]+\bhref="\/_nuxt\/DelayedWrapperTestComponent\.([^.]+?)\.js")[^>]+>)/, "")) //.replace(//, "") + }) +}) From b45c3c9cae2e718ddc58b7cef19c0112e0544c49 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 14 Apr 2024 11:06:56 +0000 Subject: [PATCH 072/123] [autofix.ci] apply automated fixes --- .../basic/server/plugins/basicRenderDelayedHydration.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts b/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts index 2aa6ac3b6344..7236caaa0ad1 100644 --- a/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts +++ b/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts @@ -1,5 +1,5 @@ export default defineNitroPlugin((nitroApp) => { - nitroApp.hooks.hook("render:html", (html, {event})=>{ - html.head = html.head.map((headSection:string)=>headSection.replace(/]+\bhref="\/_nuxt\/DelayedWrapperTestComponent\.([^.]+?)\.js")[^>]+>)/, "")) //.replace(//, "") - }) + nitroApp.hooks.hook('render:html', (html, { event }) => { + html.head = html.head.map((headSection: string) => headSection.replace(/]+\bhref="\/_nuxt\/DelayedWrapperTestComponent\.([^.]+?)\.js")[^>]+>)/, '')) // .replace(//, "") + }) }) From 3076e02082283cb4c3f7a9f5d5c7d94e927a2715 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 06:47:41 +0000 Subject: [PATCH 073/123] [autofix.ci] apply automated fixes --- .../basic/server/plugins/basicRenderDelayedHydration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts b/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts index 7236caaa0ad1..6e7c7403059a 100644 --- a/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts +++ b/test/fixtures/basic/server/plugins/basicRenderDelayedHydration.ts @@ -1,5 +1,5 @@ export default defineNitroPlugin((nitroApp) => { nitroApp.hooks.hook('render:html', (html, { event }) => { - html.head = html.head.map((headSection: string) => headSection.replace(/]+\bhref="\/_nuxt\/DelayedWrapperTestComponent\.([^.]+?)\.js")[^>]+>)/, '')) // .replace(//, "") + html.head = html.head.map((headSection: string) => headSection.replace(/]+\bhref="\/_nuxt\/DelayedWrapperTestComponent\.([^.]+)\.js")[^>]+>)/, '')) // .replace(//, "") }) }) From fa46fe3e4f2b9e2a538483544819aa1054645675 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 17:12:01 +0300 Subject: [PATCH 074/123] feat: refactor regex, add network idle --- packages/nuxt/src/components/loader.ts | 31 ++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index 913415138557..b768ee462a64 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -43,7 +43,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { const s = new MagicString(code) // replace `_resolveComponent("...")` to direct import - s.replace(/(?<=[ (])_?resolveComponent\(\s*["'](lazy-|Lazy)?([^'"]*)["'][^)]*\)/g, (full: string, lazy: string, name: string) => { + s.replace(/(?<=[ (])_?resolveComponent\(\s*["'](lazy-|Lazy)?(Idle|Visible|idle-|visible-)?([^'"]*)["'][^)]*\)/g, (full: string, lazy: string, modifier: string, name: string) => { const component = findComponent(components, name, options.mode) if (component) { // @ts-expect-error TODO: refactor to nuxi @@ -72,6 +72,31 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { } if (lazy) { + if (modifier) { + switch (modifier) { + case "Visible": + case "visible-": + imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) + imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) + identifier += '_delayedIO' + imports.add(`const ${identifier} = createLazyIOClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)))`) + break; + case "Idle": + case "idle-": + imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) + imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyNetworkClientPage' }])) + identifier += '_delayedNetwork' + imports.add(`const ${identifier} = createLazyNetworkClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)))`) + break; + } + + } + else { + imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) + identifier += '_lazy' + imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`) + } + } // Temporary hardcoded check to verify runtime functionality if (name === 'DelayedWrapperTestComponent') { imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) @@ -79,9 +104,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { identifier += '_delayedIO' imports.add(`const ${identifier} = createLazyIOClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)))`) } else { - imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) - identifier += '_lazy' - imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`) + } } else { imports.add(genImport(component.filePath, [{ name: component._raw ? 'default' : component.export, as: identifier }])) From b1e66e5c05c70efad19d83ef160c63f387d85b74 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 17:13:03 +0300 Subject: [PATCH 075/123] fix: return component when server-side --- .../nuxt/src/components/runtime/client-delayed-component.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index e5a17a9808b3..431aae4bb036 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -64,6 +64,11 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { return defineComponent({ inheritAttrs: false, setup (_, { attrs }) { + if (import.meta.server) { + return () => h('div', {}, [ + h(componentLoader, attrs), + ]) + } const nuxt = useNuxtApp() const instance = getCurrentInstance()! let vnode: VNode | null = null From 4616c172e0571b5d9ef63f29f7243255da133494 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 17:18:40 +0300 Subject: [PATCH 076/123] fix: remove leftover previous code --- packages/nuxt/src/components/loader.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index b768ee462a64..92052bb544f9 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -95,17 +95,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) identifier += '_lazy' imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`) - } - } - // Temporary hardcoded check to verify runtime functionality - if (name === 'DelayedWrapperTestComponent') { - imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) - imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) - identifier += '_delayedIO' - imports.add(`const ${identifier} = createLazyIOClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)))`) - } else { - - } + } } else { imports.add(genImport(component.filePath, [{ name: component._raw ? 'default' : component.export, as: identifier }])) From 2ac90f37b6264d0e93b1d603ebf3af01e0184659 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 14:20:58 +0000 Subject: [PATCH 077/123] [autofix.ci] apply automated fixes --- packages/nuxt/src/components/loader.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index 92052bb544f9..e330fc983a37 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -74,28 +74,26 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { if (lazy) { if (modifier) { switch (modifier) { - case "Visible": - case "visible-": + case 'Visible': + case 'visible-': imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) identifier += '_delayedIO' imports.add(`const ${identifier} = createLazyIOClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)))`) - break; - case "Idle": - case "idle-": + break + case 'Idle': + case 'idle-': imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyNetworkClientPage' }])) identifier += '_delayedNetwork' imports.add(`const ${identifier} = createLazyNetworkClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)))`) - break; + break } - - } - else { + } else { imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) identifier += '_lazy' imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`) - } + } } else { imports.add(genImport(component.filePath, [{ name: component._raw ? 'default' : component.export, as: identifier }])) From f5937803f81216cc26cfa5c578e05ca3a6d592a9 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 21:51:05 +0300 Subject: [PATCH 078/123] chore: rename component --- ...elayedWrapperTestComponent.vue => DelayedHydration.client.vue} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/fixtures/basic/components/{DelayedWrapperTestComponent.vue => DelayedHydration.client.vue} (100%) diff --git a/test/fixtures/basic/components/DelayedWrapperTestComponent.vue b/test/fixtures/basic/components/DelayedHydration.client.vue similarity index 100% rename from test/fixtures/basic/components/DelayedWrapperTestComponent.vue rename to test/fixtures/basic/components/DelayedHydration.client.vue From 6f806878fdf44768770cb252a68104ea153343d3 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 21:51:33 +0300 Subject: [PATCH 079/123] Create DelayedHydration.server.vue --- test/fixtures/basic/components/DelayedHydration.server.vue | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test/fixtures/basic/components/DelayedHydration.server.vue diff --git a/test/fixtures/basic/components/DelayedHydration.server.vue b/test/fixtures/basic/components/DelayedHydration.server.vue new file mode 100644 index 000000000000..8030f660795c --- /dev/null +++ b/test/fixtures/basic/components/DelayedHydration.server.vue @@ -0,0 +1,5 @@ + From b143038cefbc7623fe31bbac3e335d0a6d0c0f2d Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 21:55:58 +0300 Subject: [PATCH 080/123] fix: change name --- test/fixtures/basic/pages/lazy-import-components/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/basic/pages/lazy-import-components/index.vue b/test/fixtures/basic/pages/lazy-import-components/index.vue index eafa6d837576..440ca5216df7 100644 --- a/test/fixtures/basic/pages/lazy-import-components/index.vue +++ b/test/fixtures/basic/pages/lazy-import-components/index.vue @@ -6,6 +6,6 @@
This is a very tall div
- + From b1c498bea70fddf49149c5dce0d5725db3ceeb05 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 21:56:49 +0300 Subject: [PATCH 081/123] test: named LazyVisible components --- test/basic.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 0fd2b6787d4d..3dd305d1c932 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2637,11 +2637,10 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') + expect(html).toContain('This should be visible at first!') const { page } = await renderPage('/lazy-import-components') - expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) - const response = page.waitForResponse(response => response.url().includes('DelayedWrapperTestComponent') && response.status() === 200) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) - await response + expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) }) }) From d04d244799d6390a2d6115868d63462cff574877 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 22:04:03 +0300 Subject: [PATCH 082/123] fix: remove line --- test/basic.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 3dd305d1c932..604be88e8a3b 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2637,7 +2637,6 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') - expect(html).toContain('This should be visible at first!') const { page } = await renderPage('/lazy-import-components') await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) From 41c4b53af7c25dd1807e64e3c0feb8d1c0b59ae0 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 22:33:25 +0300 Subject: [PATCH 083/123] chore: use new component --- test/fixtures/basic/pages/lazy-import-components/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/basic/pages/lazy-import-components/index.vue b/test/fixtures/basic/pages/lazy-import-components/index.vue index 440ca5216df7..347083a83e81 100644 --- a/test/fixtures/basic/pages/lazy-import-components/index.vue +++ b/test/fixtures/basic/pages/lazy-import-components/index.vue @@ -6,6 +6,6 @@
This is a very tall div
- + From 28647ecb300d87435570d8d50f405c0b90b05aff Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 23:24:40 +0300 Subject: [PATCH 084/123] chore: attempt to wait for network idle --- test/basic.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/basic.test.ts b/test/basic.test.ts index 604be88e8a3b..d9cd367b993e 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2639,6 +2639,8 @@ describe('lazy import components', () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) + expect(await page.locator('body').getByText('This should be visible at first!').all()).toHaveLength(1) + await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) }) }) From 66dd659821f0ebb84e97e90dd19ba9a3703b0954 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 23:40:37 +0300 Subject: [PATCH 085/123] fix: delayed hydration for network idle --- .../nuxt/src/components/runtime/client-delayed-component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 431aae4bb036..851ee38a6024 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -72,7 +72,7 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { const nuxt = useNuxtApp() const instance = getCurrentInstance()! let vnode: VNode | null = null - if (import.meta.client && nuxt.isHydrating && instance.vnode?.el) { + if (nuxt.isHydrating && instance.vnode?.el) { vnode = createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1) } const isIdle = ref(false) @@ -90,7 +90,7 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { idleHandle = null } }) - return () => isIdle.value ? h(componentLoader, attrs) : vnode + return () => isIdle.value ? h(componentLoader, attrs) : (instance.vnode.el && nuxt.isHydrating) ? createVNode(createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1)) : null }, }) } From 2a244f056fb22ce2ec8f32f7e3ad7af604ba21aa Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 23:43:29 +0300 Subject: [PATCH 086/123] chore: remove unused vnode --- .../nuxt/src/components/runtime/client-delayed-component.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 851ee38a6024..77a5bdd03786 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -71,10 +71,6 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { } const nuxt = useNuxtApp() const instance = getCurrentInstance()! - let vnode: VNode | null = null - if (nuxt.isHydrating && instance.vnode?.el) { - vnode = createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1) - } const isIdle = ref(false) let idleHandle: number | null = null onMounted(() => { From 5051c861b191563e58998f8f96fdf81287a3df96 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 23:49:48 +0300 Subject: [PATCH 087/123] chore: remove VNode type --- .../nuxt/src/components/runtime/client-delayed-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 77a5bdd03786..67f1071d3f9d 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -1,5 +1,5 @@ import { createStaticVNode, createVNode, defineComponent, getCurrentInstance, h, onBeforeUnmount, onMounted, ref } from 'vue' -import type { Component, Ref, VNode } from 'vue' +import type { Component, Ref } from 'vue' // import ClientOnly from '#app/components/client-only' import { useObserver } from '#app/utils' import { getFragmentHTML } from '#app/components/utils' From 6d3ec1714bca4b64f3adf33f70414ca34c1ac244 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 2 Jun 2024 23:59:43 +0300 Subject: [PATCH 088/123] Update and rename DelayedHydration.client.vue to DelayedVisible.client.vue --- test/fixtures/basic/components/DelayedHydration.client.vue | 5 ----- test/fixtures/basic/components/DelayedVisible.client.vue | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 test/fixtures/basic/components/DelayedHydration.client.vue create mode 100644 test/fixtures/basic/components/DelayedVisible.client.vue diff --git a/test/fixtures/basic/components/DelayedHydration.client.vue b/test/fixtures/basic/components/DelayedHydration.client.vue deleted file mode 100644 index d42e68faf42c..000000000000 --- a/test/fixtures/basic/components/DelayedHydration.client.vue +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/test/fixtures/basic/components/DelayedVisible.client.vue b/test/fixtures/basic/components/DelayedVisible.client.vue new file mode 100644 index 000000000000..138d4fa96f0d --- /dev/null +++ b/test/fixtures/basic/components/DelayedVisible.client.vue @@ -0,0 +1,5 @@ + From 90fb0d590412ae47d274f94941e271886747ea30 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 00:00:08 +0300 Subject: [PATCH 089/123] Update and rename DelayedHydration.server.vue to DelayedVisible.server.vue --- test/fixtures/basic/components/DelayedHydration.server.vue | 5 ----- test/fixtures/basic/components/DelayedVisible.server.vue | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 test/fixtures/basic/components/DelayedHydration.server.vue create mode 100644 test/fixtures/basic/components/DelayedVisible.server.vue diff --git a/test/fixtures/basic/components/DelayedHydration.server.vue b/test/fixtures/basic/components/DelayedHydration.server.vue deleted file mode 100644 index 8030f660795c..000000000000 --- a/test/fixtures/basic/components/DelayedHydration.server.vue +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/test/fixtures/basic/components/DelayedVisible.server.vue b/test/fixtures/basic/components/DelayedVisible.server.vue new file mode 100644 index 000000000000..49f2e0262a0f --- /dev/null +++ b/test/fixtures/basic/components/DelayedVisible.server.vue @@ -0,0 +1,5 @@ + From a26603fafb18c24d991f69c17efb9d27c8860a68 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 00:00:54 +0300 Subject: [PATCH 090/123] Create DelayedNetwork.client.vue --- test/fixtures/basic/components/DelayedNetwork.client.vue | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test/fixtures/basic/components/DelayedNetwork.client.vue diff --git a/test/fixtures/basic/components/DelayedNetwork.client.vue b/test/fixtures/basic/components/DelayedNetwork.client.vue new file mode 100644 index 000000000000..c76f76b8d6d5 --- /dev/null +++ b/test/fixtures/basic/components/DelayedNetwork.client.vue @@ -0,0 +1,5 @@ + From d32cfdf09baac6884bfa5cf5fda2f51d4ef874aa Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 00:01:15 +0300 Subject: [PATCH 091/123] Create DelayedNetwork.server.vue --- test/fixtures/basic/components/DelayedNetwork.server.vue | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test/fixtures/basic/components/DelayedNetwork.server.vue diff --git a/test/fixtures/basic/components/DelayedNetwork.server.vue b/test/fixtures/basic/components/DelayedNetwork.server.vue new file mode 100644 index 000000000000..65192055eafa --- /dev/null +++ b/test/fixtures/basic/components/DelayedNetwork.server.vue @@ -0,0 +1,5 @@ + From f4f8ca08dcf9ee6ead5824656d702daba53c6397 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 00:02:31 +0300 Subject: [PATCH 092/123] chore: add network idle component --- test/fixtures/basic/pages/lazy-import-components/index.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/fixtures/basic/pages/lazy-import-components/index.vue b/test/fixtures/basic/pages/lazy-import-components/index.vue index 347083a83e81..797f01870049 100644 --- a/test/fixtures/basic/pages/lazy-import-components/index.vue +++ b/test/fixtures/basic/pages/lazy-import-components/index.vue @@ -3,9 +3,10 @@ +
This is a very tall div
- + From 9746137b28230a1801cb21614a3317406d20e8e6 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 00:04:43 +0300 Subject: [PATCH 093/123] test: add network idle test --- test/basic.test.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index d9cd367b993e..61f0fb19c286 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2638,10 +2638,15 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') + expect(await page.locator('body').getByText('This should 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(0) + await page.waitForLoadState('networkidle') + expect(await page.locator('body').getByText('This should be visible at first with network!').all()).toHaveLength(0) + expect(await page.locator('body').getByText('This shouldn\'t be visible at first with network!').all()).toHaveLength(1) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) - expect(await page.locator('body').getByText('This should be visible at first!').all()).toHaveLength(1) + expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(1) await page.waitForLoadState('networkidle') - expect(await page.locator('body').getByText('This shouldn\'t be visible at first!').all()).toHaveLength(1) + expect(await page.locator('body').getByText('This shouldn\'t be visible at first with viewport!').all()).toHaveLength(1) }) }) From 046c1ce85fa705b7af27199d19c0e560d4769e0c Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 00:27:40 +0300 Subject: [PATCH 094/123] chore: attempt to redo component From 502383feea9149d72e5d19d7a0ed60dba5a5d8d7 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 00:38:58 +0300 Subject: [PATCH 095/123] chore: attempt to remove the pre-idle checks --- test/basic.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 61f0fb19c286..ba058f0ab0b1 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2638,8 +2638,8 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') - expect(await page.locator('body').getByText('This should 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(0) + //expect(await page.locator('body').getByText('This should 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(0) await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This should be visible at first with network!').all()).toHaveLength(0) expect(await page.locator('body').getByText('This shouldn\'t be visible at first with network!').all()).toHaveLength(1) From a0f43b45f21ae20bdbae13f5410c3941bb267aee Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 21:41:22 +0000 Subject: [PATCH 096/123] [autofix.ci] apply automated fixes --- test/basic.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index ba058f0ab0b1..50d53e17fb30 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2638,8 +2638,8 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') - //expect(await page.locator('body').getByText('This should 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(0) + // expect(await page.locator('body').getByText('This should 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(0) await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This should be visible at first with network!').all()).toHaveLength(0) expect(await page.locator('body').getByText('This shouldn\'t be visible at first with network!').all()).toHaveLength(1) From 440f4cc91a16807533d88698f22ad45a418c7682 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 00:55:28 +0300 Subject: [PATCH 097/123] chore: temporarily remove network component --- test/basic.test.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 50d53e17fb30..d57bbba7743c 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2638,11 +2638,6 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') - // expect(await page.locator('body').getByText('This should 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(0) - await page.waitForLoadState('networkidle') - expect(await page.locator('body').getByText('This should be visible at first with network!').all()).toHaveLength(0) - expect(await page.locator('body').getByText('This shouldn\'t be visible at first with network!').all()).toHaveLength(1) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(1) await page.waitForLoadState('networkidle') From ea0dea2a49c443ef177018345163f0685e0acab9 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 00:59:53 +0300 Subject: [PATCH 098/123] chore: rerun tests From a53c5897a179534988465738f296b16e3cac21b5 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 09:35:49 +0300 Subject: [PATCH 099/123] docs: add docs for delayed hydration --- .../2.directory-structure/1.components.md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/2.guide/2.directory-structure/1.components.md b/docs/2.guide/2.directory-structure/1.components.md index 0cdf5cb4b651..1fb9a3502677 100644 --- a/docs/2.guide/2.directory-structure/1.components.md +++ b/docs/2.guide/2.directory-structure/1.components.md @@ -119,6 +119,37 @@ const show = ref(false) ``` +## Delayed Hydration + +In real world applications, some pages may include a lot of content and a lot of components, and most of the time not all of them need to be interactive right off the bat. Having them all load eagerly can negatively impact performance and bundle size. + +In order to optimize the page, you may want to delay the hydration of some components until they're visible, or until the browser is done with more important tasks for example. Nuxt has first class support for delayed hydration components and can help you reduce your boilerplate along the way. + +Nuxt has reserved component prefixes that will handle this delayed hydration for you, that extend dynamic Imports. By prefixing your component with `LazyVisible`, Nuxt will automatically handle your component and delay its hydration until it will be on screen. + +```vue [pages/index.vue] + +``` + +If you need the component to load as soon as possible, but not block the critical rendering path, you can use the `LazyIdle` prefix, which would handle your component's hydration whenever the browser goes idle. + +```vue [pages/index.vue] + +``` + +::important +Since Nuxt uses `LazyIdle` and `LazyVisible` to handle delayed hydration, you should avoid naming your components that, as dynamic imports will break for you. Delayed Hydration would still be possible by adding the prefix, for example to a component named `IdleBar`: +`` +:: + ## Direct Imports You can also explicitly import components from `#components` if you want or need to bypass Nuxt's auto-importing functionality. From e0a2f219db21ce9df64be07d89baf0f816551060 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 06:36:24 +0000 Subject: [PATCH 100/123] [autofix.ci] apply automated fixes --- docs/2.guide/2.directory-structure/1.components.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/2.guide/2.directory-structure/1.components.md b/docs/2.guide/2.directory-structure/1.components.md index 1fb9a3502677..36f951ee69f8 100644 --- a/docs/2.guide/2.directory-structure/1.components.md +++ b/docs/2.guide/2.directory-structure/1.components.md @@ -119,9 +119,9 @@ const show = ref(false) ``` -## Delayed Hydration +## Delayed Hydration -In real world applications, some pages may include a lot of content and a lot of components, and most of the time not all of them need to be interactive right off the bat. Having them all load eagerly can negatively impact performance and bundle size. +In real world applications, some pages may include a lot of content and a lot of components, and most of the time not all of them need to be interactive right off the bat. Having them all load eagerly can negatively impact performance and bundle size. In order to optimize the page, you may want to delay the hydration of some components until they're visible, or until the browser is done with more important tasks for example. Nuxt has first class support for delayed hydration components and can help you reduce your boilerplate along the way. From 2f2cb8e0cf1a171282b16c5a5112edeed814f0ef Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 10:22:52 +0300 Subject: [PATCH 101/123] fix: only enable delayed hydration with the experimental flag --- packages/nuxt/src/components/loader.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index e330fc983a37..8b218cacf05d 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -41,13 +41,13 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { const imports = new Set() const map = new Map() const s = new MagicString(code) - + const nuxt = tryUseNuxt() // replace `_resolveComponent("...")` to direct import s.replace(/(?<=[ (])_?resolveComponent\(\s*["'](lazy-|Lazy)?(Idle|Visible|idle-|visible-)?([^'"]*)["'][^)]*\)/g, (full: string, lazy: string, modifier: string, name: string) => { const component = findComponent(components, name, options.mode) if (component) { // @ts-expect-error TODO: refactor to nuxi - if (component._internal_install && tryUseNuxt()?.options.test === false) { + if (component._internal_install && nuxt?.options.test === false) { // @ts-expect-error TODO: refactor to nuxi import('../core/features').then(({ installNuxtModule }) => installNuxtModule(component._internal_install)) } @@ -72,7 +72,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { } if (lazy) { - if (modifier) { + if (nuxt?.options.experimental.componentLazyHydration === true && modifier) { switch (modifier) { case 'Visible': case 'visible-': From b764ae93be200a428acd63b7936a08cdfa85a0fc Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 3 Jun 2024 10:39:14 +0300 Subject: [PATCH 102/123] fix: add componentLazyHydration --- test/fixtures/basic/nuxt.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/fixtures/basic/nuxt.config.ts b/test/fixtures/basic/nuxt.config.ts index d312d55944b0..a96ea889b347 100644 --- a/test/fixtures/basic/nuxt.config.ts +++ b/test/fixtures/basic/nuxt.config.ts @@ -238,6 +238,7 @@ export default defineNuxtConfig({ renderJsonPayloads: process.env.TEST_PAYLOAD !== 'js', headNext: true, inlineRouteRules: true, + componentLazyHydration: true }, appConfig: { fromNuxtConfig: true, From 4eb39d10626be50c58acf1e96d5dd058d48815e5 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 07:41:35 +0000 Subject: [PATCH 103/123] [autofix.ci] apply automated fixes --- test/fixtures/basic/nuxt.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/basic/nuxt.config.ts b/test/fixtures/basic/nuxt.config.ts index a96ea889b347..beda5b9fcbb7 100644 --- a/test/fixtures/basic/nuxt.config.ts +++ b/test/fixtures/basic/nuxt.config.ts @@ -238,7 +238,7 @@ export default defineNuxtConfig({ renderJsonPayloads: process.env.TEST_PAYLOAD !== 'js', headNext: true, inlineRouteRules: true, - componentLazyHydration: true + componentLazyHydration: true, }, appConfig: { fromNuxtConfig: true, From b87a70c825837a205f13df3bfee2c8af996f7881 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 9 Jun 2024 21:07:39 +0300 Subject: [PATCH 104/123] chore: attempt a higher div --- test/fixtures/basic/pages/lazy-import-components/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/basic/pages/lazy-import-components/index.vue b/test/fixtures/basic/pages/lazy-import-components/index.vue index 797f01870049..ef64df44e63b 100644 --- a/test/fixtures/basic/pages/lazy-import-components/index.vue +++ b/test/fixtures/basic/pages/lazy-import-components/index.vue @@ -4,7 +4,7 @@ -
+
This is a very tall div
From ee7d8fa20e691b67ec8ecb6fd973a7064635d288 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 9 Jun 2024 22:25:06 +0300 Subject: [PATCH 105/123] fix: evaluate scroll after initial check --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index ef6a80a3cc6b..78f54165ae17 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2639,8 +2639,8 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') - await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(1) + await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This shouldn\'t be visible at first with viewport!').all()).toHaveLength(1) }) From b9e735424152a7e2d0b70cd5068e1f59f13b6995 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 9 Jun 2024 23:05:34 +0300 Subject: [PATCH 106/123] chore: fix network comp display --- .../nuxt/src/components/runtime/client-delayed-component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index 67f1071d3f9d..a5c1a918c836 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -86,7 +86,9 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { idleHandle = null } }) - return () => isIdle.value ? h(componentLoader, attrs) : (instance.vnode.el && nuxt.isHydrating) ? createVNode(createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1)) : null + return () => h('div', {}, [ + isIdle.value ? h(componentLoader, attrs) : (instance.vnode.el && nuxt.isHydrating) ? createVNode(createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1)) : null + ]) }, }) } From 79a805fa8cad5f31929a3507e5e178deba44057d Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 9 Jun 2024 20:08:02 +0000 Subject: [PATCH 107/123] [autofix.ci] apply automated fixes --- .../nuxt/src/components/runtime/client-delayed-component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-delayed-component.ts b/packages/nuxt/src/components/runtime/client-delayed-component.ts index a5c1a918c836..016ba8de1afb 100644 --- a/packages/nuxt/src/components/runtime/client-delayed-component.ts +++ b/packages/nuxt/src/components/runtime/client-delayed-component.ts @@ -86,8 +86,8 @@ export const createLazyNetworkClientPage = (componentLoader: Component) => { idleHandle = null } }) - return () => h('div', {}, [ - isIdle.value ? h(componentLoader, attrs) : (instance.vnode.el && nuxt.isHydrating) ? createVNode(createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1)) : null + return () => h('div', {}, [ + isIdle.value ? h(componentLoader, attrs) : (instance.vnode.el && nuxt.isHydrating) ? createVNode(createStaticVNode(getFragmentHTML(instance.vnode.el ?? null, true)?.join('') || '', 1)) : null, ]) }, }) From 53d73baa483cafb4adb8c159f5fb7d6cfa32386b Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 9 Jun 2024 23:34:04 +0300 Subject: [PATCH 108/123] test: attempt network idle test --- test/basic.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/basic.test.ts b/test/basic.test.ts index 78f54165ae17..01d5df3aed39 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2639,7 +2639,10 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') + expect(await page.locator('body').getByText('This should 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) + await page.waitForLoadState('networkidle') + expect(await page.locator('body').getByText('This should be visible at first with network!').all()).toHaveLength(0) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This shouldn\'t be visible at first with viewport!').all()).toHaveLength(1) From c8cbcfc56e7b9eb06efe6db2b56f3eb53d0803c9 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 9 Jun 2024 23:36:04 +0300 Subject: [PATCH 109/123] chore: use Promise.all to try and be faster than initial idle time --- test/basic.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 01d5df3aed39..431ad4fe7302 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2639,8 +2639,12 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') - expect(await page.locator('body').getByText('This should 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) + const [allNetwork, allViewport] = await Promise.all([ + page.locator('body').getByText('This should be visible at first with network!').all(), + page.locator('body').getByText('This should be visible at first with viewport!').all(), + ]) + expect(allNetwork).toHaveLength(1) + expect(allViewport).toHaveLength(1) await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This should be visible at first with network!').all()).toHaveLength(0) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) From b0f4f64d271f3c6648786cbb0680e7915bafa055 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 9 Jun 2024 23:43:41 +0300 Subject: [PATCH 110/123] chore: retry without promise.all --- test/basic.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 431ad4fe7302..01d5df3aed39 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2639,12 +2639,8 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).not.toContain('This shouldn\'t be visible at first!') const { page } = await renderPage('/lazy-import-components') - const [allNetwork, allViewport] = await Promise.all([ - page.locator('body').getByText('This should be visible at first with network!').all(), - page.locator('body').getByText('This should be visible at first with viewport!').all(), - ]) - expect(allNetwork).toHaveLength(1) - expect(allViewport).toHaveLength(1) + expect(await page.locator('body').getByText('This should 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) await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This should be visible at first with network!').all()).toHaveLength(0) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) From ed16dc4a7df9acf22d912d8691b8bbf92d40fa53 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Sun, 9 Jun 2024 23:45:22 +0300 Subject: [PATCH 111/123] chore: extract import --- packages/nuxt/src/components/loader.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index 8b218cacf05d..b65385f3e959 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -72,25 +72,23 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { } if (lazy) { + imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) if (nuxt?.options.experimental.componentLazyHydration === true && modifier) { switch (modifier) { case 'Visible': case 'visible-': - imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOClientPage' }])) identifier += '_delayedIO' imports.add(`const ${identifier} = createLazyIOClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)))`) break case 'Idle': case 'idle-': - imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyNetworkClientPage' }])) identifier += '_delayedNetwork' imports.add(`const ${identifier} = createLazyNetworkClientPage(__defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)))`) break } } else { - imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }])) identifier += '_lazy' imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`) } From 53c8bb92fef116718379d896828c8ba2f99769bb Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 10 Jun 2024 00:20:49 +0300 Subject: [PATCH 112/123] chore: attempt to check through html --- test/basic.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 01d5df3aed39..1beb9f6ad282 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2637,7 +2637,7 @@ describe('lazy import components', () => { }) it('lazy load delayed hydration comps at the right time', async () => { - expect(html).not.toContain('This shouldn\'t be visible at first!') + expect(html).toContain('This should be visible at first with network!') const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This should 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) From 2b765e0b8838e275197d31739ec19f5eea214ec0 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 10 Jun 2024 00:30:13 +0300 Subject: [PATCH 113/123] chore: refactor the test --- test/basic.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 1beb9f6ad282..32e66164f251 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2639,12 +2639,13 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).toContain('This should be visible at first with network!') const { page } = await renderPage('/lazy-import-components') - expect(await page.locator('body').getByText('This should 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) await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This should be visible at first with network!').all()).toHaveLength(0) + expect(await page.locator('body').getByText('This shouldn\'t be visible at first with network!').all()).toHaveLength(1) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await page.waitForLoadState('networkidle') + expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(0) expect(await page.locator('body').getByText('This shouldn\'t be visible at first with viewport!').all()).toHaveLength(1) }) }) From 1039735d458e73cb79e8a8d6e516b473c8746dbb Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 10 Jun 2024 00:41:55 +0300 Subject: [PATCH 114/123] chore: await another networkidle --- test/basic.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/basic.test.ts b/test/basic.test.ts index 32e66164f251..e15b62df4270 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2646,6 +2646,7 @@ describe('lazy import components', () => { await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(0) + await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This shouldn\'t be visible at first with viewport!').all()).toHaveLength(1) }) }) From 7ad6b06809bec571105db3535a5672ad81e4d1e3 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 10 Jun 2024 00:45:03 +0300 Subject: [PATCH 115/123] chore: retry tests From 2089f745a81944a38bf52874e00946b1be0c8c99 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 10 Jun 2024 10:29:32 +0300 Subject: [PATCH 116/123] test: refactor test --- test/basic.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index e15b62df4270..ea49fff6e932 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2641,12 +2641,9 @@ describe('lazy import components', () => { const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(1) await page.waitForLoadState('networkidle') - expect(await page.locator('body').getByText('This should be visible at first with network!').all()).toHaveLength(0) expect(await page.locator('body').getByText('This shouldn\'t be visible at first with network!').all()).toHaveLength(1) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await page.waitForLoadState('networkidle') - expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(0) - await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This shouldn\'t be visible at first with viewport!').all()).toHaveLength(1) }) }) From 09f341c3ef605b1fb4b206305604e7f552d87b68 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 10 Jun 2024 10:41:49 +0300 Subject: [PATCH 117/123] chore: revert test page --- test/fixtures/basic/pages/lazy-import-components/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/basic/pages/lazy-import-components/index.vue b/test/fixtures/basic/pages/lazy-import-components/index.vue index ef64df44e63b..797f01870049 100644 --- a/test/fixtures/basic/pages/lazy-import-components/index.vue +++ b/test/fixtures/basic/pages/lazy-import-components/index.vue @@ -4,7 +4,7 @@ -
+
This is a very tall div
From fb3397701e0217a0ee90d31ecafb03c36c543427 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 10 Jun 2024 11:24:16 +0300 Subject: [PATCH 118/123] chore: revert test --- test/basic.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index ea49fff6e932..a5432c760da8 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2640,8 +2640,6 @@ describe('lazy import components', () => { expect(html).toContain('This should be visible at first with network!') const { page } = await renderPage('/lazy-import-components') expect(await page.locator('body').getByText('This should be visible at first with viewport!').all()).toHaveLength(1) - await page.waitForLoadState('networkidle') - expect(await page.locator('body').getByText('This shouldn\'t be visible at first with network!').all()).toHaveLength(1) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await page.waitForLoadState('networkidle') expect(await page.locator('body').getByText('This shouldn\'t be visible at first with viewport!').all()).toHaveLength(1) From 0792f95b86c53cce60bc5ac95f3b503ba10357cb Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 10 Jun 2024 11:41:33 +0300 Subject: [PATCH 119/123] chore: retry network evaluation --- test/basic.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/basic.test.ts b/test/basic.test.ts index a5432c760da8..14b76bc235d6 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2639,6 +2639,8 @@ describe('lazy import components', () => { it('lazy load delayed hydration comps at the right time', async () => { expect(html).toContain('This should be visible at first with network!') const { page } = await renderPage('/lazy-import-components') + await page.waitForLoadState('networkidle') + 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) await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)) await page.waitForLoadState('networkidle') From 6be28279f1121c5d9a14eaab03768e96bae18664 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Mon, 10 Jun 2024 11:56:41 +0300 Subject: [PATCH 120/123] docs: fix case --- docs/2.guide/2.directory-structure/1.components.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/2.guide/2.directory-structure/1.components.md b/docs/2.guide/2.directory-structure/1.components.md index 36f951ee69f8..331b2547744a 100644 --- a/docs/2.guide/2.directory-structure/1.components.md +++ b/docs/2.guide/2.directory-structure/1.components.md @@ -121,11 +121,11 @@ const show = ref(false) ## Delayed Hydration -In real world applications, some pages may include a lot of content and a lot of components, and most of the time not all of them need to be interactive right off the bat. Having them all load eagerly can negatively impact performance and bundle size. +In real world applications, some pages may include a lot of content and a lot of components, and most of the time not all of them need to be interactive as soon as the page is loaded. Having them all load eagerly can negatively impact performance and increase bundle size. In order to optimize the page, you may want to delay the hydration of some components until they're visible, or until the browser is done with more important tasks for example. Nuxt has first class support for delayed hydration components and can help you reduce your boilerplate along the way. -Nuxt has reserved component prefixes that will handle this delayed hydration for you, that extend dynamic Imports. By prefixing your component with `LazyVisible`, Nuxt will automatically handle your component and delay its hydration until it will be on screen. +Nuxt has reserved component prefixes that will handle this delayed hydration for you, that extend dynamic imports. By prefixing your component with `LazyVisible`, Nuxt will automatically handle your component and delay its hydration until it will be on screen. ```vue [pages/index.vue]