kit
kit copied to clipboard
Make data-sveltekit-prefetch work with mousedown
Describe the problem
At this time, data-sveltekit-prefetch works with mouseover on PC, while this behavior lets the browser prefetch a link sooner, it can lead to two issues :
- prefetching more links than necessary when an user just hovers over big links without clicking on them, which can lead to additional useless requests, which are counted when using edge hostings like Cloudflare Workers or Deno, and which can lead to more data consumption
- prefetching too soon, on a near-realtime application, fetching 500ms too soon can lead to outdated data (for example, if it's realtime stats app or a chat)
Describe the proposed solution
prefetching on mousedown still lets 100ms (duration of a click) to prefetch a page before the user's click ends, and if a website is hosted on a nearby server, or on the edge, the user will keep a feeling of immediacy, it will also do requests only when the user really wants to navigate to the page
To implement mousedown prefectch, we could have something like that for per-link or per-parent-element configuration:
<a href="/mypage" data-sveltekit-prefetch="mousedown"></a>
Or have a parameter like this in svelte.config.js :
prefetching: 'mousedown'
Alternatives considered
The alternative would be to prefetch programmatically with a custom directive, but it would require to reimplement a huge part of the prefetching syntax that sveltekit already provides, so I believe just having a way to opt-in mousedown prefetching would be a much better and cleaner way of using it
Importance
i cannot use SvelteKit without it
Additional Information
Prefetching on mobile already works on touchdown and does not need to offer another prefetch behavior
While this idea is interesting the two issues you mention would still exist with mousedown prefetch hence I don't really understand the i cannot use SvelteKit without itpart since it seems you would be better off disabling prefetch completely.
I don't think we need to support this in the framework. You can disable the built-in prefetching and then programmatically call https://kit.svelte.dev/docs/modules#$app-navigation-prefetch triggered by whatever you want.
While this idea is interesting the two issues you mention would still exist with mousedown prefetch hence I don't really understand the
i cannot use SvelteKit without itpart since it seems you would be better off disabling prefetch completely.
No, disabling prefetch completely causes visible lag to the user, which prevents me from making a truly smooth app for my users.
100ms is noticeable, meanwhile, having prefetch on mousedown makes the lag disappear.
I don't think we need to support this in the framework. You can disable the built-in prefetching and then programmatically call https://kit.svelte.dev/docs/modules#$app-navigation-prefetch triggered by whatever you want.
Yes but then it makes it more boilerplatey to implement it on my own programmatically, as I described in the issue
And the feature is here to be used, I just believe it can be best used with mousedown, so modifying the behavior or at least having the option would be great
No, disabling prefetch completely causes visible lag to the user
So either the router introduces latency (which I have never noticed) then it's a specific issue or this actually concerns the entire web as it is structured, not really SvelteKit.
truly smooth app
If by smooth you mean instantaneous and your app isn't deployed in a restricted environment there are about 1001 factors that you have no control on that would make your app not "smooth".
it makes it more boilerplatey
This should be a less-than-10-lines helpers though!
So either the router introduces latency (which I have never noticed) then it's a specific issue or this actually concerns the entire web as it is structured, not really SvelteKit.
Prefetching routes also prefetches route's load() function, which makes queries to a database or at least makes a request which can take 100-200 ms, and that requests concerns the entire web, but prefetching that request eliminates this lag
If by smooth you mean
instantaneousand your app isn't deployed in a restricted environment there are about 1001 factors that you have no control on that would make your app not "smooth".
Yes but the key to make a good app is to reduces that number of factors as much as possible, even if you can't eliminate lag for every people, eliminating it for good connections is already a huge achievement that I want to have on my app
This should be a less-than-10-lines helpers though!
Not if I have to add a Svelte Action on every link to make the helper work
Another vote for not implementing this at the Kit level. This is a super-niche use case, and if you're building an app where a hundred milliseconds of prefetch delay will result in stale data, you probably need to build some better method of invalidating stale data.
Another vote for not implementing this at the Kit level. This is a super-niche use case, and if you're building an app where a hundred milliseconds of prefetch delay will result in stale data, you probably need to build some better method of invalidating stale data.
The main reason is not to invalidate stale data, but to make less useless requests on edge workers, and/or to have less requests made when some user hovers over links in my website/app
Implementing it at the kit level just requires an option that replaces mouseover by mousedown when true, I don't believe it will bloat sveltekit nor make it more complex to do it, and it will provide the best way to prefetch data without fetching too much data
Maybe there's something I'm not realizing but I don't understand why it would be a bad thing for Svelte to provide the option, given how easily it can be implemented
For instance, Discord has mousedown prefetching aswell when clicking on a server, and I believe SvelteKit should be able to make ambitious apps of this level natively, unless there is a very good reason to not let SvelteKit get the feature, but for now, I don't see any
make less useless requests on edge workers
This is a fair point, prefetch as it is now lacks a bit of subtlety in regards of limited resource, especially since sveltekit actively promotes serverless.
Two alternatives instead of making this configurable
Option 1: expose the lower-level APIs to determine the URL and if it should be prefetched (not external or reload attribute present on it), so people can implement their own ways.
Made-up example code:
import { browser } from '$app/environment';
import { findAnchor, prefetch } from '$app/navigation';
if (browser) {
document.addEventListener('mousedown', evt => {
const { url, external, reload } = findAnchor(evt);
if (!external && !reload) {
prefetch(url);
}
});
}
Option 2: Currently we trigger a custom event sveltekit:trigger_prefetch (THIS IS PRIVATE API DON'T USE) which only triggers actual prefetching if it finds a data-sveltekit-prefetch attribute. We could create a public blessed custom event which triggers prefetching without checking for the data-sveltekit-prefetch attribute but leaving all other logic in place.
What about an option to disable prefetch further down the component tree?
So you can set data-sveltekit-prefetch globally and then disable it for a specific part of your application:
<body data-sveltekit-prefetch>
<main> <!-- main content --> </main>
<nav>
<a href="/">Home</a>
<a data-sveltekit-prefetch={false} href="/settings">User Settings</a>
</nav>
</body>
I have a similar use case where preloading the route on hover could lead to some issues, But I don't want to disable prefetch for the rest of the application. Beeing able to opt-out at certain parts of the application would be a great addition.
Or also a +layout.js or +page.js option to prevent prefetching for certain routes would be an option, but I would imagine this beeing more complex to implement.
routes/settings/+layout.js
export const prerender = false
edit: I just saw that the prerender option exists already, but I guess this only applies when building the application and not when calling prerender during runtime.