Skip to content

Commit

Permalink
feat: lazy fn option
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Jul 9, 2024
1 parent a470a51 commit 174bbd3
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 173 deletions.
25 changes: 22 additions & 3 deletions src/data-loaders/createDataLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,12 @@ export interface DefineDataLoaderOptionsBase<isLazy extends boolean> {
*
* @defaultValue `false`
*/
lazy?: isLazy
lazy?:
| isLazy
| ((
to: RouteLocationNormalizedLoaded,
from?: RouteLocationNormalizedLoaded
) => boolean)

/**
* Whether this loader should be awaited on the server side or not. Combined with the `lazy` option, this gives full
Expand All @@ -118,6 +123,18 @@ export interface DefineDataLoaderOptionsBase<isLazy extends boolean> {
errors?: Array<new (...args: any) => any>
}

export const toLazyValue = (
lazy:
| boolean
| undefined
| ((
to: RouteLocationNormalizedLoaded,
from?: RouteLocationNormalizedLoaded
) => boolean),
to: RouteLocationNormalizedLoaded,
from?: RouteLocationNormalizedLoaded
) => (typeof lazy === 'function' ? lazy(to, from) : lazy)

/**
* When the data should be committed to the entry.
* - `immediate`: the data is committed as soon as it is loaded.
Expand Down Expand Up @@ -200,13 +217,15 @@ export interface UseDataLoaderInternals<
/**
* Loads the data from the cache if possible, otherwise loads it from the loader and awaits it.
*
* @param route - route location to load the data for
* @param to - route location to load the data for
* @param router - router instance
* @param from - route location we are coming from
* @param parent - parent data loader entry
*/
load: (
route: RouteLocationNormalizedLoaded,
to: RouteLocationNormalizedLoaded,
router: Router,
from?: RouteLocationNormalizedLoaded,
parent?: DataLoaderEntryBase
) => Promise<void>

Expand Down
10 changes: 6 additions & 4 deletions src/data-loaders/defineColadaLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
type UseQueryReturn,
useQuery,
} from '@pinia/colada'
import { toLazyValue } from './createDataLoader'

/**
* Creates a data loader composable that can be exported by pages to attach the data loading to a route. This returns a
Expand Down Expand Up @@ -93,6 +94,7 @@ export function defineColadaLoader<Data, isLazy extends boolean>(
function load(
to: RouteLocationNormalizedLoaded,
router: Router,
from?: RouteLocationNormalizedLoaded,
parent?: DataLoaderEntryBase,
reload?: boolean
): Promise<void> {
Expand Down Expand Up @@ -229,7 +231,7 @@ export function defineColadaLoader<Data, isLazy extends boolean>(
entry.stagedError = newError
// propagate error if non lazy or during SSR
// NOTE: Cannot be handled at the guard level because of nested loaders
if (!options.lazy || isSSR) {
if (!toLazyValue(options.lazy, to, from) || isSSR) {
throw newError
}
} else {
Expand Down Expand Up @@ -352,7 +354,7 @@ export function defineColadaLoader<Data, isLazy extends boolean>(
// )
router[APP_KEY].runWithContext(() =>
// in this case we always need to run the functions for nested loaders consistency
load(route, router, parentEntry, true)
load(route, router, undefined, parentEntry, true)
)
}

Expand Down Expand Up @@ -399,14 +401,14 @@ export function defineColadaLoader<Data, isLazy extends boolean>(
isLoading,
reload: (to: RouteLocationNormalizedLoaded = router.currentRoute.value) =>
router[APP_KEY].runWithContext(() =>
load(to, router, undefined, true)
load(to, router, undefined, undefined, true)
).then(() => entry!.commit(to)),
// pinia colada
refetch: (
to: RouteLocationNormalizedLoaded = router.currentRoute.value
) =>
router[APP_KEY].runWithContext(() =>
load(to, router, undefined, true)
load(to, router, undefined, undefined, true)
).then(() => entry!.commit(to)),
refresh: (
to: RouteLocationNormalizedLoaded = router.currentRoute.value
Expand Down
8 changes: 6 additions & 2 deletions src/data-loaders/defineLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
} from 'unplugin-vue-router/runtime'

import { shallowRef } from 'vue'
import { toLazyValue } from './createDataLoader'

/**
* Creates a data loader composable that can be exported by pages to attach the data loading to a route. This returns a
Expand Down Expand Up @@ -88,6 +89,7 @@ export function defineBasicLoader<Data, isLazy extends boolean>(
function load(
to: RouteLocationNormalizedLoaded,
router: Router,
from?: RouteLocationNormalizedLoaded,
parent?: DataLoaderEntryBase
): Promise<void> {
const entries = router[LOADER_ENTRIES_KEY]!
Expand Down Expand Up @@ -197,7 +199,7 @@ export function defineBasicLoader<Data, isLazy extends boolean>(
entry.stagedError = e
// propagate error if non lazy or during SSR
// NOTE: Cannot be handled at the guard level because of nested loaders
if (!options.lazy || isSSR) {
if (!toLazyValue(options.lazy, to, from) || isSSR) {
throw e
}
}
Expand Down Expand Up @@ -309,7 +311,9 @@ export function defineBasicLoader<Data, isLazy extends boolean>(
// console.log(
// `🔁 loading from useData for "${options.key}": "${route.fullPath}"`
// )
router[APP_KEY].runWithContext(() => load(route, router, parentEntry))
router[APP_KEY].runWithContext(() =>
load(route, router, undefined, parentEntry)
)
}

entry = entries.get(loader)!
Expand Down
15 changes: 9 additions & 6 deletions src/data-loaders/navigation-guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
Router,
} from 'vue-router'
import { type _Awaitable } from '../utils'
import { type UseDataLoader } from './createDataLoader'
import { toLazyValue, type UseDataLoader } from './createDataLoader'

/**
* TODO: export functions that allow preloading outside of a navigation guard
Expand Down Expand Up @@ -131,7 +131,7 @@ export function setupLoaderGuard({
})
})

const removeDataLoaderGuard = router.beforeResolve((to) => {
const removeDataLoaderGuard = router.beforeResolve((to, from) => {
// if we reach this guard, all properties have been set
const loaders = Array.from(to.meta[LOADER_SET_KEY]!) as UseDataLoader[]

Expand All @@ -154,13 +154,13 @@ export function setupLoaderGuard({
app
// allows inject and provide APIs
.runWithContext(() =>
loader._.load(to as RouteLocationNormalizedLoaded, router)
loader._.load(to as RouteLocationNormalizedLoaded, router, from)
)
)!

// on client-side, lazy loaders are not awaited, but on server they are
// we already checked for the `server` option above
return !isSSR && lazy
return !isSSR && toLazyValue(lazy, to, from)
? undefined
: // return the non-lazy loader to commit changes after all loaders are done
ret.catch((reason) =>
Expand Down Expand Up @@ -196,7 +196,7 @@ export function setupLoaderGuard({

// listen to duplicated navigation failures to reset the pendingTo and pendingLoad
// since they won't trigger the beforeEach or beforeResolve defined above
const removeAfterEach = router.afterEach((to, _from, failure) => {
const removeAfterEach = router.afterEach((to, from, failure) => {
// console.log(
// `🔚 afterEach "${_from.fullPath}" -> "${to.fullPath}": ${failure?.message}`
// )
Expand All @@ -223,7 +223,10 @@ export function setupLoaderGuard({
// lazy loaders do not block the navigation so the navigation guard
// might call commit before the loader is ready
// on the server, entries might not even exist
if (entry && (!lazy || !entry.isLoading.value)) {
if (
entry &&
(!toLazyValue(lazy, to, from) || !entry.isLoading.value)
) {
entry.commit(to as RouteLocationNormalizedLoaded)
}
}
Expand Down
Loading

0 comments on commit 174bbd3

Please sign in to comment.