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

Navigation sometimes gets cancelled whenever a route change occurs on initial load #334

Open
stuartcargill opened this issue Feb 3, 2021 · 2 comments

Comments

@stuartcargill
Copy link

stuartcargill commented Feb 3, 2021

Hi

I have a large application which runs 2 Angular MFE’s at the same time (nav mfe and a primary mfe)

This app has dynamic email links sent out to users. Upon opening these links, both angular mfe's bootstrap and the primary mfe calls an API to figure out what action the user wants to take (.e.g a password reset or email verify). The API call is quite lightweight and navigates the user to the respective view within the primary app.

https://myapp.com/email-handler?actioncode=123
->
https://myapp.com/reset-password

I have noticed that there is an intermittent issue with the routing where it will get stuck on the email-handler path. The redirect to the next view does not happen. The issue occurs around 1/15 attempts but seems to be more prominent when the user is on a slower connection.

After doing some tracing I can see that the navigation event gets cancelled because angular is expecting a different navigation id than the one being proposed: See below for router trace:

image

My understanding is, single-spa emits a popstate event every time a route is changed to tell MFE’s to re-render. If I set the urlReRouteOnly flag to true, this issue doesn’t happen anymore.

Whenever Angular sees a popstate event being fired, it schedules a navigation event to occur. In single-spa-angular, skipNextPopState helps us to ignore popstate events that were not dispatched by the browser (ie single-spa). What I’ve seen is sometimes this flag is set to false and thus a popstate is emitted. This triggers Angular’s navigation and it writes a new navigation id to the History API. Depending on the timing of the navigation being scheduled, Angular expects a certain navigation id but sees a different one so it cancels the navigation event.

It seems to be timing related - whenever a successful route change occurs, I can see the popstate events are emitted at a different time compared to when the navigation gets cancelled.

Demonstration
As this is a large complex app with many modules, views & dependencies, it is very difficult to create a like-for-like sample app to replicate the issue. (If I manage to replicate it, I will upload it)

Summary

  • Intermittent issue occurs when an app first loads and needs to redirect from one view to another within a short period of time.
  • Only happens if 2 MFE’s are running together.
  • Only happens when single-spa is enabled to fire popstate events

I’ve tried to narrow down the issue further but to no avail. Any help or advice is appreciated.. thanks guys.

Angular Version - 9.1
(Tested on the latest version of single-spa-angular)

@stuartcargill stuartcargill changed the title Navigation gets cancelled whenever a route change occurs on initial load Navigation sometimes gets cancelled whenever a route change occurs on initial load Feb 4, 2021
@arturovt
Copy link
Member

arturovt commented Feb 28, 2021

I'm not sure we can do anything w/o reproducible example. In general, I do not understand something very well from the screenshots.

Well, the navigation gets cancelled when somebody calls navigateByUrl (and not because navigation id doesn't match, the navigation id matching happens at the very end). It's called manually during the initial navigation by Angular when it bootstraps the module for the first time and when popstate event is dispatched. However, we can't do anything with initial navigation since it's called internally.

As I understand the navigation is cancelled for the specific app where some view should be rendered. What I would do is open the router file (node_modules/@angular/router/__ivy_ngcc__/fesm2015/router.js), press Ctrl+F and search for setupNavigations. You should be able to find this:

setupNavigations(transitions) {
        const eventsSubject = this.events;
        return transitions.pipe(filter(t => t.id !== 0), 
        // Extract URL
        map(t => (Object.assign(Object.assign({}, t), { extractedUrl: this.urlHandlingStrategy.extract(t.rawUrl) }))), 

There is switchMap going right after the map and it has an appropriate comment:

// Using switchMap so we cancel executing navigations when a new one comes in

You can modify that map to get the extracted URL before returning it so you'll understand what URL navigation cancels the current navigation:

// Extract URL
        map(t => {
            const url = Object.assign(Object.assign({}, t), { extractedUrl: this.urlHandlingStrategy.extract(t.rawUrl) });
            console.log('url = ', url);
            return url;
        }), 

@stuartcargill
Copy link
Author

@arturovt - I tried your suggestion but couldn't figure out the issue. In the end up, I converted my nav MFE from Angular to React and this fixed my problem..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants