-
Notifications
You must be signed in to change notification settings - Fork 430
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
Navigations failing in Turbo iOS apps, due to initiator
visit option
#720
Comments
@kevinmcconnell thanks for testing this. How about sanitising the options before calling function sanitizeOptions (options) {
for (const key in options) {
try { structuredClone(options[key]) }
catch (e) { delete options[key] }
}
return options
} Ideally this would be done on the Turbo iOS side before calling We should also make a note that VisitOptions need be transferable objects. Another thought: it does seem a bit of a shame that native clients won't be able to make use of this feature. Perhaps |
Hi @domchristie
It's a good idea, but (unless I'm overlooking something here) the problem is that If you only sanitise it for a specific adapter, that could stop the crash, but it also means that the feature won't be working for clients using that adapter. Browser clients will then have events fired on the initiating element, but in mobile clients those events will continue to fire on the document element as before. I think that would lead to confusion for anyone adding listeners to those events.
Yeah, agreed. I'll have a look at the iOS side to see if there's something useful we can do for future versions there. It wouldn't help with backwards compatibility, but maybe we can make things easier on ourselves in the future somehow. One other idea could be to narrow the scope of this a bit so that it only affects the events that fire before the Either way.... until we have a version of this that works in all the adapters, I think we should consider reverting it in the meantime. It'll be great to have when it's ready, but currently it's a blocker for any iOS apps to use this version of Turbo. Does that seem reasonable? |
…723) The inclusion of the `initiator` in `VisitOptions` causes a JS crash in the Turbo iOS adapter. This is because Turbo iOS's implementation of `visitProposedToLocation` relies on being able to pass the entire options struct to native code. Initiator is an `Element`, which can't be passed in this way, resulting in a `DataCloneError` exception. There is some discussion on this [GitHub issue][]. We're reverting the change for the moment, until we have an implementation of it that works with all adapters. [GitHub issue]: #720 This reverts commit 8871817.
Hey @kevinmcconnell
Ah of course! (I guess I was hoping that the event would be dispatched before, but it makes total sense it does not!) Having mulled this over, I still think it makes sense for Here's a diff of what it might look like if we store the initiator on the I'm thinking we could also do some clever stuff with TypeScript to ensure that visit options passed to an adapter are always |
Yes, I think that sounds like it could work! Keeping this outside of the adapter seems like the key to making this work in a backwards compatible way. If it only needs to retain the initiator for the duration of proposeVisit(location: URL, options: Partial<VisitOptions> = {}) {
...
this.withCurrentInitiator(options.initiator, () => {
this.delegate.visitProposedToLocation(location, options)
})
...
}
}
startVisit(locatable: Locatable, restorationIdentifier: string, options: Partial<VisitOptions> = {}) {
...
this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, {
referrer: this.location,
initiator: this.currentInitiator,
...options,
})
this.currentVisit.start()
}
// Helpers
withCurrentInitiator(initiator: Element | undefined, func: () => void) {
this.currentInitiator = initiator
func()
delete this.currentInitiator
} So that way, any
That's the bit that worries me :) I'm just not sure what the edge cases might be here. If the only downside was that visits started outside of a |
Nice! ✨
Perhaps we could do the following:
Or that that a little over-engineered? Also, I'm not really certain that Navigator is the right place to store the initiator. Given that it calls |
In #695, an
initiator: Element
property is added toVisitOptions
, in order to track the element that initiates the visit. This works great in the browser 👍However it causes a problem for native apps that use the Turbo iOS adapter. The adapter's implementation of
visitProposedToLocation
passes the options through to native code usingpostMessage
, and the presence of theElement
causes it to fail with aDataCloneError
exception. (Presumably because theElement
type isn't supported by the underlying structuredClone operation.)The result is that tapping links in Turbo iOS apps silently fails (aside from the console error that you can see in development).
This could be fixed in Turbo iOS, but In order to not break backwards compatibility with existing apps, it would be better to take the
initiator
property back out of the options.One option could be to extend
visitProposedToLocation
with an additional argument (EventOptions
perhaps?) and move theinitiator
property into it. That extra argument would be ignored by the existing Turbo iOS code, so it would be a backwards-compatible way to evolve that part of the adapter interface. Alternatively, we could try to sidestepvisitProposedToLocation
entirely with this, and set the initiator property on theVisit
after creation.What do you think @domchristie @seanpdoyle ?
The text was updated successfully, but these errors were encountered: