From d5cf7080417deacdc17dbd62eb12b532fb8be45e Mon Sep 17 00:00:00 2001 From: Peter Buglavecz Date: Sun, 15 Sep 2024 16:45:03 +0200 Subject: [PATCH 01/11] fix(nuxt): hook called twice during navigation --- packages/nuxt/src/pages/runtime/page.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/nuxt/src/pages/runtime/page.ts b/packages/nuxt/src/pages/runtime/page.ts index 5ba304cd23..f9284173a2 100644 --- a/packages/nuxt/src/pages/runtime/page.ts +++ b/packages/nuxt/src/pages/runtime/page.ts @@ -41,7 +41,6 @@ export default defineComponent({ const nuxtApp = useNuxtApp() const pageRef = ref() const forkRoute = inject(PageRouteSymbol, null) - let previousPageKey: string | undefined | false expose({ pageRef }) @@ -97,10 +96,6 @@ export default defineComponent({ } const key = generateRouteKey(routeProps, props.pageKey) - if (!nuxtApp.isHydrating && !hasChildrenRoutes(forkRoute, routeProps.route, routeProps.Component) && previousPageKey === key) { - nuxtApp.callHook('page:loading:end') - } - previousPageKey = key const hasTransition = !!(props.transition ?? routeProps.route.meta.pageTransition ?? defaultPageTransition) const transitionProps = hasTransition && _mergeTransitionProps([ @@ -161,10 +156,3 @@ function haveParentRoutesRendered (fork: RouteLocationNormalizedLoaded | null, n (c, i) => c.components?.default !== fork.matched[i]?.components?.default) || (Component && generateRouteKey({ route: newRoute, Component }) !== generateRouteKey({ route: fork, Component })) } - -function hasChildrenRoutes (fork: RouteLocationNormalizedLoaded | null, newRoute: RouteLocationNormalizedLoaded, Component?: VNode) { - if (!fork) { return false } - - const index = newRoute.matched.findIndex(m => m.components?.default === Component?.type) - return index < newRoute.matched.length - 1 -} From b99d5660e456e1b726237b6028db90e352d13bb7 Mon Sep 17 00:00:00 2001 From: Peter Buglavecz Date: Thu, 10 Oct 2024 21:43:14 +0200 Subject: [PATCH 02/11] add unit test --- test/basic.test.ts | 12 ++++++++++++ test/fixtures/basic/pages/page-load-hook.vue | 5 +++++ test/fixtures/basic/plugins/page-hook-plugin.ts | 5 +++++ 3 files changed, 22 insertions(+) create mode 100644 test/fixtures/basic/pages/page-load-hook.vue create mode 100644 test/fixtures/basic/plugins/page-hook-plugin.ts diff --git a/test/basic.test.ts b/test/basic.test.ts index 01a135223e..b76cb2ea79 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -2845,3 +2845,15 @@ describe('namespace access to useNuxtApp', () => { await page.close() }) }) + +describe('page hook', () => { + it('should trigger page:loading:end only once', async () => { + const { page, consoleLogs } = await renderPage() + await page.goto(url('/page-load-hook')) + await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/page-load-hook') + const loadingEndLogs = consoleLogs.filter(c => c.text.includes('page:loading:end')) + expect(loadingEndLogs.length).toBe(1) + + await page.close() + }) +}) diff --git a/test/fixtures/basic/pages/page-load-hook.vue b/test/fixtures/basic/pages/page-load-hook.vue new file mode 100644 index 0000000000..49b858b0b8 --- /dev/null +++ b/test/fixtures/basic/pages/page-load-hook.vue @@ -0,0 +1,5 @@ + diff --git a/test/fixtures/basic/plugins/page-hook-plugin.ts b/test/fixtures/basic/plugins/page-hook-plugin.ts new file mode 100644 index 0000000000..5c1e4ad528 --- /dev/null +++ b/test/fixtures/basic/plugins/page-hook-plugin.ts @@ -0,0 +1,5 @@ +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.hook('page:loading:end', () => { + console.log('page:loading:end'); + }); +}); From 390f88bdf66667cabb20227a2cd149eb96cf93f5 Mon Sep 17 00:00:00 2001 From: Peter Buglavecz Date: Thu, 10 Oct 2024 21:49:47 +0200 Subject: [PATCH 03/11] eslint fix --- test/fixtures/basic/plugins/page-hook-plugin.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/fixtures/basic/plugins/page-hook-plugin.ts b/test/fixtures/basic/plugins/page-hook-plugin.ts index 5c1e4ad528..28f8a45518 100644 --- a/test/fixtures/basic/plugins/page-hook-plugin.ts +++ b/test/fixtures/basic/plugins/page-hook-plugin.ts @@ -1,5 +1,5 @@ export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('page:loading:end', () => { - console.log('page:loading:end'); - }); -}); + console.log('page:loading:end') + }) +}) From 50255cb5c1b92edde79313bf242a4541a3aa0d4b Mon Sep 17 00:00:00 2001 From: Peter Buglavecz Date: Thu, 10 Oct 2024 22:08:55 +0200 Subject: [PATCH 04/11] fix test --- 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 b76cb2ea79..d32bbf8174 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -1582,7 +1582,7 @@ describe('nested suspense', () => { const first = start.match(/\/suspense\/(?a?sync)-(?\d)\/(?a?sync)-(?\d)\//)!.groups! const last = nav.match(/\/suspense\/(?a?sync)-(?\d)\/(?a?sync)-(?\d)\//)!.groups! - expect(consoleLogs.map(l => l.text).filter(i => !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ + expect(consoleLogs.map(l => l.text).filter(i => !i.includes('page:loading:end') && !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ // [first load] from parent `[${first.parentType}]`, ...first.parentType === 'async' ? ['[async] running async data'] : [], @@ -1624,7 +1624,7 @@ describe('nested suspense', () => { await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, nav) - expect(consoleLogs.map(l => l.text).filter(i => !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ + expect(consoleLogs.map(l => l.text).filter(i => !i.includes('page:loading:end') && !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ // [first load] from parent `[${first.parentType}]`, ...first.parentType === 'async' ? ['[async] running async data'] : [], @@ -1660,7 +1660,7 @@ describe('nested suspense', () => { const first = start.match(/\/suspense\/(?a?sync)-(?\d)\//)!.groups! const last = nav.match(/\/suspense\/(?a?sync)-(?\d)\/(?a?sync)-(?\d)\//)!.groups! - expect(consoleLogs.map(l => l.text).filter(i => !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ + expect(consoleLogs.map(l => l.text).filter(i => !i.includes('page:loading:end') && !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ // [first load] from parent `[${first.parentType}]`, ...first.parentType === 'async' ? ['[async] running async data'] : [], From 2984d3f66a30805cdef527e0358eccb75835cb0e Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Fri, 11 Oct 2024 14:16:39 +0100 Subject: [PATCH 05/11] test: only log on `/page-load-hook` route --- test/basic.test.ts | 6 +++--- test/fixtures/basic/pages/index.vue | 3 +++ test/fixtures/basic/plugins/page-hook-plugin.ts | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 88638250c2..4cfe43fd71 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -1582,7 +1582,7 @@ describe('nested suspense', () => { const first = start.match(/\/suspense\/(?a?sync)-(?\d)\/(?a?sync)-(?\d)\//)!.groups! const last = nav.match(/\/suspense\/(?a?sync)-(?\d)\/(?a?sync)-(?\d)\//)!.groups! - expect(consoleLogs.map(l => l.text).filter(i => !i.includes('page:loading:end') && !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ + expect(consoleLogs.map(l => l.text).filter(i => !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ // [first load] from parent `[${first.parentType}]`, ...first.parentType === 'async' ? ['[async] running async data'] : [], @@ -1624,7 +1624,7 @@ describe('nested suspense', () => { await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, nav) - expect(consoleLogs.map(l => l.text).filter(i => !i.includes('page:loading:end') && !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ + expect(consoleLogs.map(l => l.text).filter(i => !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ // [first load] from parent `[${first.parentType}]`, ...first.parentType === 'async' ? ['[async] running async data'] : [], @@ -1660,7 +1660,7 @@ describe('nested suspense', () => { const first = start.match(/\/suspense\/(?a?sync)-(?\d)\//)!.groups! const last = nav.match(/\/suspense\/(?a?sync)-(?\d)\/(?a?sync)-(?\d)\//)!.groups! - expect(consoleLogs.map(l => l.text).filter(i => !i.includes('page:loading:end') && !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ + expect(consoleLogs.map(l => l.text).filter(i => !i.includes('[vite]') && !i.includes(' is an experimental feature')).sort()).toEqual([ // [first load] from parent `[${first.parentType}]`, ...first.parentType === 'async' ? ['[async] running async data'] : [], diff --git a/test/fixtures/basic/pages/index.vue b/test/fixtures/basic/pages/index.vue index d0fcd1513c..84edf9d105 100644 --- a/test/fixtures/basic/pages/index.vue +++ b/test/fixtures/basic/pages/index.vue @@ -94,6 +94,9 @@ to server page + + to page load hook + diff --git a/test/fixtures/basic/plugins/page-hook-plugin.ts b/test/fixtures/basic/plugins/page-hook-plugin.ts index 28f8a45518..880f7f1ac4 100644 --- a/test/fixtures/basic/plugins/page-hook-plugin.ts +++ b/test/fixtures/basic/plugins/page-hook-plugin.ts @@ -1,5 +1,8 @@ export default defineNuxtPlugin((nuxtApp) => { + const route = useRoute() nuxtApp.hook('page:loading:end', () => { - console.log('page:loading:end') + if (route.path === '/page-load-hook') { + console.log('page:loading:end') + } }) }) From 1edb8d2d7ac0bdeff859f088bf05b2545cc3dcb7 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Fri, 11 Oct 2024 14:17:01 +0100 Subject: [PATCH 06/11] test: trigger logging with client-side navigation --- test/basic.test.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 4cfe43fd71..42fdf957da 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -625,6 +625,17 @@ describe('pages', () => { const html = await $fetch('/prerender/test') expect(html).toContain('should be prerendered: true') }) + + it('should trigger page:loading:end only once', async () => { + const { page, consoleLogs } = await renderPage('/') + + await page.getByText('to page load hook').click() + await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/page-load-hook') + const loadingEndLogs = consoleLogs.filter(c => c.text.includes('page:loading:end')) + expect(loadingEndLogs.length).toBe(1) + + await page.close() + }) }) describe('nuxt composables', () => { @@ -2854,15 +2865,3 @@ describe('namespace access to useNuxtApp', () => { await page.close() }) }) - -describe('page hook', () => { - it('should trigger page:loading:end only once', async () => { - const { page, consoleLogs } = await renderPage() - await page.goto(url('/page-load-hook')) - await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/page-load-hook') - const loadingEndLogs = consoleLogs.filter(c => c.text.includes('page:loading:end')) - expect(loadingEndLogs.length).toBe(1) - - await page.close() - }) -}) From d4e2b44f4c9895f0bde920b681699a185414314d Mon Sep 17 00:00:00 2001 From: Peter Buglavecz Date: Sun, 17 Nov 2024 18:49:51 +0100 Subject: [PATCH 07/11] test: add nuxt page load indictor regression test --- test/basic.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/basic.test.ts b/test/basic.test.ts index e7219e7a29..27d611e428 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -636,8 +636,22 @@ describe('pages', () => { await page.close() }) + + it('should hide nuxt page load indicator after navigate back from nested page', async () => { + const LOAD_INDICATOR_SELECTOR = '.nuxt-loading-indicator' + const { page } = await renderPage('/') + await page.getByText('to page nuxt load indicator').click() + await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/nested/xyz') + await page.goBack() + await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/') + await page.waitForSelector(LOAD_INDICATOR_SELECTOR, { state: 'hidden' }) + const isVisible = await page.isVisible(LOAD_INDICATOR_SELECTOR) + expect(isVisible).toBe(false) + await page.close() + }) }) + describe('nuxt composables', () => { it('has useRequestURL()', async () => { const html = await $fetch('/url') From d218a835f30f2822f270e07d0fa5988451a5c9d5 Mon Sep 17 00:00:00 2001 From: Peter Buglavecz Date: Sun, 17 Nov 2024 18:51:52 +0100 Subject: [PATCH 08/11] test: add nuxt page load indictor regression test --- test/basic.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 27d611e428..f16c793e9f 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -651,7 +651,6 @@ describe('pages', () => { }) }) - describe('nuxt composables', () => { it('has useRequestURL()', async () => { const html = await $fetch('/url') From df749b9b5bf7d71e291930b637f9c7fbe9cb947a Mon Sep 17 00:00:00 2001 From: Peter Buglavecz Date: Sun, 17 Nov 2024 18:58:50 +0100 Subject: [PATCH 09/11] test: add fixture --- test/fixtures/basic/pages/index.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/fixtures/basic/pages/index.vue b/test/fixtures/basic/pages/index.vue index 84edf9d105..ebc61019c1 100644 --- a/test/fixtures/basic/pages/index.vue +++ b/test/fixtures/basic/pages/index.vue @@ -97,6 +97,9 @@ to page load hook + + to page nuxt load indicator + From 0646244a30e21c3a31007487ae68b5a5fcb5f19f Mon Sep 17 00:00:00 2001 From: Peter Buglavecz Date: Tue, 19 Nov 2024 16:24:38 +0100 Subject: [PATCH 10/11] fix: add nuxt load indicator to fixture --- test/basic.test.ts | 8 +++++++- test/fixtures/basic/pages/index.vue | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index f16c793e9f..7531e70d26 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -644,9 +644,15 @@ describe('pages', () => { await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/nested/xyz') await page.goBack() await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/') + + await page.waitForSelector(LOAD_INDICATOR_SELECTOR) + let isVisible = await page.isVisible(LOAD_INDICATOR_SELECTOR) + expect(isVisible).toBe(true) + await page.waitForSelector(LOAD_INDICATOR_SELECTOR, { state: 'hidden' }) - const isVisible = await page.isVisible(LOAD_INDICATOR_SELECTOR) + isVisible = await page.isVisible(LOAD_INDICATOR_SELECTOR) expect(isVisible).toBe(false) + await page.close() }) }) diff --git a/test/fixtures/basic/pages/index.vue b/test/fixtures/basic/pages/index.vue index ebc61019c1..45edab2b72 100644 --- a/test/fixtures/basic/pages/index.vue +++ b/test/fixtures/basic/pages/index.vue @@ -3,6 +3,7 @@ Basic fixture +

Hello Nuxt 3!

RuntimeConfig | testConfig: {{ config.public.testConfig }}
Composable | foo: {{ foo }}
From 23b1af766b20f8ae45f08563609529fb51164a48 Mon Sep 17 00:00:00 2001 From: Peter Buglavecz Date: Tue, 19 Nov 2024 16:29:17 +0100 Subject: [PATCH 11/11] fix: add nuxt load indicator to fixture --- test/basic.test.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/basic.test.ts b/test/basic.test.ts index 7531e70d26..e3102842ab 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -642,8 +642,6 @@ describe('pages', () => { const { page } = await renderPage('/') await page.getByText('to page nuxt load indicator').click() await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/nested/xyz') - await page.goBack() - await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/') await page.waitForSelector(LOAD_INDICATOR_SELECTOR) let isVisible = await page.isVisible(LOAD_INDICATOR_SELECTOR) @@ -653,6 +651,16 @@ describe('pages', () => { isVisible = await page.isVisible(LOAD_INDICATOR_SELECTOR) expect(isVisible).toBe(false) + await page.goBack() + + await page.waitForSelector(LOAD_INDICATOR_SELECTOR) + isVisible = await page.isVisible(LOAD_INDICATOR_SELECTOR) + expect(isVisible).toBe(true) + + await page.waitForSelector(LOAD_INDICATOR_SELECTOR, { state: 'hidden' }) + isVisible = await page.isVisible(LOAD_INDICATOR_SELECTOR) + expect(isVisible).toBe(false) + await page.close() }) })