Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Browser Back/Forward buttons issue on iOS Chrome #1954

Closed
jakemake opened this issue Aug 30, 2024 · 8 comments · Fixed by #1984
Closed

Browser Back/Forward buttons issue on iOS Chrome #1954

jakemake opened this issue Aug 30, 2024 · 8 comments · Fixed by #1984
Assignees
Labels
bug Something isn't working

Comments

@jakemake
Copy link

jakemake commented Aug 30, 2024

Version:

  • @inertiajs/vue2 version: 1.2.0

Describe the problem:

Browser history not working properly on iOS Chrome v 128.0.6613.98
When i navigate through my web app and then click browsers "Back" button or using gesture "swipe from left" Chrome does not follow correct path (not navigating to previous page)
I use component from @inertiajs/vue2 package
When i check on iOS Safari or Brave browser everything works fine

Browser back and forward and swipe actions should work properly based on history

Steps to reproduce:

  1. Open https://demo.inertiajs.com/login or https://inertiajs.com/ or another web app which uses inertiajs on Chrome iOS
  2. Try to navigate through web app (open some links)
  3. hit the back button or swipe from left gesture
@RobertBoes
Copy link
Contributor

I've also replied on Discord (https://discord.com/channels/592327939920494592/592327939920494594/1279105338045632636), but I'll share my findings here as well.

By the looks of it this is intended behavior in Chrome/WebKit, as it's a security feature. A window.history.pushState() call can basically only be triggered through user-interaction. If it's done without user-interaction then the history item receives a special flag, then when the user navigates back it'll skip all those entries with a special flag. See https://bugs.webkit.org/show_bug.cgi?id=248303#c5

I think this is caused by the way Inertia navigates. When a user clicks on a link an XHR request is made, then when the response comes back a call is made to window.history.pushState(), so the browser would not see that as user-interaction and that history entry receives the special flag. The issue isn't with using the History API, sites like nuxtjs work as expected, it's that the pushState call is made later, outside of user-interaction.

I would think using promises all the way would let the browser figure out the origin of the call is in fact a user-interaction, but not sure if that's the case here.

@reinink
Copy link
Member

reinink commented Sep 2, 2024

Yikes, this isn't good. Thanks for bringing this to our attention. Weird that it only happens in iOS Chrome. Going to have to do some digging into this one...

@fjahn
Copy link

fjahn commented Sep 16, 2024

Just stumbled upon this as well. The way I worked around this issue for now in Vue is by replacing all references to the Link component with a custom component that falls back to regular a tags if the user is on Chrome iOS:

<template>
    <Link
        v-if="supportsPwaLinks"
        v-bind="$attrs"
    >
        <slot/>
    </Link>
    <a
        v-else
        v-bind="$attrs"
    >
        <slot/>
    </a>
</template>

<script setup>
import {Link} from '@inertiajs/vue3'

const supportsPwaLinks = !isChromeIos()

function isChromeIos() {
    return (
        !import.meta.env.SSR
        && /CriOS/i.test(navigator.userAgent)
        && /iphone|ipod|ipad/i.test(navigator.userAgent)
    )
}
</script>

The line !import.meta.env.SSR is only necessary to make SSR work.

This is horrific, but it's a good enough workaround for our purposes.

@pedroborges pedroborges added the bug Something isn't working label Sep 19, 2024
@pedroborges pedroborges self-assigned this Sep 19, 2024
@pedroborges
Copy link
Collaborator

pedroborges commented Sep 20, 2024

I hooked up my phone to debug in Chrome iOS, and here’s what I found:

  • The bug is inconsistent on Chrome iOS, giving different results each time the back button is used.

  • router.replaceState is being called multiple times during navigation, likely overwriting history states and causing incorrect behavior with the back button.

    Screen Shot 2024-09-19 at 22 52 34
  • pushState seems to work fine, but the problem appears when replaceState is used excessively.

  • Commenting out this.replaceState in saveScrollPositions reliably fixes the issue on Chrome iOS.

  • The issue is specific to Chrome on iOS. It doesn't happen in Chrome on macOS, Safari on iOS, or Safari on macOS.

  • I haven't finished investigating, but one possible solution is to detect Chrome on iOS using the user agent (/CriOS/) and adjust or skip the replaceState logic just for this browser.

I’ll keep digging into this and report back soon.

Cc: @reinink

@pedroborges
Copy link
Collaborator

pedroborges commented Sep 21, 2024

Turns out the real issue was the sequence of router.storeScrollPositions followed by router.setPage inside the router.visit method (as seen on the image above), not multiple history.replaceState calls. By ensuring that history.pushState is called only after history.replaceState completes, the navigation problem is resolved.

I have just opened #1984 for review.

@corentinclichy
Copy link

Hello,
Still have the issue on my side using chrome ios. is there any fix for that?

@dan-get-salve
Copy link

Hello, Still have the issue on my side using chrome ios. is there any fix for that?

The fix is in the current beta release

@AbdullahAgsar
Copy link

AbdullahAgsar commented Oct 30, 2024

The fix is in the current beta release

The issue is still persisting. Despite the code being the same, it sometimes works and sometimes doesn’t, so this isn’t a permanent solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants