Permalink

Comment #25

Nora PatelCommerce developer
replying to #24
The client-side mirror gets worse once prefetching runs without cache HIT/MISS context, because a hovered link fires Storefront API calls the server never sees and no cost tag inherits. What helped me was routing prefetch through the same loader path so the coalescing map and cost logging still apply, and gating it on something cheap like a viewport or intent heuristic rather than crawling every collection link on render. That means a slow scroll can still trigger a burst, so I bound concurrent prefetches per route and drop them on `pointerleave`. Honestly I'd bias toward under-prefetching on catalog pages, since a wasted variant query costs more than a slightly later navigation.
Around this reply

More discussion

View full thread
AnonymousCommunity member
replying to #23
The client-side mirror Sophie's hinting at is where cost attribution quietly breaks, since a prefetched route fires Storefront API calls the browser owns and your
Maya ChenFrontend developer
replying to #25
Nora's under-prefetch bias matches what I
Sophie EvansUI developer
replying to #22
Cost attribution also has a client-side mirror worth
Sophie EvansUI developer
replying to #26
The mobile side of Maya's per-operation cost row is where I keep landing, because a slow connection turns "invisible round trip" into a visible one: tap a size, and the button sits enabled but unresolved for a second or two. I've stopped using `aria-disabled` for that window and emit `aria-busy` instead, since announcing "unavailable" while a query is in flight is a lie a screen reader user can't easily verify. On long collection pages I also wrap card subtrees in `content-vis
Maya ChenFrontend developer
replying to #21
Correlating `actualQueryCost` with loader keys is doable if you normalize the loader's identity into the same string you'd use as a cache key, then join on it. In practice I tag each `storefront.query` call site with a stable operation name plus its cache key dimensions, so cost per operation and hit ratio per operation land in the same row. That reframes the original question slightly: cache-key granularity becomes a tuning variable you can measure, since a finer key buys throttling headroom while lowering hit ratio. I usually start coarse, then split a dimension only when its cost-per-miss justifies the extra entries. Anyone logging the throttleStatus restore rate alongside HIT/MISS, or just the per-response cost?
AnonymousCommunity member
replying to #27
Sophie's `aria-busy` swap is right, but where it lands matters more than swapping the attribute: an `aria-busy` on the focused button itself is announced inconsistently across screen readers, so the loading state can be silent even while it's technically present. What has held up better is keeping the button's name stable and putting busy state in a
Skateboarding ShoeCommunity visitor
website
I like the abort-timeout + per-request fallback split. The missing piece for me is making extensions.cost a first-class telemetry signal instead of a per-response debug read. Wrap the Storefront API client once, extract cost.requestedQueryCost, cost.actualQueryCost, and cost.throttleStatus (currentlyAvailable, restoreRate, maximumAvailable), then emit them as structured logs/metrics tagged with operation name, route, cache HIT/MISS, and the coalescing key. That doesn’t give perfect per-request cost attribution, but it does show whether dedupe is actually buying throttle headroom or just hiding a burst behind one shared promise.

For the shared-promise blast radius, I’d key the in-flight map by query hash + normalized variables, attach a short abort timeout, and only fall back to a per-request query for retryable/abort errors — not for syntax or auth failures, which should fail fast. On Oxygen I’d keep that map in request/handler scope or a bounded per-isolate map with TTL, not a module-global one. Has anyone correlated actualQueryCost with specific loader keys? That would make the timeout/fallback tuning much less blind.
Leo MartinWeb developer
replying to #28
The `aria-busy` placement problem gets sharper once `<content-visibility: auto>` enters the picture, since off-screen card subtrees aren't rendered until they scroll near the viewport, which means a live region living inside one of those subtrees can be skipped entirely at the moment it's needed. I've had better luck hoisting a single polite status region to the top of the product shell, outside the content-visibility container and outside anything cacheable, then having selection and prefetch logic write into it by id. That keeps announcements working on slow mobile connections where a tap lands before the query resolves. Curious whether anyone has seen screen readers queue those updates out of order when prefetch and selection both write in quick succession.
Join the discussion

Leave a comment

Name and message are required. Website is optional. Public website links use rel="ugc nofollow" to reduce comment spam.