diff --git a/.changeset/neat-mangos-judge.md b/.changeset/neat-mangos-judge.md new file mode 100644 index 000000000000..f42417d4a0cf --- /dev/null +++ b/.changeset/neat-mangos-judge.md @@ -0,0 +1,5 @@ +--- +'astro': minor +--- + +Changes the fallback prefetch behavior on slow connections and when data saver mode is enabled. Instead of disabling prefetch entirely, the `tap` strategy will be used. diff --git a/.changeset/six-owls-trade.md b/.changeset/six-owls-trade.md new file mode 100644 index 000000000000..cd16cecec2e9 --- /dev/null +++ b/.changeset/six-owls-trade.md @@ -0,0 +1,5 @@ +--- +'astro': minor +--- + +Adds a `ignoreSlowConnection` option to the `prefetch()` API to prefetch even on data saver mode or slow connection. diff --git a/packages/astro/src/prefetch/index.ts b/packages/astro/src/prefetch/index.ts index f47cff0606f9..573efe5734ef 100644 --- a/packages/astro/src/prefetch/index.ts +++ b/packages/astro/src/prefetch/index.ts @@ -56,7 +56,7 @@ function initTapStrategy() { event, (e) => { if (elMatchesStrategy(e.target, 'tap')) { - prefetch(e.target.href, { with: 'fetch' }); + prefetch(e.target.href, { with: 'fetch', ignoreSlowConnection: true }); } }, { passive: true } @@ -176,6 +176,10 @@ export interface PrefetchOptions { * - `'fetch'`: use `fetch()`, has higher loading priority. */ with?: 'link' | 'fetch'; + /** + * Should prefetch even on data saver mode or slow connection. (default `false`) + */ + ignoreSlowConnection?: boolean; } /** @@ -190,7 +194,8 @@ export interface PrefetchOptions { * @param opts Additional options for prefetching. */ export function prefetch(url: string, opts?: PrefetchOptions) { - if (!canPrefetchUrl(url)) return; + const ignoreSlowConnection = opts?.ignoreSlowConnection ?? false; + if (!canPrefetchUrl(url, ignoreSlowConnection)) return; prefetchedUrls.add(url); const priority = opts?.with ?? 'link'; @@ -211,15 +216,11 @@ export function prefetch(url: string, opts?: PrefetchOptions) { } } -function canPrefetchUrl(url: string) { +function canPrefetchUrl(url: string, ignoreSlowConnection: boolean) { // Skip prefetch if offline if (!navigator.onLine) return false; - if ('connection' in navigator) { - // Untyped Chrome-only feature: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/connection - const conn = navigator.connection as any; - // Skip prefetch if using data saver mode or slow connection - if (conn.saveData || /(2|3)g/.test(conn.effectiveType)) return false; - } + // Skip prefetch if using data saver mode or slow connection + if (!ignoreSlowConnection && isSlowConnection()) return false; // Else check if URL is within the same origin, not the current page, and not already prefetched try { const urlObj = new URL(url, location.href); @@ -241,6 +242,12 @@ function elMatchesStrategy(el: EventTarget | null, strategy: string): el is HTML if (attrValue === 'false') { return false; } + + // Fallback to tap strategy if using data saver mode or slow connection + if (strategy === 'tap' && (attrValue != null || prefetchAll) && isSlowConnection()) { + return true; + } + // If anchor has no dataset but we want to prefetch all, or has dataset but no value, // check against fallback default strategy if ((attrValue == null && prefetchAll) || attrValue === '') { @@ -254,6 +261,15 @@ function elMatchesStrategy(el: EventTarget | null, strategy: string): el is HTML return false; } +function isSlowConnection() { + if ('connection' in navigator) { + // Untyped Chrome-only feature: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/connection + const conn = navigator.connection as any; + return conn.saveData || /(2|3)g/.test(conn.effectiveType); + } + return false; +} + /** * Listen to page loads and handle Astro's View Transition specific events */