Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fallback to tap prefetch strategy on slow connection #9092

Merged
merged 6 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/neat-mangos-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': minor
---

Fallback to the `tap` prefetch strategy on slow connection, instead of bailing.
bluwy marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 5 additions & 0 deletions .changeset/six-owls-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': minor
---

Adds a `ignoreSlowConnection` option to the `prefetch()` API to prefetch even on data saver mode or slow connection.
34 changes: 25 additions & 9 deletions packages/astro/src/prefetch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -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';
Expand All @@ -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);
Expand All @@ -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 === '') {
Expand All @@ -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
*/
Expand Down
Loading