-import { createRouter, createWebHistory } from '../../src'
+import { createRouter, createWebHistory, RouterViewSuspended } from '../../src'
import { createApp, defineComponent, onErrorCaptured } from 'vue'
const delay = (t: number) => new Promise(r => setTimeout(r, t))
template: `
<div>
<h1>With Data</h1>
+ <p>{{ $route.path }}</p>
<router-view/>
async setup() {
await delay(300)
- throw new Error('oops')
+ // throw new Error('oops')
return {}
},
<li><router-link to="/data-2/data">Suspended nested (2)</router-link></li>
</ul>
- <router-view-suspended />
+ <router-view />
</div>
`,
})
app.use(router)
+app.component('RouterView', RouterViewSuspended)
window.vm = app.mount('#app')
window.r = router
AllowedComponentProps,
ComponentCustomProps,
watch,
+ Suspense,
} from 'vue'
import {
RouteLocationNormalized,
import { assign } from './utils'
import { isSameRouteRecord } from './location'
-export interface RouterViewProps {
+export interface RouterViewSuspendedProps {
name?: string
// allow looser type for user facing api
route?: RouteLocationNormalized
}
export const RouterViewSuspendedImpl = /*#__PURE__*/ defineComponent({
- name: 'RouterView',
+ name: 'RouterViewSuspended',
// #674 we manually inherit them
inheritAttrs: false,
props: {
setup(props, { attrs }) {
const injectedRoute = inject(routerViewLocationKey)!
+ const isSuspended = inject('isSuspended', false as boolean)
+ // TODO: should be pending route -> after leave, update and global navigation guards
const suspendedRoute = inject(suspendedRouteKey)!
const routeToDisplay = computed(() => props.route || injectedRoute.value)
const depth = inject(viewDepthKey, 0)
const matchedRouteRef = computed<RouteLocationMatched | undefined>(
() => routeToDisplay.value.matched[depth]
)
+ const suspendedMatchedRouteRef = computed<
+ RouteLocationMatched | undefined | null
+ >(() => suspendedRoute.value && suspendedRoute.value.matched[depth])
provide(viewDepthKey, depth + 1)
provide(matchedRouteKey, matchedRouteRef)
provide(routerViewLocationKey, routeToDisplay)
+ provide('isSuspended', true)
const viewRef = ref<ComponentPublicInstance>()
return () => {
const route = routeToDisplay.value
const matchedRoute = matchedRouteRef.value
+ const suspendedMatchedRoute = suspendedMatchedRouteRef.value
const ViewComponent = matchedRoute && matchedRoute.components[props.name]
+ const SuspendedViewComponent =
+ suspendedMatchedRoute && suspendedMatchedRoute.components[props.name]
// we need the value at the time we render because when we unmount, we
// navigated to a different location so the value is different
const currentName = props.name
+ console.log('suspended', suspendedMatchedRoute)
+
+ // TODO: should be smarter to still display a suspended component
if (!ViewComponent) {
return null
}
}
}
+ function onPending(...args: any[]) {
+ console.log('pending', ...args)
+ }
+
+ function onResolve(...args: any[]) {
+ console.log('resolve', ...args)
+ }
+
+ function onFallback(...args: any[]) {
+ console.log('fallback', ...args)
+ }
+
const component = h(
ViewComponent,
assign({}, routeProps, attrs, {
})
)
- return component
+ return isSuspended
+ ? component
+ : h(
+ Suspense,
+ {
+ timeout: 0,
+ onPending,
+ onResolve,
+ onFallback,
+ },
+ component
+ )
}
},
})
$props: AllowedComponentProps &
ComponentCustomProps &
VNodeProps &
- RouterViewProps
+ RouterViewSuspendedProps
}
}
import { warn } from './warning'
import { RouterLink } from './RouterLink'
import { RouterView } from './RouterView'
-import { RouterViewSuspended } from './RouterViewSuspended'
import {
routeLocationKey,
routerKey,
const router = this
app.component('RouterLink', RouterLink)
app.component('RouterView', RouterView)
- app.component('RouterViewSuspended', RouterViewSuspended)
app.config.globalProperties.$router = router
Object.defineProperty(app.config.globalProperties, '$route', {