Using App Shell to Improve Performance – Angular 6

| By Maina Wycliffe | | | Angular

Subscribe for more content from me

Angular apps take time to show meaningful content to the user. This time is mainly after loading the index.html page and bootstrapping the app. This is especially worse on lower end devices or slower networks, where it takes longer to get the all files required to bootstrap the app. It is therefore important to show some animation or an app shell, to indicate to the user that your web app is not broken. When it takes longer to paint something on the web page, most users will likely leave your app, most likely for a competitor. And we all want to avoid that.

There are several ways around this, the first one, is using a simple loading animation, indicating to the user something is happening on the background. And the second option, is loading the app shell – title bar, navigation etc. of the app, then some animation where the data will be placed after bootstrapping. Let’s first look at the loading animation, and then the app shell option:

Using a Simple Loading Animation/Message

This is the easiest option, it involves using CSS and html to create an animation or print a message to the user, as they wait for the app to load and bootstrap. This is important, as it indicates to them, that something is happening in the background instead of a blank page. Achieving this is rather straightforward, open the index.html file, under the src directory in the root of your angular workspace. Add the animation code in between <app-root> </app-root> tags. Why here? This is because, after the app has successfully bootstrapped, it will replace the content in between with the application itself. So, our animation code will look something like this:

<app-root>
  <div class="text-center bg-primary p-2" style="height: 100vh;">
    <div class="container align-middle p-5">
      <i class="fa fa-spinner fa-spin fa-3x"></i><br />Loading ...
    </div>
  </div>
</app-root>

I am using font-awesome and bootstrap for this demo, so remember to add the minified CSS imports at the header section.

<link
  rel="stylesheet"
  href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
  integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
  crossorigin="anonymous"
/>
<link
  rel="stylesheet"
  href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"
  integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU"
  crossorigin="anonymous"
/>

And this is what it looks like: Using App Shell to Improve Performance – Angular 6 NB: You  can make it lighter and easier to load by using pure CSS to load the animation, instead of using Bootstrap and Font Awesome, which is overkill for a simple animation. But if you are using both of these libraries somewhere else, this is a great way to load them and keep them outside your final angular bundle.

Using an App Shell

Now, let’s take the above process a step further. We can use angular cli to generate an app shell for a specific route. An app shell is the skeleton of an app – navigation, title bar, menu etc. In angular, you can prerender a specific route, to create an app shell which will be show to the user as they wait for the to bootstrap. This will include all components, in between the app-root and the router outlet of the prerendered route. The component to be loaded in the router-outlet is then replaced by the app shell component, this component is where you would add a loading animation or message.

NB: Unfortunately, as far as I can tell from my own research, you can only create for one route in an angular project. So, let’s first generate an app shell for our application, using the ng generate app-shell command:

$  ng generate app-shell --client-project angular-app-shell-demo --universal-project angular-app-shell-demo-rendered

Where: client-project is the project you want to generate the app shell for. And --universal-project is the name of server app or universal app, the option we will use to prerender our app shell. You may also want to include a --route, if you don’t want to create an app shell for the default route.

Changes to your Angular Project

When you run the above command, it makes some changes to your angular application. If you look at angular.json, you will see a few modifications:

...
"server": {
  "builder": "@angular-devkit/build-angular:server",
    "options": {
      "outputPath": "dist/angular-app-shell-demo-server",
      "main": "src/main.server.ts",
      "tsConfig": "src/tsconfig.server.json"
      }
    },
"app-shell": {
   "builder": "@angular-devkit/build-angular:app-shell",
   "options": {
     "browserTarget": "angular-app-shell-demo:build",
     "serverTarget": "angular-app-shell-demo:server",
     "route": "shell"
   },
  "configurations": {
    "production": {
      "browserTarget": "angular-app-shell-demo:build:production"
    }
  }
}
...

Another key change to take note of, is the component generated - AppShellComponent. This is a normal component, apart from the fact that it is registered with Server Module instead of the App Module. The Server Module was also generated by the generate app-shell command and can be found in the same directory as the app module.

Building your Angular Application

To build our application with an app shell, all you have to do is run the following command:

$ ng run angular-app-shell-demo:<app-shell-name>

Replace the <app-shell-name> with the name of the app shell name, you specified when generating the app shell. This will first prerender the path, and then build your angular app just as normal. But, if you look at your final index.html, you will notice it has extra content, unlike a normal one:

<app-root _nghost-sc0="" ng-version="6.1.9">
  <div _ngcontent-sc0="" class="container">
    <nav _ngcontent-sc0="" class="navbar navbar-light bg-light">
      <a _ngcontent-sc0="" class="navbar-brand" href="#"
        ><img
          _ngcontent-sc0=""
          alt=""
          class="d-inline-block align-top"
          height="30"
          src="/docs/4.1/assets/brand/bootstrap-solid.svg"
          width="30"
        />
        My Application
      </a>
    </nav>
    <router-outlet _ngcontent-sc0=""></router-outlet>
    <app-app-shell _nghost-sc1="">
      <div _ngcontent-sc1="" class="row">
        <div _ngcontent-sc1="" class="col-12 text-center">
          <i _ngcontent-sc1="" class="fas fa-spinner fa-spin"></i> Loading
          application
        </div>
      </div>
    </app-app-shell>
  </div>
</app-root>

All the above content is pulled from all components content right up to the router-outlet of the path. So, any modification you make to the components, will be reflected to the app shell when you build the application. This is certainly better than the first option of adding a loading animator directly to the index.html. To view the app shell, all you have to do is navigate to the route you generated for the app shell. In our case it was the default route, so navigating to it, you will see loading message from the app shell component, before being replaced by the actual content from the message. Using App Shell to Improve Performance – Angular 6

Source Code

You can find the source code of the app shell here.

Angular Hidden Treasures – Features you might know About

In this post, we are going to look at four important features in angular that can help you during your app development life cycle. These …

Read More
Angular 6 - Angular CLI Workspaces

One of the least talked about features of Angular 6 is Angular CLI Workspaces. Workspaces or Angular CLI Workspaces give angular …

Read More
How to upgrade your Angular 4 App to Angular 5.0

Angular 5 was finally released earlier this week after several delays. It brings a lot of improvements over Angular 4 and new features as …

Read More
Angular 5 has been released

Angular 5 was finally released after several delays yesterday, November 1, 2017. It was also accompanied by Angular CLI 1.5. This is a …

Read More
Role Based Authorization in Angular – Route Guards

In this post, we are going to use Route Guards to determine which user can and can not access certain pages. It is common to have multiple …

Read More
Docker Compose - Angular Multi Environment Deployments

In a previous post, we covered how to use multiple dockerfile to target different environments for an angular app. In this post, we are …

Read More

Comments