Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update prop store to support prefetching #282

Merged
merged 10 commits into from
Oct 17, 2024
2 changes: 1 addition & 1 deletion src/components/routerView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
}

const component = getComponent(match)
const props = getProps(match.id, name, route.params)
const props = getProps(match.id, name, route)

if (!component) {
return null
Expand Down
56 changes: 43 additions & 13 deletions src/services/createPropStore.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,64 @@
import { InjectionKey, reactive } from 'vue'
import { isWithComponent, isWithComponents } from '@/types/createRouteOptions'
import { getPrefetchOption, PrefetchConfigs } from '@/types/prefetch'
import { ResolvedRoute } from '@/types/resolved'
import { Route } from '@/types/route'
import { MaybePromise } from '@/types/utilities'

export const propStoreKey: InjectionKey<PropStore> = Symbol()

type ComponentProps = { id: string, name: string, props?: (params: Record<string, unknown>) => unknown }

export type PropStore = {
prefetchProps: (route: ResolvedRoute, prefetch: PrefetchConfigs) => void,
setProps: (route: ResolvedRoute) => void,
getProps: (id: string, name: string, params: unknown) => MaybePromise<unknown> | undefined,
getProps: (id: string, name: string, route: ResolvedRoute) => unknown,
}

export function createPropStore(): PropStore {
const store = reactive(new Map<string, unknown>())

function setProps(route: ResolvedRoute): void {
store.clear()
const store: Map<string, unknown> = reactive(new Map())

const prefetchProps: PropStore['prefetchProps'] = (route, prefetch) => {
route.matches
.flatMap(match => getComponentProps(match))
.filter(match => getPrefetchOption({ ...prefetch, routePrefetch: match.prefetch }, 'props'))
.flatMap(getComponentProps)
.forEach(({ id, name, props }) => {
if (props) {
const key = getPropKey(id, name, route.params)
const key = getPropKey(id, name, route)
const value = props(route.params)

store.set(key, value)
}
})
}

function getProps(id: string, name: string, params: unknown): MaybePromise<unknown> | undefined {
const key = getPropKey(id, name, params)
const setProps: PropStore['setProps'] = (route) => {
const componentProps = route.matches.flatMap(getComponentProps)
const routeKeys = componentProps.reduce<string[]>((routeKeys, { id, name, props }) => {
const key = getPropKey(id, name, route)

if (!props || store.has(key)) {
return routeKeys
}

const value = props(route.params)

store.set(key, value)
routeKeys.push(key)

return routeKeys
}, [])

clearUnusedStoreEntries(routeKeys)
}

const getProps: PropStore['getProps'] = (id, name, route) => {
const key = getPropKey(id, name, route)

return store.get(key)
}

function getPropKey(id: string, name: string, params: unknown): string {
return [id, name, JSON.stringify(params)].join('-')
function getPropKey(id: string, name: string, route: ResolvedRoute): string {
return [id, name, route.id, JSON.stringify(route.params)].join('-')
}

function getComponentProps(options: Route['matched']): ComponentProps[] {
Expand All @@ -59,5 +79,15 @@ export function createPropStore(): PropStore {
return []
}

return { setProps, getProps }
function clearUnusedStoreEntries(keysToKeep: string[]): void {
for (const key in store.keys()) {
if (keysToKeep.includes(key)) {
continue
}

store.delete(key)
}
}

return { prefetchProps, setProps, getProps }
}
8 changes: 7 additions & 1 deletion src/types/prefetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ export type PrefetchConfigOptions = {
* @default true
*/
components?: boolean,
/**
* When true any props for routes will be prefetched
* @default false
*/
props?: boolean,
}

/**
Expand All @@ -15,9 +20,10 @@ export type PrefetchConfig = boolean | PrefetchConfigOptions

export const DEFAULT_PREFETCH_CONFIG: Required<PrefetchConfigOptions> = {
components: true,
props: false,
}

type PrefetchConfigs = {
export type PrefetchConfigs = {
routerPrefetch: PrefetchConfig | undefined,
routePrefetch: PrefetchConfig | undefined,
linkPrefetch: PrefetchConfig | undefined,
Expand Down
Loading