diff options
Diffstat (limited to 'src/lib/shared')
| -rw-r--r-- | src/lib/shared/refresh-policy.test.ts | 43 | ||||
| -rw-r--r-- | src/lib/shared/refresh-policy.ts | 31 |
2 files changed, 74 insertions, 0 deletions
diff --git a/src/lib/shared/refresh-policy.test.ts b/src/lib/shared/refresh-policy.test.ts new file mode 100644 index 0000000..5cab234 --- /dev/null +++ b/src/lib/shared/refresh-policy.test.ts @@ -0,0 +1,43 @@ +import { describe, it, expect } from 'vitest'; +import { shouldAutoRefresh } from './refresh-policy'; + +const idle = { visible: true, online: true, navigating: false }; + +describe('shouldAutoRefresh', () => { + it('refreshes a list page when the tab is visible and idle', () => { + expect(shouldAutoRefresh({ routeId: '/groceries', ...idle })).toBe(true); + expect(shouldAutoRefresh({ routeId: '/groceries/catalog', ...idle })).toBe( + true, + ); + expect(shouldAutoRefresh({ routeId: '/projects/[id]', ...idle })).toBe( + true, + ); + }); + + it('never refreshes a page holding an in-progress edit', () => { + expect(shouldAutoRefresh({ routeId: '/grocery/[id]', ...idle })).toBe( + false, + ); + expect( + shouldAutoRefresh({ + routeId: '/projects/[projectId]/routine/[routineId]', + ...idle, + }), + ).toBe(false); + expect(shouldAutoRefresh({ routeId: '/login', ...idle })).toBe(false); + }); + + it('holds off while hidden, offline or mid-navigation', () => { + const routeId = '/groceries'; + expect(shouldAutoRefresh({ routeId, ...idle, visible: false })).toBe(false); + expect(shouldAutoRefresh({ routeId, ...idle, online: false })).toBe(false); + expect(shouldAutoRefresh({ routeId, ...idle, navigating: true })).toBe( + false, + ); + }); + + it('holds off when the route is not resolved yet', () => { + expect(shouldAutoRefresh({ routeId: null, ...idle })).toBe(false); + expect(shouldAutoRefresh({ routeId: undefined, ...idle })).toBe(false); + }); +}); diff --git a/src/lib/shared/refresh-policy.ts b/src/lib/shared/refresh-policy.ts new file mode 100644 index 0000000..d79e6b7 --- /dev/null +++ b/src/lib/shared/refresh-policy.ts @@ -0,0 +1,31 @@ +/** + * Routes whose page data must not be refetched in the background: edit pages + * hold in-progress work, and refreshing the login form is pointless. + */ +export const EXCLUDED_ROUTES: Record<string, true> = { + '/login': true, + '/grocery/[id]': true, + '/projects/[projectId]/routine/[routineId]': true, +}; + +export interface RefreshConditions { + /** `$page.route.id`; null when no route matched yet. */ + routeId: string | null | undefined; + /** Document is visible (not a backgrounded tab). */ + visible: boolean; + /** Browser reports a network connection. */ + online: boolean; + /** A navigation or form action is already in flight. */ + navigating: boolean; +} + +/** A background refetch may re-run the page load only if nothing is at stake. */ +export function shouldAutoRefresh({ + routeId, + visible, + online, + navigating, +}: RefreshConditions): boolean { + if (!routeId || routeId in EXCLUDED_ROUTES) return false; + return visible && online && !navigating; +} |
