Lazy loading and deep linking with Ionic 3

April 14, 2017, 11:58 am Categories:

Categories

The team at Ionic recently upgraded the framework to version 3 which brings with it the following changes:

  • Updated to use Angular 4
  • Compatibility with TypeScript 2.1 and 2.2
  • Deep linking with the @IonicPage decorator
  • Ability to lazy load page components and pipes
  • Use of Semver versioning for framework releases

Unlike the leap from Ionic 1 to Ionic 2 though this transition is barely noticeable in comparison, so don't worry - you won't have to relearn everything from scratch!

Ionic 3, for the most part, will feel and act just like Ionic 2.

With that said we'll explore the following features of Ionic 3+ and see how they can be used within a sample project:

  • Deep linking with the @IonicPage decorator
  • Lazy loading

The case for lazy loading

Ionic 3+ allows developers the opportunity to organise their application into different modules and then "lazy load" those sections as and where required.

This means that page components and pipes can now be loaded on a section-by-section basis instead of being imported and declared within the application's root module and, afterwards, additionally imported into each page component where the developer wants to use that particular item.

Although optional (for now at least) this lazy loading approach provides the following benefits:

  • Decreased bundle sizes (as components and pipes are NOT being "front-loaded" through the application's root module)
  • Increased modularity - Components and pipes are organised into specific modules
  • Decreased application launch time - Component and pipe modules are ONLY loaded when and where required
  • Facilitates deep linking (we'll explore this in the next section)

How this all works is fairly straightforward.

When you generate a page component using the Ionic CLI you will see a component package structure akin to the following:

  • component-name.html
  • component-name.module.ts
  • component-name.scss
  • component-name.ts

The component-name.module.ts file uses Angular's NgModule class to handle which components, directives and pipes will be used by that particular component as well as making that component available for use by other parts of the Ionic application.

A default generated component module might look like the following:

import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { About } from './about';

@NgModule({
  declarations: [
    About,
  ],
  imports: [
    IonicModule.forChild(About),
  ],
  exports: [
    About
  ]
})
export class AboutModule {}

Let's break this down in further detail to understand exactly what is going on here.

We begin by importing Angular's NgModule class which allows module definitions to be created with the @NgModule decorator.

The IonicModule is imported (although you need to change this to IonicPageModule instead - read the IMPORTANT section below for information on why you need to do this) which allows this child page component to be bootstrapped for use and subsequently made available for routing.

The component class (About) itself is imported into the module then added to the declarations and exports section.

Further page components and/or directives and pipes can then be imported into this module making them automatically available for use in that component.

This, in a nutshell, is the basics of a component module.

Obviously there's a lot more we could do with this but I'll leave that for the subject of a future blog article.

IMPORTANT - At the time of writing you WILL need to change ALL references from IonicModule to IonicPageModule with these Ionic CLI generated components otherwise you end up with errors like the following when running the application:

about.module.ts, line: 10
           Property 'forChild' does not exist on type 'typeof IonicModule'.

      L9:  imports: [
     L10:    IonicModule.forChild(About),
     L11:  ],

Why the IonicPageModule isn't imported by default I don't know but just be aware of this bug otherwise you will end up scratching your head trying to figure out what's happening.

Hopefully this will be fixed in subsequent framework releases.

Now let's take a moment to look into the role of deep linking and then see how this ties into lazy loading our app content.

Deep linking

For those unaware deep linking makes it possible for a user to directly navigate to content buried deep within an app from an external source whether that be a web browser or another app.

Essentially deep linking is to Mobile apps what the hyperlink is to the website - content can be linked from and through different sources.

Previously this was, to put it mildly, somewhat cumbersome to implement but Ionic 3+ introduces the @IonicPage decorator specifically for this purpose.

Using the @IonicPage decorator is fairly straightforward.

When a new page component is generated using the Ionic CLI the following takes place:

  • The IonicPage module is imported from ionic-angular
  • The @IonicPage decorator is placed above the @component decorator for the class

This might look something like the following:

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-about',
  templateUrl: 'about.html',
})
export class About {
   ...
}

Although it may appear somewhat insignificant the @IonicPage decorator automatically creates a link to the About page component.

The About page can then be accessed from within our application by its class name like so:

@Component({
  selector: 'page-home',
  templateUrl: 'home.html',
})
export class HomePage {

  constructor(public navCtrl: NavController) {}

  navigateTo() 
  {
    // go to the About component
    this.navCtrl.push('About');
  }
}

Notice how the About class name is accessed as a string in the NavController push method?

This is by default although you do have the option to change the name for that link from within the @IonicPage decorator for that particular class - like so:

@IonicPage({
  name: 'about-this-app'
})

This change now creates a link to the About page that can be accessed in the following way:

navigateTo() 
{
   // go to the About component
   this.navCtrl.push('about-this-app');
}

This is great as it means we can, if we choose to do so, create keyword rich links (obviously a boon for SEO purposes) instead of simply using the class name.

As you might be aware there are further configuration options available for the @IonicPage decorator that we can additionally use with the above example but I'll explore those in a future blog article.

For now let's see how lazy loading and deep linking can work hand in hand...

Putting it all together

Now that we have an understanding of lazy loading and deep linking let's see how both of these work together in a sample Ionic 3+ application.

If you haven't upgraded to the latest version of the ionic framework run the following command from your system command line utility:

npm install -g ionic cordova

If you should run into permission related errors on Mac/Unix systems simply prefix the above command with sudo like so:

sudo npm install -g ionic cordova

With Ionic 3+ installed on your system create the following project from the command line:

ionic start sample-project blank

Once the project has been created change into its root directory:

cd sample-project

And generate the following assets:

ionic g page about
ionic g page contact

For the purpose of this tutorial we're not interested in the content or styling for the About and Contact page components only seeing how they can be lazy loaded and deep linked to.

To start this process create the following file - home.module.ts - within the sample-project/src/pages/home directory and populate this module with the following code:

import { NgModule } from '@angular/core';
import { HomePage } from './home';
import { IonicPageModule } from 'ionic-angular';

@NgModule({
  declarations: [HomePage],
  imports: [
    IonicPageModule.forChild(HomePage)
  ],
  entryComponents: [
    HomePage
  ]
})
export class HomePageModule { }

This simply imports and bootstraps the HomePage component for the application.

Now we need to edit the Home page component itself - sample-project/src/pages/home/home.ts - to import the IonicPage module and add its decorator like so:

import { Component } from '@angular/core';
import { IonicPage, Content, NavController} from 'ionic-angular';


@IonicPage({
   name: 'welcome'
})
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

Here we simply pass a custom name of welcome for the link to this page which now makes the HomePage component available for deep linking.

With the necessary page components and modules generated we need to make some slight tweaks to the following files:

  • sample-project/src/page/about/about.module.ts
  • sample-project/src/page/contact/contact.module.ts

And change all references from IonicModule to IonicPageModule instead.

This will hopefully be unnecessary in coming iterations of the Ionic framework but for now it's a step we need to take.

Lazy loading the Home page

Open the sample-project/src/app/app.component.ts file and change the following from this:

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { HomePage } from '../pages/home/home';
@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage:any = HomePage;

To removing the imported HomePage component and modifying the rootPage property to point to the welcome deep link - like so:

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage:any = 'welcome';

Next we need to modify the application root module - sample-project/src/app/app.module.ts - so that the HomePage component is no longer imported and NO references to the HomePage component are left in the declarations and entryComponents sections.

This should leave the root module looking like the following:

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';

import { MyApp } from './app.component';

@NgModule({
  declarations: [
    MyApp
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

If we were to run the application using the ionic serve command we should be able to see the Home page component being displayed in the browser like so:

Default Ionic home page template

Result!

We've just lazy loaded our Home page component, now let's do the same with the About and Contact pages.

Linking it together

Inside the About page component - sample-project/src/page/about/about.ts - add the following configuration to the @IonicPage decorator:

@IonicPage({
   name : 'about-this-app'
})

And within the contact page component - sample-project/src/page/contact/contact.ts - make the following configuration change to the @IonicPage decorator:

@IonicPage({
   name : 'get-in-touch-bro'
})

Now all we need to do is link to these pages from our Home page component.

Let's turn to the home page HTML template - sample-project/src/page/home/home.html - and spruce up the interface with the following code:

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Blank
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>

   <button
      ion-button
      block
      color="primary"
      (click)="navigateTo('about-this-app')">
         About this Application
      </button>


   <button
      ion-button
      block
      color="secondary"
      (click)="navigateTo('get-in-touch-bro')">
         Get In Touch
      </button>

</ion-content>

Here we simply replace the default content with 2 buttons, each of which contains a click event pointing to a navigateTo method.

As you can see this method accepts the name of the page links we want to navigate to:

  • about-this-app
  • get-in-touch-bro

In our component class we define the navigateTo method like so:

import { Component } from '@angular/core';
import { IonicPage, NavController } from 'ionic-angular';

@IonicPage({
	name : 'welcome'
})
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  constructor(public navCtrl: NavController) {

  }


  navigateTo(page)
  {
     this.navCtrl.push(page);
  }
}

Now if we run the ionic serve utility we should see the home page updated to display the following interface:

Modified Ionic home page template

Upon interacting with these buttons we should be able to navigate to the About and Contact pages like so:

Default About page template

Default Contact page template

Yes - they're pretty boring to look at but we're not interested in exploring the aesthetics of the application for this tutorial.

We're simply looking to implement lazy loading and deep linking and we've certainly achieved that with the above example!

In summary

Ionic 3 is a pretty gentle upgrade that introduces the IonicPage decorator and optional lazy loading functionality for developers to explore using within their applications.

As you can see from the above tutorial implementing both of these features is fairly simple and helps create apps that are both modular and present much richer navigation opportunities than were possible with previous versions of ionic.

I suspect that, after further refinements to the underlying framework logic, lazy loading will become the norm for developing Ionic applications but, for now, it's entirely optional.

I'll be exploring deep linking and modules in future tutorials but for now I hope the above tutorial proves useful in helping to guide your own development exploits.

Feel free to share your thoughts, findings or suggestions in the comment section below.

If you enjoyed what you've read here then please sign up to my mailing list and, if you haven't done so already, take a look at my e-book: Mastering Ionic for further information about using deep linking and lazy loading within Ionic.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top