Angular App Shell Performance Results & How to add app shell to existing application

Angular App Shell

The angular app shell is a special technique to show very minimalistic content until the web browser downloads the actual content of the page, So how this matter? This technique helps in two ways, firstly it improves the customer experience by letting users know that web page is loading and secondly and the most important thing it reduces First Contentful Paint time drastically and hence it improves your page performance score.

After some in-depth research on performance improvements after adding app shell to an existing application, it is certain that App Shell really improved the performance results by 10-11% both in mobile and 5-6 % desktop tests

There are many questions asked around Angular App shell technique in the official Git Repo, So in order to help the community, Git repository has been added for the reference and hosted these applications in Heroku so that anyone can easily compare the results in PageSpeed Insights

Angular WITHOUT app shell

  1. Github Repo:https://github.com/allabouttech0803/universal-tutorial-without-app-shell
  2. Demo URL:https://universal-tutorial-woapp-shell.herokuapp.com/tutorials

Angular WITH app shell

  1. Github Repo:https://github.com/allabouttech0803/universal-tutorial-with-app-shell
  2. Demo URL:https://universal-tutorial-app-shell.herokuapp.com/tutorials

After performing multiple tests, indeed the application with App shell enabled wins by 13% extra in mobiles and wins by 4% extra in desktop, below are performance scores


Performance results of Angular Application WITHOUT App Shell

Performance results of Angular Application WITHOUT App Shell

Performance results of Angular Application WITH App Shell

Performance results of Angular Application WITH App Shell

So now if you want to enable the app shell to your existing application follow these steps to add app shell to your existing application

Step 1): Generate the the shell component by executing below command

ng generate app-shell

Step 2): You can notice that there are some changes in your workspace after running above angular schematics, such as there is a new entry in angular.json for app-shell and also majorly there is new file introduced named with app.server.module.ts as shown below, In fact, this is where all magic happens as you can see that there is new route is introduced with 'shell' and this will be pre-rendered during build time itself and displayed to the users until real content is loaded

Note: Currently there is a bug in Angular schematics generation, in case if you are using default route with path ** in app.routing.module.ts then app shell doesn't load hence as temporary fix we have to reset the route configuration in the constructor of app.server.module.ts hence we manually added the line this.router.resetConfig(routes);

ng run projectname:app-shell --configuration=production

Step 3): Then add the necessary view, you want to display in the app shell component and here major point to be noted that you should add very minimal HTML, CSS content so that browser loads app shell very quickly. The best option for this would be to add the spinner view in your app shell component so that it’s an indication to the users that the application is still loading. you can see we have added the HTML and CSS to view the app shell as below

Angular App Shell Live

Step 4): Then the most important thing is you need to build your application using below command, here you replace projectname string with your actual project name present in the angular.json

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';

import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { Routes, RouterModule, Router } from '@angular/router';
import { AppShellComponent } from './app-shell/app-shell.component';

const routes: Routes = [{ path: 'shell', component: AppShellComponent }];

@NgModule({
  imports: [
    AppModule,
    ServerModule,
    RouterModule.forRoot(routes),
  ],
  bootstrap: [AppComponent],
  declarations: [AppShellComponent],
})
export class AppServerModule {
  constructor(private router: Router) {
    this.router.resetConfig(routes);
  }
}

References: