fix(nuxt): separate routes for different suspense forks (#6275)

This commit is contained in:
Daniel Roe 2022-08-02 10:58:03 +01:00 committed by GitHub
parent b12fe7eb7c
commit c72093b1f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 28 deletions

View File

@ -6,14 +6,17 @@
</template> </template>
<script setup> <script setup>
import { defineAsyncComponent, onErrorCaptured } from 'vue' import { defineAsyncComponent, onErrorCaptured, provide } from 'vue'
import { callWithNuxt, isNuxtError, showError, useError, useNuxtApp } from '#app' import { callWithNuxt, isNuxtError, showError, useError, useRoute, useNuxtApp } from '#app'
const ErrorComponent = defineAsyncComponent(() => import('#build/error-component.mjs')) const ErrorComponent = defineAsyncComponent(() => import('#build/error-component.mjs'))
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
const onResolve = () => nuxtApp.callHook('app:suspense:resolve') const onResolve = () => nuxtApp.callHook('app:suspense:resolve')
// Inject default route (outside of pages) as active route
provide('_route', useRoute())
// vue:setup hook // vue:setup hook
const results = nuxtApp.hooks.callHookWith(hooks => hooks.map(hook => hook()), 'vue:setup') const results = nuxtApp.hooks.callHookWith(hooks => hooks.map(hook => hook()), 'vue:setup')
if (process.dev && results && results.some(i => i && 'then' in i)) { if (process.dev && results && results.some(i => i && 'then' in i)) {

View File

@ -1,3 +1,4 @@
import { getCurrentInstance, inject } from 'vue'
import type { Router, RouteLocationNormalizedLoaded, NavigationGuard, RouteLocationNormalized, RouteLocationRaw, NavigationFailure } from 'vue-router' import type { Router, RouteLocationNormalizedLoaded, NavigationGuard, RouteLocationNormalized, RouteLocationRaw, NavigationFailure } from 'vue-router'
import { sendRedirect } from 'h3' import { sendRedirect } from 'h3'
import { joinURL } from 'ufo' import { joinURL } from 'ufo'
@ -8,11 +9,15 @@ export const useRouter = () => {
} }
export const useRoute = () => { export const useRoute = () => {
return useNuxtApp()._route as RouteLocationNormalizedLoaded if (getCurrentInstance()) {
return inject<RouteLocationNormalizedLoaded>('_route', useNuxtApp()._route)
}
return useNuxtApp()._route
} }
/** @deprecated Use `useRoute` instead. */
export const useActiveRoute = () => { export const useActiveRoute = () => {
return useNuxtApp()._activeRoute as RouteLocationNormalizedLoaded return useNuxtApp()._route as RouteLocationNormalizedLoaded
} }
export interface RouteMiddleware { export interface RouteMiddleware {

View File

@ -30,17 +30,28 @@ export default defineComponent({
return () => { return () => {
return h(RouterView, { name: props.name, route: props.route, ...attrs }, { return h(RouterView, { name: props.name, route: props.route, ...attrs }, {
default: (routeProps: RouterViewSlotProps) => routeProps.Component && default: (routeProps: RouterViewSlotProps) => {
_wrapIf(Transition, routeProps.route.meta.pageTransition ?? defaultPageTransition, if (!routeProps.Component) { return }
wrapInKeepAlive(routeProps.route.meta.keepalive,
isNested && nuxtApp.isHydrating const Component = defineComponent({
setup () {
provide('_route', routeProps.route)
return () => h(routeProps.Component, {
key: generateRouteKey(props.pageKey, routeProps)
} as {})
}
})
return _wrapIf(Transition, routeProps.route.meta.pageTransition ?? defaultPageTransition,
wrapInKeepAlive(routeProps.route.meta.keepalive, isNested && nuxtApp.isHydrating
// Include route children in parent suspense // Include route children in parent suspense
? h(routeProps.Component, { key: generateRouteKey(props.pageKey, routeProps) } as {}) ? h(Component)
: h(Suspense, { : h(Suspense, {
onPending: () => nuxtApp.callHook('page:start', routeProps.Component), onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
onResolve: () => nuxtApp.callHook('page:finish', routeProps.Component) onResolve: () => nuxtApp.callHook('page:finish', routeProps.Component)
}, { default: () => h(routeProps.Component, { key: generateRouteKey(props.pageKey, routeProps) } as {}) }) }, { default: () => h(Component) })
)).default() )).default()
}
}) })
} }
} }

View File

@ -76,15 +76,9 @@ export default defineNuxtPlugin(async (nuxtApp) => {
get: () => previousRoute.value get: () => previousRoute.value
}) })
// https://github.com/vuejs/vue-router-next/blob/master/src/router.ts#L1192-L1200
const route = {}
for (const key in router.currentRoute.value) {
route[key] = computed(() => router.currentRoute.value[key])
}
// Allows suspending the route object until page navigation completes // Allows suspending the route object until page navigation completes
const _activeRoute = shallowRef(router.resolve(initialURL) as RouteLocation) const _route = shallowRef(router.resolve(initialURL) as RouteLocation)
const syncCurrentRoute = () => { _activeRoute.value = router.currentRoute.value } const syncCurrentRoute = () => { _route.value = router.currentRoute.value }
nuxtApp.hook('page:finish', syncCurrentRoute) nuxtApp.hook('page:finish', syncCurrentRoute)
router.afterEach((to, from) => { router.afterEach((to, from) => {
// We won't trigger suspense if the component is reused between routes // We won't trigger suspense if the component is reused between routes
@ -93,14 +87,14 @@ export default defineNuxtPlugin(async (nuxtApp) => {
syncCurrentRoute() syncCurrentRoute()
} }
}) })
// https://github.com/vuejs/vue-router-next/blob/master/src/router.ts#L1192-L1200
const activeRoute = {} // https://github.com/vuejs/router/blob/main/packages/router/src/router.ts#L1225-L1233
for (const key in _activeRoute.value) { const route = {}
activeRoute[key] = computed(() => _activeRoute.value[key]) for (const key in _route.value) {
route[key] = computed(() => _route.value[key])
} }
nuxtApp._route = reactive(route) nuxtApp._route = reactive(route)
nuxtApp._activeRoute = reactive(activeRoute)
nuxtApp._middleware = nuxtApp._middleware || { nuxtApp._middleware = nuxtApp._middleware || {
global: [], global: [],