kit
                                
                                
                                
                                    kit copied to clipboard
                            
                            
                            
                        Viewport prefetching
Describe the problem
Currently sveltekit:prefetch works by requesting data on hover or before click only. In some cases, it may be desirable to prefetch immediately when the link enters the viewport, similar to how nextjs works today.
https://github.com/sveltejs/kit/discussions/3041 also highlighted some points there.
Describe the proposed solution
Provide a way to define the prefetching strategy, either by viewport or hover. This can be achieved by passing a value to the attribute, e.g. sveltekit:prefetch="<strategy>". By default with no value, it would fallback to the hover strategy.
For viewport prefetching, IntersectionObservers can't be used as anchor tags change often and to detect that MutationObservers are needed, but that imposes a lot of potential overhead. An alternative is to query select anchor tags and prefetch them in short intervals. (Ideas welcomed)
To detect when to invalidate the data, maxage can be used. To avoid discouraging short maxage (which indirectly cause repeated prefetching), a syntax like sveltekit:prefetch="viewport:1000" could be supported to denote "invalidate after 1s". Or a config option can be used to set a minimum prefetch interval (similar https://github.com/sveltejs/kit/issues/790)
Alternatives considered
Refer users to implement their own viewport prefetch logic using actions. Caveat is that links in contents from CDN can't take advantage of the declarative prefetching syntax.
Importance
nice to have
Additional Information
- Rich noted that prefetch invalidation may not always be wasteful as the modules requested are usually reusable, only the data is stale.
 - Adding viewport prefetch implementation may require some infrastructure refactoring.
 - I might've forgotten some points from the last maintainer's meeting.
 
Just wanted to chime in again that adding this kind of config to every anchor element in an app is a lot of user overhead in terms of DX which is also introduces more surface for user-error. IMO if this was implemented it would be an even stronger argument for adding the ability to prefetch all relative links by default at the same time, with this stuff configured globally in the same place. A prefetch option under kit in svete.config.js feels like a no-brainer, with per-link overrides possible.
I wrote my own implementation of a Prefetch link whenever the link is in viewport. I additionally added a prop which if set to false will only prefetch the page and not run the load method (as in NextJS where load is not run).
For checking whether the link is in viewport, I think its better to use Intersection Observer API
<script lang="ts">
  import { goto, prefetch, prefetchRoutes } from "$app/navigation";
  export let to: string;
  export let preload: boolean = true;
  let fetched = false;
  const isInViewPort = (element: any) => {
    const rect = element.getBoundingClientRect();
    return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <=
        (window.innerHeight + rect.height ||
          document.documentElement.clientHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
  };
  const viewPortAction = (element: any) => {
    const interval = setInterval(() => {
      if (!fetched && isInViewPort(element)) {
        //prefetch the page
        if (preload) {
          prefetch(to).finally(() => {
            fetched = true;
            clearInterval(interval);
          });
        } else {
          prefetchRoutes([to]).finally(() => {
            fetched = true;
            clearInterval(interval);
          });
        }
      }
    }, 200); // check if link is in viewport every 200 millis
    return {
      destroy: () => {
        clearInterval(interval);
      },
    };
  };
  const handleLinkClick = () => {
    goto(to);
  };
</script>
{#if preload}
  <a href={to} use:viewPortAction on:click|preventDefault={handleLinkClick}>
    <slot />
  </a>
{:else}
  <a href={to} use:viewPortAction on:click|preventDefault={handleLinkClick}
    ><slot /></a
  >
{/if}
                                    
                                    
                                    
                                
Another strategy might be 'focus'. If I navigate to a link with the tab key, maybe that link should start prefetching? Then again, doing so would typically mean prefetching all the links you tab through until you get to the one you want, so maybe not. Unclear. At the very least we should prefetch on keydown for focused links.
this can be closed now that we have data-sveltekit-preload-code="viewport"
https://kit.svelte.dev/docs/link-options#data-sveltekit-preload-code