You're here because you want to learn how to improve the angular performance of your web application. Your client would like to see the app load quickly on their rusty computers and you're not sure what you should do.

You're in the right place.

You might measure size improvements in megabytes and performance improvements in milliseconds.

Large applications will benefit most. But, small applications will see significant angular performance improvements too.

Improving the Performance of Your Angular Application with Optimization

By the end of this article, you're going to know the exact steps you need to take to improve your app's angular performance.

Before proceeding, if you're on an older version of Angular, you should upgrade to to v4. You'll experience significant angular performance improvements simply by upgrading.

If you're already on Angular v4, we're going to focus on these two strategies -

AoT - Ahead of Time Compiling Tree Shaking

How Your App Compiles

Let's take a quick look at how Angular compiles your code.

Inputs - The code you write using components, templates, services and Angular stuff. Parsed Code - The compiler parses inputs and generates an Abstract Syntax Tree. Transformed Code - It then converts the AST into a browser readable format. Instantiation - The browser creates the DOM elements using the transformed code.

If you want to learn more about compiling you check out this talk by Tobias Bosch (he's written most of Angular's compiler).

JIT vs AoT

Depending on where the first three steps take place, the code is compiled using either of these two methods -

JIT - Just in Time Compiling

This means that all the 4 steps mentioned above take place in your browser. Your browser makes sense of plain Angular code and renders the DOM elements.

That means that every browser that runs your code has to spend time making sense of it first. It DOES NOT run the code directly.

AoT - Ahead of Time Compiling

If you're using AoT, you do the heavy lifting before any browser runs the code. That means - your server serves code that any browser can instantiate directly. That's where the speed improvements come from.

But that's only half the story.

With AoT, the browser doesn't have to know how to process your raw Angular code. That means - your browser does not need to download the compiler either.

Benefits of Using AoT to Improve Angular Performance

By using AoT, your application -

renders faster - because it does not have to compile the code before rendering it. sends less asynchronous requests - the compiler inlines the templates and CSS into JavaScript. is smaller - the browsers no longer need the compiler to run the code. can detect errors compile-time - otherwise, these errors would show up as runtime errors in the browser. is more secure - compiling beforehand reduces the number of injection opportunities by sending compiled templates.

Using AoT in Your Application

Let's take all this compiler knowledge and use it in our application.

Demo Application

For this tutorial, we have prepared a simple application for you to play with. You can run the application by following these instructions.

# Clone the repo

git clone https://github.com/Cartab/angular-aot-tutorial.git # Install the dependencies with yarn - https://yarnpkg.com/

yarn install # Run the code

ng serve



You can view the application on http://localhost:4200 in your browser.

You can use this application to search for users on GitHub and view their repositories.

The master branch contains code that is not compiled ahead of time. Check out the aot branch if you'd like to run the final version of the code.

git checkout --track origin/aot



How to Setup AoT Compilation for Angular Performance

Now we're going to fetch all the packages we need and take care of any config.

1. Download Required Packages

The two packages we need are -

@angular/compiler-cli - This gives us access to the ngc command (Angular's compiler). @angular/platform-server

If you're following along with the demo project, these are already installed. If you're following along for your own project, time to fetch them...

npm install @angular/compiler-cli @angular/platform-server --save



2. Create New Config File

We're going to use ngc to compile our files instead of tsc . ngc is a drop-in replacement for the TypeScript compiler.

ngc requires its own tsconfig.json . This is where we're going to set up all the AoT magic.

So let's create a new tsconfig file and call it tsconfig-aot.json . Now we'll add this code -

{

"compilerOptions": {

"target": "es5",

"module": "es2015",

"moduleResolution": "node",

"sourceMap": true,

"emitDecoratorMetadata": true,

"experimentalDecorators": true,

"lib": ["es2015", "dom"],

"noImplicitAny": true,

"suppressImplicitAnyIndexErrors": true,

"typeRoots": [

"./node_modules/@types/"

]

}, "files": [

"src/app/app.module.ts",

"src/main.ts"

], "angularCompilerOptions": {

"genDir": "aot",

"skipMetadataEmit" : true

}

}



There are two major things to pay attention to -

module (under compileOptions ) - We want es2015 modules (the import and export syntax). One of the tools we use later depends on these keywords for Tree Shaking. angularCompilerOptions - This is where we add the AoT settings -

- "genDir: "aot" - the directory to generate the build in.

- "skipMetadataEmit: true - we don't want the compiler to generate metadata files. These aren't necessary because we're working with TypeScript.

3. Update URLs in Component

AoT compilation needs relative URLs in the components. Our new URLs should look something like this.

@Component({

selector: 'app-home',

templateUrl: './home.component.html',

styleUrls: ['./home.component.css'],

})



4. Compiling Application Using ngc

We're going to add a script to package.json and use the ngc compiler.

"scripts": {

...

"build:aot": "node_modules/.bin/ngc -p tsconfig-aot.json"

}



We need to give ngc the flag to locate the tsconfig file with AoT configuration.

5. Building With AoT Compilation

Now let's create our first AoT build.

npm run build:aot



This will create an aot directory in the root of the project. This is one we specified in tsconfig-aot.json .

Within the aot directory, you'll notice .ngfactory.ts files in all the folders. These files create an instance of the component in the browser. They combine the class file and the JavaScript representation of the Component's template.

When the browser compiles these files (JIT), it generates them in memory. No wonder AoT compiling is so much faster!

But we're not done yet. One final step.

6. Creating Second Bootstrap File

The new bundle has a different structure so we need to bootstrap our application differently.

Let's create a copy of the main.ts file (I've called it main-jit.ts ). We'll need this file later to use JIT compilation in development.

Now let's update the main.ts file.

import { platformBrowser } from '@angular/platform-browser';

import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);



There are three things which are different here -

New Imports

- platformBrowser module instead of platformBrowserDynamic .

- AppModuleFactory from the aot build folder instead of AppModule directly.

2. Using platformBrowser - we no longer need the extra functionality provided by platformBrowserDynamic (template processing).

3. bootstrapModuleFactory - we're now bootstrapping a factory instead of a module.

7. Build Again

When you're done setting up AoT compiling you won't have to run the build process twice. We did this twice now so that you can understand where the factory files come from.

So let's run the build one more time.

npm run build:aot



Nice work! We've configured AoT compiling.

But there's no index.html ...! How are we going to run this code?

Setting Up Module Bundling and Tree Shaking

If you haven't worked with a module bundler in the past, then welcome to a new world of angular optimization.

Module bundlers allow us to process modules (and dependencies) and generate static assets.

We can also run several optimization processes such as tree shaking and minification.

Tree Shaking

Think of your application like this massive tree. It's composed of hundreds of branches (dependencies). But all the branches aren't connected (all dependencies aren't used).

So what do we do to get rid of these unnecessary branches?

We shake the tree!

Bundlers can analyse the imports and exports in our files to reveal exported modules that aren't imported. We can then get rid of these branches and reduce the size of our application.

We're going to use Rollup for module bundling and tree shaking. Let's do it!

1. Install Dependencies for Module Bundler

npm install rollup rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-uglify --save-dev



We're also installing some more dependencies - plugins. We'll use these plugins to optimize our build further.

2. Create Rollup Config File

Let's create the rollup.config.js file. This configuration file is from Angular's official documentation.

import nodeResolve from 'rollup-plugin-node-resolve';

import commonjs from 'rollup-plugin-commonjs';

import uglify from 'rollup-plugin-uglify'; export default {

entry: 'src/main.ts',

dest: 'src/build.js', // output a single application bundle

sourceMap: false,

format: 'iife',

onwarn: function(warning) {

// Skip certain warnings // should intercept ... but doesn't in some rollup versions

if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; } // console.warn everything else

console.warn( warning.message );

},

plugins: [

nodeResolve({jsnext: true, module: true}),

commonjs({

include: 'node_modules/rxjs/**',

}),

uglify()

]

};



This file tells rollup about the -

entry point - where to start bundling. destination - where to store the bundled files. plugins - additional rollup plugins that can help optimize the build further.

The plugins include -

uglify - this reduces the final file size by getting rid of white spaces and unnecessary characters. It minifies the code.

- this reduces the final file size by getting rid of white spaces and unnecessary characters. It minifies the code. commonjs - some libraries such as RxJS use commonJS module syntax module.exports . Rollup needs ES module export syntax with the keywords import and export for tree shaking. This plugin modifies RxJS to use the required syntax.

3. Build with Rollup

Let's add another command to our 'package.json' file

"scripts": {

...

"build:rollup": "node_modules/.bin/rollup -c rollup.config.js"

}



And now let's run the script.

npm run build:rollup



This will generate a build.js file in our source folder.

4. Update index.html

Now we're going to update the index.html file to use the build generated with AoT compiling.

Before doing that, let's create a copy and save it as index-jit.html . We'll use this very soon.

<!doctype html>

AngularAotTutorial

We've added a reference to build.js , styles.css . We're also importing the required shims and Bootstrap's CSS. In the JIT compiled version, Angular CLI did all this work for us.

5. Serve the Code

Now you can serve the build using your server. We're going to use lite-server for this demo. Let's install it.

npm install --save-dev lite-server



Add a script to our package.json .

"scripts": {

...

"serve:aot": "lite-server --baseDir="src""

}



And now we can serve the new build.

npm run serve:aot



Congratulations you now have an AoT compiled build running!

Using JIT and AoT Together

In development, it's not practical to compile the code every time you make changes.

That's why we're going to use both kinds of compiling. Sounds complex, but it's not.

For Angular CLI users, you can update .angular-cli.json file with these new values.

"index": "index-jit.html",

"main": "main-jit.ts",



Now you can use these commands to run your application in development and production.

# Development

ng serve # Production

npm run build:aot && npm run build:rollup && npm run serve:aot

If you're not using Angular CLI, you need to update the command you use during development. You also need to update your configuration files to use main-jit.ts and index-jit.html .

Now you'd use these commands.

# Development

npm run dev # Production

npm run build:aot && npm run build:rollup && npm run serve:aot

And we're done.

Conclusion

Let's compare the before and after.

Here's the before.

And here's the after.

Almost 1/2 the load and render times! That shows the power of AoT compilation. Imagine the performance improvements on larger angular applications when you start to optimize.

Now you know how to take your application to the next level with AoT compilation and Tree Shaking.

Share your results, questions, and suggestions in the comments below!