Skip to content

Commit bc92c09

Browse files
committed
fix: loaders not being collected from async components for repeated navigations
1 parent e8f8dc4 commit bc92c09

File tree

4 files changed

+44
-0
lines changed

4 files changed

+44
-0
lines changed

src/data-loaders/meta-extensions.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
ABORT_CONTROLLER_KEY,
99
NAVIGATION_RESULTS_KEY,
1010
IS_SSR_KEY,
11+
LOADER_SET_PROMISES_KEY,
1112
} from './symbols'
1213
import { type NavigationResult } from './navigation-guard'
1314

@@ -70,6 +71,12 @@ declare module 'vue-router' {
7071
*/
7172
[LOADER_SET_KEY]?: Set<UseDataLoader>
7273

74+
/**
75+
* List of promises while loaders from async components are being collected.
76+
* @internal
77+
*/
78+
[LOADER_SET_PROMISES_KEY]?: Promise<void>[]
79+
7380
/**
7481
* The signal that is aborted when the navigation is canceled or an error occurs.
7582
* @internal

src/data-loaders/navigation-guard.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,26 @@ describe('navigation-guard', () => {
178178
expect([...set!]).toEqual([useDataOne, useDataTwo])
179179
})
180180

181+
it('collects all loaders from lazy loaded pages with repeated navigation', async () => {
182+
setupApp({ isSSR: false })
183+
const router = getRouter()
184+
router.addRoute({
185+
name: '_test',
186+
path: '/fetch',
187+
component: () =>
188+
import('../../tests/data-loaders/ComponentWithLoader.vue'),
189+
})
190+
191+
void router.push('/fetch')
192+
193+
// simulate repeated navigation while the async component is loading
194+
await Promise.resolve()
195+
await router.push('/fetch')
196+
197+
const set = router.currentRoute.value.meta[LOADER_SET_KEY]
198+
expect([...set!]).toEqual([useDataOne, useDataTwo])
199+
})
200+
181201
it('awaits for all loaders to be resolved', async () => {
182202
setupApp({ isSSR: false })
183203
const router = getRouter()

src/data-loaders/navigation-guard.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
IS_SSR_KEY,
1515
LOADER_ENTRIES_KEY,
1616
LOADER_SET_KEY,
17+
LOADER_SET_PROMISES_KEY,
1718
NAVIGATION_RESULTS_KEY,
1819
PENDING_LOCATION_KEY,
1920
} from './meta-extensions'
@@ -105,6 +106,7 @@ export function setupLoaderGuard({
105106
const lazyLoadingPromises: Promise<unknown>[] = []
106107

107108
for (const record of to.matched) {
109+
console.log('record', record.meta[LOADER_SET_KEY])
108110
// we only need to do this once per record as these changes are preserved
109111
// by the router
110112
if (!record.meta[LOADER_SET_KEY]) {
@@ -114,6 +116,7 @@ export function setupLoaderGuard({
114116
// add all the loaders from the components to the set
115117
for (const componentName in record.components) {
116118
const component: unknown = record.components[componentName]
119+
console.log('component', component, isAsyncModule(component))
117120

118121
// we only add async modules because otherwise the component doesn't have any loaders and the user should add
119122
// them with the `loaders` array
@@ -143,10 +146,17 @@ export function setupLoaderGuard({
143146
}
144147
}
145148
}
149+
console.log('v', viewModule)
146150
})
147151

152+
record.meta[LOADER_SET_PROMISES_KEY] ??= []
153+
record.meta[LOADER_SET_PROMISES_KEY].push(promise)
148154
lazyLoadingPromises.push(promise)
149155
}
156+
} else if (record.meta[LOADER_SET_PROMISES_KEY]) {
157+
// When repeated navigation happen on the same route, loaders might still be
158+
// resolved from async modules, so we need to wait for them to resolve.
159+
lazyLoadingPromises.push(...record.meta[LOADER_SET_PROMISES_KEY])
150160
}
151161
}
152162

@@ -156,6 +166,7 @@ export function setupLoaderGuard({
156166
// merge the whole set of loaders
157167
for (const loader of record.meta[LOADER_SET_KEY]!) {
158168
to.meta[LOADER_SET_KEY]!.add(loader)
169+
to.meta[LOADER_SET_PROMISES_KEY] = undefined
159170
}
160171
}
161172
// we return nothing to remove the value to allow the navigation

src/data-loaders/symbols.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
*/
55
export const LOADER_SET_KEY = Symbol('loaders')
66

7+
/**
8+
* Retrieves promises for loaders which are still being collected.
9+
* @internal
10+
*/
11+
export const LOADER_SET_PROMISES_KEY = Symbol('loadersPromise')
12+
713
/**
814
* Retrieves the internal version of loader entries.
915
* @internal

0 commit comments

Comments
 (0)