Ionic PWA Loading The Wrong First Page

I’m having a weird issue with our PWA, where’s the app is initially loading the wrong page, before loading the correct one specified from the URL (http://localhost:8100/#/groups).

I’m defining links in our IonicModule.forRoot like:

[
{ component: PersonListPage, segment: 'people'},
{ component: GroupListPage, segment: 'groups'}, 
...
]

It seems random but it always loads the 18th segment in the list, seems bazaar right? If I re-arrange the items, it still loads the 18th segment.

I thought maybe it could be related to priority, although we have preloadModules set to false.

I’ve added null checks to each page to ensure parameters are set so it doesn’t thrown an exception, although it still flashes that first page before loading the correct page.

Any thoughts or suggestions on what could be causing this issue?

Is the ‘wrong page’ your AppComponent’s rootPage:

  public rootPage: any = 'SignInPage'; 

Do user’s have to sign up/sign in?

    this.authService.afAuth.authState.subscribe(user => {

        if (user) {
          this.rootPage = 'TabsPage';
        } else {
          this.rootPage = 'SignInPage';
        }
      }, () => {
        this.rootPage = 'SignInPage';
      }
    );

I try to follow the Angular Style Guide: https://angular.io/guide/styleguide#app-root-module

So my AppModule is very ‘light’:

@NgModule({
  declarations: [ AppComponent ],
  imports: [
    BrowserModule,
    CoreModule,
    IonicModule.forRoot(AppComponent, {
      backButtonText: ''
      // preloadModules: true
      // tabsHideOnSubPages: true
    })
  ],
  bootstrap: [ IonicApp ],
  entryComponents: [ AppComponent ],
  providers: []
})
export class AppModule {}

And my CoreModule does all the heavy lifting

@NgModule({
  imports: [
    AngularFireModule.initializeApp(ENV.firebase),
    AngularFirestoreModule,
    AngularFireAuthModule,
    CommonModule,
    HttpClientModule,
    IonicModule,
    ...
    ServiceWorkerModule.register('/ngsw-worker.js', { enabled: ENV.production }),
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [ HttpClient ]
      }
    })
  ],
  exports: [],
  declarations: [],
  providers: [
    AuthService,
    ...
    { provide: LoggerService, useClass: ConsoleLoggerService },
    ...
    ServiceWorkerService
  ]
})
export class CoreModule {
  constructor( @Optional() @SkipSelf() parentModule: CoreModule,
               private translate: TranslateService,
               private afs: AngularFirestore) {

    throwIfAlreadyLoaded(parentModule, 'CoreModule');

    translate.setDefaultLang('en');

    const settings = { timestampsInSnapshots: true };
    afs.app.firestore().settings(settings);
  }
}

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http);
}

And, I lazy load pages.

BTW, you can configure your segments via @IonicPage:

@IonicPage({
  segment: 'sign-in'
})

Hmm @robinyo, something strange is definitely happening with the routes but can’t figure out what.

I added a LoadingPage which I set rootPage to, so that should be loaded first before I determine if the user is logged in or not. When the PWA first loads, it shows the LoadingPage and then either shows SigninPage or HomePage correctly.

However if I refresh the page or try to load http://localhost:8100/#/signin directly, that’s when it loads the wrong page. Also now that there’s another segment listed in the links, it’s showing a different page first, in this case the last one in the array.

I’m setting links inside IonicModule.forRoot where ROUTES is the array of pages.

IonicModule.forRoot(MyApp, {}, {links:this.ROUTES})

And also setting segment inside of IonicPage as well.

@IonicPage({
  segment: 'signin'
})

Could setting segment in both IonicPage and IonicModule.forRoot be the issue? Or does the order you specify your links matter?

Oh @robinyo, looks like this bug might be related?

Ok, I think I’ve made some progress, by the looks of those issues the DeepLinker has problems sometimes matching names.

I previously had not defined any name values in IonicPage or in deepLinkConfig. So after adding a name for each component, I no longer get that random first page loading, so that’s good!

However I now started getting another error when trying to reload a page like http://localhost:8100/#/groups:

Error: Uncaught (in promise): TypeError: Cannot set property 'groups' of undefined
TypeError: Cannot set property 'groups' of undefined

Clicking links in the PWA works fine, the problem only happens when reloading a page or trying to access a page by it’s URL like http://localhost:8100/#/groups.

Ok, looks like that specific error is being caused when loading values in ionViewWillEnter vs ionViewDidEnter.

When clicking links in the app, everything works as expected. However when reloading a page or accessing page directly like http://localhost:8100/#/groups, some of values are not getting set as I’d expect.

Looks like I’ll need to dig deeper on how I’m passing values between pages versus how they are being set when loaded from the DeepLinker.

Did you try to patch the DeepLinker:

UrlSerializer.prototype.getLinkFromName = function (nameOrComponent) {
        return this.links.find(function (link) {
            return (link.component === nameOrComponent) 
                       || (link.name === nameOrComponent) 
                       || (nameOrComponent.indexOf(link.name )>-1); //added this line
        });
    };

Ok, I think I’ve figured things out, sort of.

Turns out my original problem with the DeepLinker loading the wrong first page, was fixed when I gave all pages a name value (in case someone else runs into the same problem).

The other problem is different, due to how I am expecting certain parameters being set in ionViewWillEnter of pages.

When its running as an app, I’m passing parameters in navController.push or navController.setRoot and then loading those values using navParams.get in pages ionViewWillEnter.

However when it’s running as a PWA, opening a page directly like http://localhost:8100/#/groups is relying on the DeepLinker to load that page, those same parameters are not being passed.

So I’ll need to rethink how pages expect parameters, since they need to work for both mobile app and as PWA.

Just FYI, the routing for Ionic 4 is likely to be way better. So I do everything I can except deal with the Deep Linker, expecting that this problem with “solve itself” soon.

Maybe a slap in your face, now that you’ve done so much work, but I do think things will get better sometime this summer.

Thanks for the message @AaronSterling, I’m looking forward to Ionic 4!

Our app was originally built for iOS and Android, just recently converted to also run as a PWA.

For the most part things are working alright, although it’s taking some refactoring to skip using the native plugins when running in the browser and now trying to get routes wired up has been a learning curve.

Remember if your bookmarking a URL then you need to provide the ‘id’ as a part of the URL. You can’t pass objects only object id’s.

@IonicPage({
  name: 'VenuePage',
  segment: 'venue/:id'
})

...

  constructor(public navCtrl: NavController,
              public navParams: NavParams,
              private venuesService: VenuesService,
              private logger: LoggerService) {

    this.itemId = navParams.get('id');
  }


I’m also using tabs:

<ion-tabs #tabs selectedIndex="2" (ionChange)="onIonChanged($event)">
  <ion-tab [root]="tab0Root" tabUrlPath="activity-tab" tabIcon="fa-fal-list"></ion-tab>
  <ion-tab [root]="tab1Root" tabUrlPath="location-tab" tabIcon="fa-fal-map-marker"></ion-tab>
  <ion-tab [root]="tab2Root" tabUrlPath="search-tab" tabIcon="fa-fal-street-view"></ion-tab>
  <ion-tab [root]="tab3Root" tabUrlPath="person-tab" tabIcon="fa-fal-user"></ion-tab>
  <ion-tab [root]="tab4Root" tabUrlPath="notifications-tab" tabIcon="fa-fal-bell"></ion-tab>
</ion-tabs>

So I followed this advice: URL navigation redirects to root page when using lazy loaded tabs template · Issue #12680 · ionic-team/ionic-framework · GitHub

tabs.page.ts:

@IonicPage({
  name: 'TabsPage',
  segment: 'sbat'  // tabs
})

search.page.ts:

@IonicPage({
  name: 'SearchPage',
  segment: 'hcraes'  // search
})

verified.venues.page.ts:

@IonicPage({
  name: 'VerifiedVenuesPage',
  segment: 'verified-venues',
  defaultHistory: ['SearchPage']
})

So I can open a page directly, like: http://localhost:8100/#/sbat/search-tab/verified-venues