fix(nuxt): use route key for loading indicator/view transition (#23868)

This commit is contained in:
Julien Huang 2023-10-27 16:32:09 +02:00 committed by GitHub
parent a13bf67ecb
commit df022a4a9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 2 deletions

View File

@ -1,4 +1,5 @@
import { computed, defineComponent, h, onBeforeUnmount, ref } from 'vue' import { computed, defineComponent, h, onBeforeUnmount, ref } from 'vue'
import { isChangingPage } from './utils'
import { useNuxtApp } from '#app/nuxt' import { useNuxtApp } from '#app/nuxt'
import { useRouter } from '#app/composables/router' import { useRouter } from '#app/composables/router'
@ -42,7 +43,7 @@ export default defineComponent({
indicator.finish() indicator.finish()
}) })
router.beforeResolve((to, from) => { router.beforeResolve((to, from) => {
if (to === from || to.matched.every((comp, index) => comp.components && comp.components?.default === from.matched[index]?.components?.default)) { if (!isChangingPage(to, from)) {
indicator.finish() indicator.finish()
} }
}) })

View File

@ -3,6 +3,7 @@ import type { Component, RendererNode } from 'vue'
// eslint-disable-next-line // eslint-disable-next-line
import { isString, isPromise, isArray, isObject } from '@vue/shared' import { isString, isPromise, isArray, isObject } from '@vue/shared'
import destr from 'destr' import destr from 'destr'
import type { RouteLocationNormalized } from '#vue-router'
/** /**
* Internal utility * Internal utility
@ -13,6 +14,35 @@ export const _wrapIf = (component: Component, props: any, slots: any) => {
return { default: () => props ? h(component, props, slots) : slots.default?.() } return { default: () => props ? h(component, props, slots) : slots.default?.() }
} }
// TODO: consider refactoring into single utility
// See https://github.com/nuxt/nuxt/tree/main/packages/nuxt/src/pages/runtime/utils.ts#L8-L19
function generateRouteKey (route: RouteLocationNormalized) {
const source = route?.meta.key ?? route.path
.replace(/(:\w+)\([^)]+\)/g, '$1')
.replace(/(:\w+)[?+*]/g, '$1')
.replace(/:\w+/g, r => route.params[r.slice(1)]?.toString() || '')
return typeof source === 'function' ? source(route) : source
}
/**
* Utility used within router guards
* return true if the route has been changed with a page change during navigation
*/
export function isChangingPage (to: RouteLocationNormalized, from: RouteLocationNormalized) {
if (to === from) { return false }
// If route keys are different then it will result in a rerender
if (generateRouteKey(to) !== generateRouteKey(from)) { return true }
const areComponentsSame = to.matched.every((comp, index) =>
comp.components && comp.components.default === from.matched[index]?.components?.default
)
if (areComponentsSame) {
return false
}
return true
}
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
export type SSRBuffer = SSRBufferItem[] & { hasAsync?: boolean } export type SSRBuffer = SSRBufferItem[] & { hasAsync?: boolean }
export type SSRBufferItem = string | SSRBuffer | Promise<SSRBuffer> export type SSRBufferItem = string | SSRBuffer | Promise<SSRBuffer>

View File

@ -1,3 +1,4 @@
import { isChangingPage } from '#app/components/utils'
import { useRouter } from '#app/composables/router' import { useRouter } from '#app/composables/router'
import { defineNuxtPlugin } from '#app/nuxt' import { defineNuxtPlugin } from '#app/nuxt'
@ -10,7 +11,7 @@ export default defineNuxtPlugin((nuxtApp) => {
const router = useRouter() const router = useRouter()
router.beforeResolve((to, from) => { router.beforeResolve((to, from) => {
if (to === from || to.matched.every((comp, index) => comp.components && comp.components?.default === from.matched[index]?.components?.default)) { if (!isChangingPage(to, from)) {
return return
} }
const promise = new Promise<void>((resolve, reject) => { const promise = new Promise<void>((resolve, reject) => {