WICG / navigation-api

The new navigation API provides a new interface for navigations and session history, with a focus on single-page application navigations.
https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api
484 stars 30 forks source link

Getting notified about cancellation of the initial navigation. #256

Open jespertheend opened 1 year ago

jespertheend commented 1 year ago

We have a site that shows a loading screen on first page load, which is served in the html of the initial navigation, without running any scripts. We then download all the scripts and assets, which might take a while on slower connections. During this time the user is able to cancel the page load using the escape key. But this can be a bit confusing, because when cancelling the page load, the text 'loading...' will stay visible forever, or until the page is refreshed. It doesn't help either that the escape key is also used to open the menu once the page has loaded.

So I'm trying to figure out a way to improve the user experience here. I was hoping there would be an event that I could listen for when the page load is cancelled. That way I could change the text to something else. Or maybe prevent the cancellation. Right now the only thing that seems to work is listening for the 'Escape' key. But without being able to know for sure whether this caused the user agent to prevent loading, the best I can do is preventDefault the event:

window.addEventListener("keydown", e => {
    if (e.code == "Escape") {
        e.preventDefault();
    }
});
domenic commented 1 year ago

This is not currently possible. However, I think we could consider making it work. The hard part is whether we want to treat the initial page load as special, or try to integrate it with the rest of the navigation API.

Arguments for treating it as special: well, it is special. In particular:

So although it is tempting to try to do something clever here, e.g. making navigation.transition have a non-null value during the current page load, or try to find a good time to fire a special NavigateEvent representing the initial page load, I think we're better off doing a special API just for the initial page load.

Another idea we've gotten in this space is https://github.com/whatwg/html/issues/9090.

Here's one idea:

navigation.initialLoad.signal.addEventListener("abort", () => {
  // initial page load was aborted
});

// Stop the loading indicator.
navigation.initialLoad.stopIndicator();

// Maybe this is the place to put https://github.com/whatwg/html/pull/1936,
// if people still want that:
await navigation.initialLoad.parsed;
await navigation.initialLoad.contentLoaded;
await navigation.initialLoad.subresourcesFullyLoaded;

// We could add some of the more informational properties of NavigateEvent, maybe?!
navigation.initialLoad.userInitiated;
navigation.initialLoad.navigationType;
navigation.initialLoad.formData; // this one could be a lot of work to implement, for POSTs
jespertheend commented 1 year ago

This sounds good! I wish I could give somewhat more constructive feedback on this, but admittedly I haven't yet had a chance to use the navigation api a lot. The sites I make are mostly SPA web games, so I'm not exactly dealing with navigations on a daily basis. Getting more control over the initial page load is my only use case really.

khushalsagar commented 1 year ago

I like the proposal on here! Another use-case which needs this is cross-document View Transition. The new Document needs to know the type of navigation to set up the UX (like swipe left/right if its a back/fwd navigation).

A few aspects to think through:

domenic commented 1 year ago
  • initialLoad will need to be updated if the Document is restored from BFCache or activated after pre-rendering. So probably just the naming needs to be different.

Strongly agreed. Name suggestions welcome... Nothing is immediately coming to mind.

  • initialLoad can also provide you an index of the previous navigation entry. So authors can know what the url or any other state of the old Document was for this navigation.

I think we can provide the whole previous entry, with a .from property. At least for same-origin navigations, which is what the navigation API mostly deals with... is it OK to scope out cross-origin ones? Or should we think through something that might work for both? (All navigation API indices are within a same-origin context.)

  • I like that initialLoad gives a set of promises to observe the Document going through different stages in a navigation lifecycle. I wonder if the event proposed here could be one of those promises?

That sounds great!

In general, the promises I mentioned above (from https://github.com/whatwg/html/pull/1936) kind of floundered on lack of use cases. So we should start with ones that have solid use cases, like your reveal. (Another one that comes up often is a promise version of the prerenderingchange event.)

khushalsagar commented 1 year ago

Or should we think through something that might work for both? (All navigation API indices are within a same-origin context.)

Same-origin is fine for now.

We want to extend this feature to same-site eventually. Assuming both Documents opt-in, is there a reason the browser still can't allow same-site entries to be visible in the navigation API.

domenic commented 1 year ago

We want to extend this feature to same-site eventually. Assuming both Documents opt-in, is there a reason the browser still can't allow same-site entries to be visible in the navigation API.

Assuming both documents opt-in, this would be fine.

vmpstr commented 1 year ago
      // Subscribe for new load.
      navigation.initialLoad.reveal.then(setUpTransition);

      // Subscribe for BFCache loads? Does this also work for pre-render?
      window.addEventList("pageshow", (event) => {
        if (event.persisted) { setUpTransition(); }
      });

Just to clarify my understanding: You'd still need to register things for BFCache restores right? Like navigation.initialLoad.reveal is a promise that gets satisfied at some point in the initial load, but then it would need to be a new promise when this page is again activated out of BFCache, so you'd still register for pageshow?

khushalsagar commented 1 year ago

^ yes. The initialLoad object changes when the Document exits BFCache. The event.persisted check in pageShow is to register to the new promise for that case.

noamr commented 11 months ago

Created an HTML issue to continue evolving the proposal from the comment: https://github.com/whatwg/html/issues/9760