byhemechi

byhemechi

Many web frameworks (e.g. Remix, Gatsby) have an option for their link components that begins the navigation request on hover so that when the link is actually clicked ~300ms later the page is cached and ready to be swapped over. This compensates for network latency very effectively, my ping from Sydney to Frankfurt is about 280ms.

This would be an enourmous improvement in UX for people not geographically close to servers, and as nice as it would be to put everything on fly.io or some other edge equivalent it’s not an option for many people

My understanding of the challenges involved is that the biggest issue would be desync between what the server thinks the DOM looks like vs what is actually there if the link is hovered over but not actually clicked.

I would work on this myself but i don’t feel like my knowledge of liveview is adequate to implement this without creating a huge mess :slight_smile:

Showing Posts 1 to 10

LostKobrakai

LostKobrakai

This might be a huge rabbit hole. Think of mount callbacks connecting to presence, pubsub or the likes triggering side effects beyond what you really intend on a prefetch. You might also need to be able to run two LV processes side by side unless you dig in real deep and remodel probably half of LV to add a new specialized prefetch rendering mode.

aloukissas

aloukissas

I would love to see this. It’s so common nowadays, it’s a miss on Phoenix not to have something like that OOTB.

Btw I kind of hackily did this (don’t run this in production, probably) like so:

function prefetchPage(url) {
  // Create a hidden iframe to load the page
  const iframe = document.createElement("iframe");
  iframe.style.display = "none";
  iframe.src = url;
  document.body.appendChild(iframe);

  // Remove the iframe after loading to clean up
  iframe.onload = () => {
    setTimeout(() => {
      document.body.removeChild(iframe);
    }, 1000); // Give some time for resources to load
  };
}

document.querySelectorAll("a").forEach((link) => {
  let timer;

  link.addEventListener("mouseenter", () => {
    // Start a timer to avoid prefetching on quick hover-bys
    timer = setTimeout(() => {
      prefetchPage(link.href);
    }, 100);
  });

  link.addEventListener("mouseleave", () => {
    // Cancel prefetch if mouse leaves before timer completes
    clearTimeout(timer);
  });
});
harrisi

harrisi

I would recommend using fetch with priority: low instead of embedding an iframe to reduce memory, not modify the DOM, etc. I’d also recommend using mouseover and mouseout, and further would recommend pointerover and pointerout instead to support more pointing devices. For both of those, obviously you want to make sure the changed behavior is acceptable/handled correctly. I also think the 100ms delay is kind of counterproductive for this use, but I get it. Using fetch instead also allows you to easily abort the request if desired.

You also asked about this behavior in relation to Next on Slack, which does the hover logic when prefetch=false. For prefetch=true, which fetches the linked page when it’s in the viewport, this can be done pretty easily with the Intersection Observer API.

As far as the interaction with liveview, I don’t have anything useful to add, unfortunately.

rhcarvalho

rhcarvalho

Been looking at this thread and thinking…

I think the problem with fetch (and the iframe) in the case of LiveView is that it probably doesn’t help make the live navigation (over the persistent WebSocket connection) any faster, and brings questions about behavior.

JS fetch would probably cause only a “disconnected mount” of the prefetched page/LiveView, while the iframe would trigger both disconnected and connected mounts with a full LiveView process on the server which can’t really be reused when the actual navigation happens.

harrisi

harrisi

Yeah, I think it would only help when using <.link href=foo>, which does an HTTP request, as far as I understand. For live navigation, I don’t know enough to say if the familiar “prefetch” tricks are useful, but I wouldn’t expect them to be.

aloukissas

aloukissas

I think the approach that astro does is the cleanest and mostly leveraging browser standards:

  1. It prefers using speculation rules, if available
  2. It falls back to rel=prefetch, if available
  3. finally, resorts to using fetch()

They also keep track of already prefetched URLs in a set and bail early.

Prefetching can be configured to be global on the project, opt-in/out per link, etc. Very good ergonomics!

harrisi

harrisi

Unfortunately the only option of the three that is actually available in >80% of user agents is fetch. This may not matter for certain purposes (if you know or are able to require your users to use Chrome, mainly), but I’m personally not a fan of using Chrome-only features (rel=prefetch is not Chrome-only, for what it’s worth, just not as widely available as fetch).

Anyway, still not sure how relevant any of this is to liveview :slight_smile:

aloukissas

aloukissas

wdym? this works on chrome/chromium, safari, firefox? Plus most of the world is on Chrome. Would you really not ship an optimization for the majority of the world because it’s chrome-only? Sounds like a terrible trade-off!

rhcarvalho

rhcarvalho

I looked at some of the Astro docs to understand/remember what it is all about: Why Astro? | Docs

IIUC, Astro allows one to build server-rendered static pages. Navigation then means full/regular HTTPS requests.

External links are not prefetched, so prefetching focuses on optimizing internal page navigation.

LiveView’s focuses on a different set of goals. Whereas Astro contrasts itself with other JS frameworks primarily targeted at building web applications (with login, dashboards, User Interactions, etc), LiveView is a tool for building just that, albeit in a different way.

LiveView has a persistent WebSocket connection and internal navigation over the WebSocket bypasses most of what goes on in an HTTPS request. I think Astro doesn’t have that.

Typical LiveView applications have state, and that complicates the applicability of prefetching as others have mentioned.

At this point I don’t know what are we actually trying to improve in LiveView with prefetching, or is it just trying to copy a solution to a problem we don’t have :slight_smile:

aloukissas

aloukissas

Cross-site navigation in phoenix projects (liveview or not) is just slower compared to astro, nextjs, remix etc. All of them to prefetch on hover (or when a link is in the view port). This means fetching images etc. So navigating to another page within the site is instant.

If you think Phoenix is ok staying behind as the “slow” solution (e.g. try using hexdocs sidenav- it is def not instant), then fine :slight_smile:

Where Next? Top

Trending in Proposals: Ideas Top

woylie
We are seeing a lot of warning logs like this: navigate event to "https://someurl" failed because you are redirecting across live_sessio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews