Skip to content

feat: add link prefetching support #3788

@bartlomieju

Description

@bartlomieju

Problem

Fresh supports client-side navigation via f-client-nav and Partials, but there's no built-in mechanism for prefetching upcoming navigations. Frameworks like Next.js (<Link prefetch>), Remix (<Link prefetch="intent">), and Astro (prefetch) all provide this, and it makes a noticeable difference in perceived performance.

Currently, the only workaround is manually adding <link rel="prefetch" href="..."> inside <Head>, which is static and doesn't respond to user intent.

Proposed Solution

Add prefetching support, potentially via one or more of these approaches:

1. prefetch attribute on <a> tags (within f-client-nav)

Extend the client-side navigation system to support a f-prefetch attribute:

<nav f-client-nav>
  <a href="/about" f-prefetch>About</a>
  <a href="/dashboard" f-prefetch="hover">Dashboard</a>
  <a href="/settings" f-prefetch="viewport">Settings</a>
</nav>

Strategies:

  • hover (default) — prefetch when the user hovers over the link (similar to instant.page)
  • viewport — prefetch when the link enters the viewport (via IntersectionObserver)
  • load — prefetch immediately on page load
  • none — opt out (useful when a parent sets a default)

2. Container-level default

Allow setting a default prefetch strategy on the f-client-nav container:

<nav f-client-nav f-prefetch="hover">
  <!-- All links in here prefetch on hover by default -->
  <a href="/about">About</a>
  <a href="/heavy-page" f-prefetch="none">Heavy Page</a>
</nav>

Implementation considerations

  • Prefetched responses should work with the Partials system — prefetch the partial HTML, not the full page
  • Use <link rel="prefetch"> injection or fetch() with low priority depending on browser support
  • Respect Save-Data header / navigator.connection.saveData
  • Deduplicate prefetch requests (don't re-prefetch already cached URLs)
  • Consider a cache/TTL for prefetched content to avoid serving stale partials
  • Should integrate with the cache() middleware (feat: add cache() middleware for server-side response caching #3782) — prefetched responses benefit from server-side caching

Alternatives considered

  • Manual <Head> injection — works but static, no intent-based prefetching
  • Third-party script (instant.page) — works for full page loads but doesn't integrate with Fresh's Partial system

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions