perf(series): the episode list no longer waits on the server
Opening Frasier on a Fairphone took ~5 s to render the episode list although every episode was cached. Three causes: - resolve_series_view waited for Next Up and resume before returning the episodes, and Next Up was server-first. The episode list now returns as soon as the episodes are in (with_hints); hints that have answered are used, late ones dropped, and the picker falls back to local watch state. Next Up is cache-first like every other query. - The page loaded itself six times per open: onMount plus a mount-time $effect, the reachability effect's first run posing as a reconnect, and a double mount. All triggers now share one coalesced load per item (createCoalescedLoader); refresh triggers get one re-run after it. - The root layout rendered the route in two branches that each rendered children; the page store deciding between them updates a flush late, so navigating Search -> library page mounted the page twice. One element now renders the route and only its classes change. On the device: one load per open, seasons from cache in 14 ms, episodes and the Resume button up in under a second (was ~5 s).
This commit is contained in:
+24
-23
@@ -73,7 +73,8 @@
|
||||
// a new page inherits the previous page's offset. Must be registered here at
|
||||
// init, alongside the tracker above, for the same reason. (DR-156)
|
||||
let shellScroller = $state<HTMLElement>();
|
||||
useScrollRestore(() => shellScroller, "shell");
|
||||
// Owned routes scroll inside their own column; the shell box does not.
|
||||
useScrollRestore(() => (routeOwnsLayout ? undefined : shellScroller), "shell");
|
||||
|
||||
// Layout-shell visibility rules live in one pure, unit-tested module
|
||||
// ($lib/utils/layoutShell) so they can't drift per route/platform.
|
||||
@@ -357,29 +358,29 @@
|
||||
scrolling internally. All other top-level pages render directly here, so
|
||||
this wrapper must scroll and reserve the fixed bottom UI's measured
|
||||
height so the mini player / bottom nav never overlap the last rows. -->
|
||||
{#if routeOwnsLayout}
|
||||
<!-- These routes own their own full-height flex column (header + scroller
|
||||
+ their own in-flow BottomUi), so the root just clips and steps back. -->
|
||||
<div class="flex-1 overflow-hidden">
|
||||
{@render children()}
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Shared header (account menu, desktop nav) as a flex-shrink-0 sibling
|
||||
above the scroller, so it never eats into the scroller's bounds. -->
|
||||
{#if showGlobalHeader}
|
||||
<AppHeader />
|
||||
{/if}
|
||||
<!-- Scroller is flex-1/min-h-0; the in-flow BottomUi below is a flex
|
||||
sibling, so the list is physically bounded above it and can never
|
||||
render behind it. No measurement, no reserved padding. -->
|
||||
<div
|
||||
bind:this={shellScroller}
|
||||
class="flex-1 overflow-y-auto min-h-0"
|
||||
style="overscroll-behavior: contain"
|
||||
>
|
||||
{@render children()}
|
||||
</div>
|
||||
<!-- Shared header (account menu, desktop nav) as a flex-shrink-0 sibling
|
||||
above the scroller, so it never eats into the scroller's bounds. -->
|
||||
{#if !routeOwnsLayout && showGlobalHeader}
|
||||
<AppHeader />
|
||||
{/if}
|
||||
<!-- ONE element renders the route, whatever the layout mode; only its
|
||||
classes change. Routes that own their full-height column (header +
|
||||
scroller + their own in-flow BottomUi) get a plain clipped box; every
|
||||
other route gets the shell scroller (flex-1/min-h-0, bounded above the
|
||||
in-flow BottomUi, so no measurement or reserved padding).
|
||||
|
||||
This used to be two branches, each rendering `children`. The page
|
||||
store that decides the mode can update a flush after the new route
|
||||
renders, so navigating between the two kinds of route (Search → a
|
||||
library page) mounted the page under one branch and then *remounted*
|
||||
it under the other — every load it started, twice (DR-295). -->
|
||||
<div
|
||||
bind:this={shellScroller}
|
||||
class={routeOwnsLayout ? "flex-1 overflow-hidden" : "flex-1 overflow-y-auto min-h-0"}
|
||||
style={routeOwnsLayout ? undefined : "overscroll-behavior: contain"}
|
||||
>
|
||||
{@render children()}
|
||||
</div>
|
||||
|
||||
<!-- Re-authentication modal -->
|
||||
<ReauthModal isOpen={$needsReauth} />
|
||||
|
||||
Reference in New Issue
Block a user