kit icon indicating copy to clipboard operation
kit copied to clipboard

data-sveltekit-preload-data="hover" results in unexpected hard navigation when network is sketchy / offline

Open leereamsnyder opened this issue 3 years ago • 6 comments

Describe the bug

When using data-sveltekit-preload-data="hover", you can invoke an unexpected hard navigation when the network is unavailable. When you're offline, and hover over a link, SvelteKit tries to preload the data/code, that fails (because you're offline, of course), and then it tries to load the error page (which also fails), and the eventual fallback is a hard navigation to the link's href, which I would not expect to happen while you are just hovering over a link.

This requires a certain combination of circumstances:

  • root layout has a load function (this does not happen without that)
  • you are using data-sveltekit-preload-data="hover" either on the link or set globally on the body (it's still a problem with "tap", but it's way more obviously a bug with "hover", because you're not clicking on the link)
  • the link goes to a different page route
  • you are offline or under some other adverse network situation, such that the preload requests and the subsequent requests for the error page all fail

What appears to be happening stepping through the code in client/client.js, it looks like when you try to preload the data on a link, SvelteKit is eventually doing load_route(), which sends you via a catch block to load_root_error_page(), which has a conditional when your root layout has a load function that lands you in native_navigation.

So, this is easiest to reproduce when offline, but it could happen in other adverse network situations.

Reproduction

https://github.com/leereamsnyder/sveltekit-offline-preload-bug

This is a skeleton SvelteKit project, with the addition of a simple layout load fn.

The readme has repro steps, copied here:

  1. npm install
  2. npm run dev
  3. Open up http://localhost:5173 in Chrome (this is most straightforward in Chrome)
  4. In the command palette (CMD + SHIFT + P), choose Go Offline, or select Offline from the throttling selector in the Network panel, typically next to Disable cache
  5. Hover over the Sverdle link in the nav. In a flash, SvelteKit will do a hard navigation tohttp://localhost:5173/sverdle, which will fail because you're offline

Logs

No response

System Info

System:
    OS: macOS 13.2
    CPU: (10) arm64 Apple M1 Pro
    Memory: 112.14 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.13.0 - /opt/homebrew/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 8.19.3 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 111.0.5563.110
    Safari: 16.3
    Safari Technology Preview: 16.4
  npmPackages:
    @sveltejs/adapter-auto: ^2.0.0 => 2.0.0 
    @sveltejs/kit: ^1.5.0 => 1.13.0 
    svelte: ^3.54.0 => 3.57.0 
    vite: ^4.2.0 => 4.2.1

Severity

serious, but I can work around it

Additional Information

Just to be clear, I don't expect SvelteKit to, ya know, work when the network is unavailable.

It's the unexpected hard navigation that happens when you just hover over a link that's the problem.

This is not a throrough or ironclad workaround, but to the extent that the browser will tell you that you're offline with built-in APIs, you can mitigate this by turning preload behavior "off" when detected. I have a component like this floating around that changes the data-sveltekit-preload-data on the <body>:

import { onMount } from 'svelte'

  onMount(() => {
    const originalPreloadData = document.body.getAttribute('data-sveltekit-preload-data')

    // this is not often accurate!
    if (navigator.onLine === false) {
      document.body.setAttribute('data-sveltekit-preload-data', 'off')
    }

    window.addEventListener('offline', () => {
      document.body.setAttribute('data-sveltekit-preload-data', 'off')
    })

    window.addEventListener('online', () => {
      document.body.setAttribute('data-sveltekit-preload-data', originalPreloadData)
    })
  })

leereamsnyder avatar Mar 24 '23 20:03 leereamsnyder

I am experiencing a similar thing. I have

  • a prerendered +layout.server.js file that is loading data
  • a data-sveltekit-preload-data="hover" attribute on the body tag
  • a page transition handled by the +layout.svelte file on route change

Everything works fine in dev mode. Also npm run preview works great. But once deployed with Firebase, the route change happens when I'm just hovering over a link! And it's also happening when I'm online - not just when offline.

Deleting data-sveltekit-preload-data="hover" from the body tag solves the issue with the navigation on hover. But the app ist still performing a full page reload, thus my page transition doesn't work anymore.

moritzlaube avatar Aug 03 '23 20:08 moritzlaube

I'm facing this exact same problem without having to deal with that last point.

you are offline or under some other adverse network situation, such that the preload requests and the subsequent requests for the error page all fail

I built my SvelteKit app, and I ran a local preview using that vite preview and it works fine. Furthermore, I even throttled the network speed to GPRS in Firefox, and it's still not forcefully switching routes.

But, when I deploy my app to Firebase, it's the exact same behavior in the deployed application as described above. To deploy, I didn't use any adapters, just regular firebase deploy command because Firebase has experimental support for deploying SvelteKit apps now.

rhymbit avatar Oct 16 '23 16:10 rhymbit

We have also seen this problem on our site where hovering over a link sometimes randomly triggers a navigation. But our site is deployed on Vercel, not Firebase.

kristjanmar avatar Oct 26 '23 14:10 kristjanmar

Regardless of network, when a link would error (403), just hovering over it redirects the user to the error page. We'd expect the error to be silent, rather than redirecting to the error page!

coyotte508 avatar Nov 12 '23 18:11 coyotte508

This is also happening to me when I use cloudflare DDoS protection. I think it is because the network request is initially not a success because it hits the DDoS protection so it does a hard navigation.

mrxbox98 avatar Feb 10 '24 22:02 mrxbox98

I have a similar issue where hard-navigation occurs when __data.json?x-sveltekit-invalidated=01 results in a 403 for whatever reason (deployed to cloudfront/s3)

danclaroni avatar Feb 20 '24 20:02 danclaroni