2022-12-11 21:44:52 +00:00
|
|
|
import { computed, defineComponent, h, provide, reactive, onMounted, nextTick, Suspense, Transition } from 'vue'
|
2023-01-25 08:44:59 +00:00
|
|
|
import type { VNode, KeepAliveProps, TransitionProps } from 'vue'
|
2022-10-14 08:36:03 +00:00
|
|
|
import { RouterView } from 'vue-router'
|
2022-10-19 12:43:03 +00:00
|
|
|
import { defu } from 'defu'
|
2022-10-14 08:36:03 +00:00
|
|
|
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded, RouteLocation } from 'vue-router'
|
2022-01-25 14:32:09 +00:00
|
|
|
|
2022-12-11 21:44:52 +00:00
|
|
|
import type { RouterViewSlotProps } from './utils'
|
|
|
|
import { generateRouteKey, wrapInKeepAlive } from './utils'
|
2023-02-09 06:26:41 +00:00
|
|
|
import { useNuxtApp } from '#app/nuxt'
|
2022-03-14 10:47:24 +00:00
|
|
|
import { _wrapIf } from '#app/components/utils'
|
2022-08-23 14:24:20 +00:00
|
|
|
// @ts-ignore
|
|
|
|
import { appPageTransition as defaultPageTransition, appKeepalive as defaultKeepaliveConfig } from '#build/nuxt.config.mjs'
|
2022-01-25 14:32:09 +00:00
|
|
|
|
|
|
|
export default defineComponent({
|
|
|
|
name: 'NuxtPage',
|
2022-06-03 14:01:46 +00:00
|
|
|
inheritAttrs: false,
|
2022-02-07 11:32:04 +00:00
|
|
|
props: {
|
2022-06-03 14:01:46 +00:00
|
|
|
name: {
|
|
|
|
type: String
|
|
|
|
},
|
2022-09-14 10:34:16 +00:00
|
|
|
transition: {
|
|
|
|
type: [Boolean, Object] as any as () => boolean | TransitionProps,
|
|
|
|
default: undefined
|
|
|
|
},
|
|
|
|
keepalive: {
|
|
|
|
type: [Boolean, Object] as any as () => boolean | KeepAliveProps,
|
|
|
|
default: undefined
|
|
|
|
},
|
2022-06-03 14:01:46 +00:00
|
|
|
route: {
|
|
|
|
type: Object as () => RouteLocationNormalized
|
|
|
|
},
|
2022-02-07 11:32:04 +00:00
|
|
|
pageKey: {
|
|
|
|
type: [Function, String] as unknown as () => string | ((route: RouteLocationNormalizedLoaded) => string),
|
|
|
|
default: null
|
|
|
|
}
|
|
|
|
},
|
2022-06-03 14:01:46 +00:00
|
|
|
setup (props, { attrs }) {
|
2022-01-25 14:32:09 +00:00
|
|
|
const nuxtApp = useNuxtApp()
|
|
|
|
return () => {
|
2022-06-03 14:01:46 +00:00
|
|
|
return h(RouterView, { name: props.name, route: props.route, ...attrs }, {
|
2022-08-02 09:58:03 +00:00
|
|
|
default: (routeProps: RouterViewSlotProps) => {
|
|
|
|
if (!routeProps.Component) { return }
|
|
|
|
|
2022-11-21 13:03:22 +00:00
|
|
|
const key = generateRouteKey(routeProps, props.pageKey)
|
2022-10-08 14:18:57 +00:00
|
|
|
const done = nuxtApp.deferHydration()
|
|
|
|
|
2022-10-19 12:43:03 +00:00
|
|
|
const hasTransition = !!(props.transition ?? routeProps.route.meta.pageTransition ?? defaultPageTransition)
|
|
|
|
const transitionProps = hasTransition && _mergeTransitionProps([
|
|
|
|
props.transition,
|
|
|
|
routeProps.route.meta.pageTransition,
|
|
|
|
defaultPageTransition,
|
|
|
|
{ onAfterLeave: () => { nuxtApp.callHook('page:transition:finish', routeProps.Component) } }
|
|
|
|
].filter(Boolean))
|
|
|
|
|
|
|
|
return _wrapIf(Transition, hasTransition && transitionProps,
|
2022-10-08 14:18:57 +00:00
|
|
|
wrapInKeepAlive(props.keepalive ?? routeProps.route.meta.keepalive ?? (defaultKeepaliveConfig as KeepAliveProps), h(Suspense, {
|
|
|
|
onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
|
2022-10-19 12:43:03 +00:00
|
|
|
onResolve: () => { nextTick(() => nuxtApp.callHook('page:finish', routeProps.Component).finally(done)) }
|
2023-01-14 01:27:38 +00:00
|
|
|
}, { default: () => h(RouteProvider, { key, routeProps, pageKey: key, hasTransition } as {}) })
|
2022-08-02 09:58:03 +00:00
|
|
|
)).default()
|
|
|
|
}
|
2022-01-25 14:32:09 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-01-25 08:44:59 +00:00
|
|
|
})
|
2022-01-25 14:32:09 +00:00
|
|
|
|
2022-10-19 12:43:03 +00:00
|
|
|
function _toArray (val: any) {
|
|
|
|
return Array.isArray(val) ? val : (val ? [val] : [])
|
|
|
|
}
|
|
|
|
|
|
|
|
function _mergeTransitionProps (routeProps: TransitionProps[]): TransitionProps {
|
|
|
|
const _props: TransitionProps[] = routeProps.map(prop => ({
|
|
|
|
...prop,
|
|
|
|
onAfterLeave: _toArray(prop.onAfterLeave)
|
|
|
|
}))
|
|
|
|
// @ts-ignore
|
|
|
|
return defu(..._props)
|
|
|
|
}
|
|
|
|
|
2023-01-14 01:27:38 +00:00
|
|
|
const RouteProvider = defineComponent({
|
|
|
|
name: 'RouteProvider',
|
2022-08-12 17:47:58 +00:00
|
|
|
// TODO: Type props
|
2022-08-04 11:30:18 +00:00
|
|
|
// eslint-disable-next-line vue/require-prop-types
|
2022-08-23 10:25:48 +00:00
|
|
|
props: ['routeProps', 'pageKey', 'hasTransition'],
|
2022-08-03 10:38:46 +00:00
|
|
|
setup (props) {
|
2022-08-04 11:30:18 +00:00
|
|
|
// Prevent reactivity when the page will be rerendered in a different suspense fork
|
2022-08-31 18:34:17 +00:00
|
|
|
// eslint-disable-next-line vue/no-setup-props-destructure
|
2022-08-04 11:30:18 +00:00
|
|
|
const previousKey = props.pageKey
|
2022-08-31 18:34:17 +00:00
|
|
|
// eslint-disable-next-line vue/no-setup-props-destructure
|
2022-08-04 11:30:18 +00:00
|
|
|
const previousRoute = props.routeProps.route
|
|
|
|
|
|
|
|
// Provide a reactive route within the page
|
2022-08-12 17:47:58 +00:00
|
|
|
const route = {} as RouteLocation
|
2022-08-04 11:30:18 +00:00
|
|
|
for (const key in props.routeProps.route) {
|
2022-08-12 17:47:58 +00:00
|
|
|
(route as any)[key] = computed(() => previousKey === props.pageKey ? props.routeProps.route[key] : previousRoute[key])
|
2022-08-04 11:30:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
provide('_route', reactive(route))
|
2022-08-23 10:25:48 +00:00
|
|
|
|
|
|
|
let vnode: VNode
|
|
|
|
if (process.dev && process.client && props.hasTransition) {
|
|
|
|
onMounted(() => {
|
|
|
|
nextTick(() => {
|
|
|
|
if (['#comment', '#text'].includes(vnode?.el?.nodeName)) {
|
|
|
|
const filename = (vnode?.type as any).__file
|
|
|
|
console.warn(`[nuxt] \`${filename}\` does not have a single root node and will cause errors when navigating between routes.`)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
if (process.dev && process.client) {
|
|
|
|
vnode = h(props.routeProps.Component)
|
|
|
|
return vnode
|
|
|
|
}
|
|
|
|
|
|
|
|
return h(props.routeProps.Component)
|
|
|
|
}
|
2022-08-03 10:38:46 +00:00
|
|
|
}
|
|
|
|
})
|