What's new in Angular CLI 7.0?

Angular CLI 7.0.0 is out (in fact we even have a 7.0.1 available)!

If you want to upgrade to 7.0.1 without pain (or to any other version, by the way), I have created a Github project to help: angular-cli-diff. Choose the version you’re currently using (6.2.1 for example), and the target version (7.0.1 for example), and it gives you a diff of all files created by the CLI: angular-cli-diff/compare/6.2.1…7.0.1. It can be a great help along the official ng update @angular/core @angular/cli command. You have no excuse for staying behind anymore!

Let’s see what we’ve got!

Interactive prompts

One of the major additions to this version: the CLI now offers interactive prompts on several commands to let the developer choose some options or names.

For example, if you run ng new with CLI 7.0, then it asks you:

? What name would you like to use for the project?
? Would you like to add Angular routing? y/N
? Which stylesheet format would you like to use? (Use arrow keys)
❯ CSS
  SCSS   [ http://sass-lang.com   ]
  SASS   [ http://sass-lang.com   ]
  LESS   [ http://lesscss.org     ]
  Stylus [ http://stylus-lang.com ]

You can enter the name of the project, choose to add or not the routing support (with No as a default value if you just press Enter), and pick which CSS pre-processor you want, allowing to choose between CSS, SCSS, SASS, LESS and Stylus by using the arrow keys.

Note that all these options were already available, but you had to know the correct flags to add. For example ng new ponyracer --routing --style=scss.

If you don’t specify one of the options, a prompt will appear. You can of course deactivate this interactive mode, by using ng new ponyracer --no-interactive (no prompt at all), or ng new ponyracer --defaults (uses the default option of the prompt if it exists).

All the ng generate commands (component, service, pipe, etc.) will also ask for the name of the entity to generate if not provided.

You can add these prompts to your own schematics too. See how easy it is to add, for example in ng new.

Fun with flags!

A lot of flags have been added to various commands!

ng serve

A --verbose flag is now available for ng serve and ng build, displaying how much time each task took, how much each asset weighs, etc.

ng build

ng build now has a --profile flag.

It outputs two files:

  • chrome-profiler-events.json
  • speed-measure-plugin.json

The first one is a Chrome profile file, that you can load via the Performances tab in your Chrome Dev Tools. The second one is the result of the Speed Measure Webpack plugin and contains information about how much time each plugin took.

This is not really intended for us, but to help the CLI team improving some projects with long build times. If you are in this case, you can now offer proper information to the team about your build, and they might be able to speed things up in future releases.

The CLI README now also has a dedicated section to CPU profiling of your build.

ng generate

ng generate component now accepts --viewEncapsulation=ShadowDom to reflect the new view encapsulation option added in Angular 6.1.

ng new

We already talked about --no-interactive and --defaults, but ng new also earned a flag called --no-create-application. If you use it, the CLI will create a workspace with the NPM, TypeScript, TSLint and Angular CLI configurations, but with no application (so no src and e2e directories).

Along the same lines, a new flag called --minimal will generate a workspace with a project, but with the bare minimum: no unit tests or e2e tests, no TSLint either, and it uses inline styles and templates in components. This can be useful if you just want to setup a repository for a quick proof of concept.

ng test

The --reporters flag for the test command is back, after disappearing for a few versions. It allows to directly specify which reporters you want Karma to use, so it can be useful on a CI for example.

ng xi18n

You can now turn off the progress of the build when extracting the i18n messages with: ng xi18n --no-progress.

TypeScript 3.1 support

As Angular 7.0 now requires TypeScript 3.1 (check out our article about Angular 7), the CLI officially supports it too. This also includes a few optimizations in build-optimizer specific to Angular 7.0/TS 3.1.

Terser instead of UglifyJS

As uglify-es is no longer maintained and uglify-js does not support ES6+, the CLI team has moved to Terser for the minification phase of the build. Terser is a fork of uglify-es that retains API and CLI compatibility with uglify-es and uglify-js@3. It shouldn’t really change the results, but it fixes a few long standing issues with UglifyJS, like production builds that weren’t working in old Firefox ESR versions.

Configuration

In angular.json, you can now ignore certain files in your assets, with the brand new ignore option:

"assets": [
  {
    "glob": "**/*",
    "input": "src/assets/",
    "ignore": ["**/*.svg"],
    "output": "/assets/"
  },
],

On the polyfill side, the reflect-metadata polyfill (core-js/es7/reflect) is now only included in JiT mode, as it is not needed in AoT (production) mode. If you run ng update to update to 7.0, it should be automatically removed and your bundle will be a few kB lighter!

Talking about bundle sizes, a new application now has some “budgets” set by default:

budgets: [{
  type: 'initial',
  maximumWarning: '2mb',
  maximumError: '5mb',
}],

When you build your application, you’ll see a warning if the bundle is over 2MB, and an error if it is over 5MB. You can customize these limits of course (see our article about the CLI 1.7, the version that introduced budgets).

Performances

The CLI team released a new package (still experimental), called benchmark. The goal is to help benchmarking a NodeJS process, by measuring the time, CPU usage, memory usage, etc. So it’s not specific to the CLI itself. You can check out the README to learn more. The CLI team probably intends to track the performances of the various tools they are currently releasing, but maybe you can use it on your projects too.

.npmrc per project

You can now define one .npmrc file per project in your workspace, making it easier to deploy artefacts to your Nexus or Artifactory repository.

Breaking change

This is a small one, but worth noting: the CLI no longer inlines the assets less than 10kb in the CSS. If you had a small image, it used to be inlined directly in the generated CSS.

Eject is not coming back

As you may know, the CLI used to have an eject command, making it possible to customize the Webpack config directly (at the price of losing the CLI support). It was temporarily removed in CLI 6.0 due to the internal refactoring, but it will not come back. It will be removed completely in 8.0. The team thinks that the new configuration format provides enough flexibility to modify the configuration of your workspace without ejecting. They also mention ngx-build-plus if you want even more customization without ejecting.

That’s all for this release, I hope you enjoyed reading this blog post. Stay tuned !

All our materials (ebook, online training and training) are up-to-date with these changes if you want to learn more!


What's new in Angular 7?

Angular 7.0.0 is here!

Angular logo

Not a lot of new features in this release: the Angular team is mainly focused on the Ivy project, rewriting the Angular compiler and runtime code to make it smaller, better, faster. But Ivy is not ready for prime time yet.

So don’t expect a lot of shiny things in Angular 7.0: there was not enough material to make a video as we did for Angular 5 or Angular 6. This will be a short blog post for once, and a fast and easy upgrade for you!

TypeScript 3.1 support

One of the main new features is the support of TypeScript 3.1, which is the latest release! It is in fact mandatory to bump to TS 3.1 for Angular 7. Usually Angular lags a few releases behind, so it’s great to be able to use the latest TypeScript version for once! You can check out what was introduced in TypeScript 3.0 and TypeScript 3.1 on the Microsoft blog.

Angular compilation options

As you may know, you can define compilerOptions for TypeScript and angularCompilerOptions for Angular in your tsconfig.json files:

{
  "extends": "../tsconfig.base.json",
  "compilerOptions": {
    "experimentalDecorators": true,
    // ...
  },
  "angularCompilerOptions": {
    "fullTemplateTypeCheck": true,
    "preserveWhitespaces": true,
    // ...
  }
}

TypeScript allows you to extend the compilerOptions of another file (see the extends part in the example), but it was not doing anything with the Angular compiler options. The Angular compiler is now fixed, and you can define Angular compiler options in a base config, then extend them in another file. The options will be merged with the one defined in the inheriting config file, as they are for the TypeScript compiler options!

Ivy progress

The rewrite is making progress, but Ivy is still not usable in this release. If you refer to the official feature tracking, a good chunk of the work is done. But in reality, there is still a long way to go before we can use it.

Ivy has several pieces:

  • ngtsc: the compiler that compiles your Angular application and generates JavaScript from your HTML templates. This piece of code has made good progress but still misses a few features.
  • ngcc: a tool that explores all the dependencies you have, to convert existing code into “Ivy compatible” code. This is still very early stage, and barely usable at the moment if you don’t know how to workaround a few issues (Olivier and Pete from the Angular team were nice enough to help me).
  • the renderer itself, which takes the generated code and makes the magic happen at runtime. It still moves a lot, as new optimizations and new issues are found by the team.

Another part that is eagerly awaited is the support of “runtime i18n”. The implementation work has just started this week, so this is also far from being done.

I gave Ivy a few shots lately but it is definitely not ready for prime time yet. Internally at Google, the Angular team needs to migrate the huge number of projects they have to gather feedback and fix issues. So it will take a few more months.

But you can check it out yourself, as the CLI added an --experimental-ivy flag to generate an application with the configuration needed to try it.

ng new ivy-test --experimental-ivy
cd ivy-test
$(npm bin)/ngcc
ng serve --aot

Note that the change detection is not working as I’m writing these lines, so this is very limited right now :).

Slots with Angular Elements

It is possible to use ViewEncapsulation.ShadowDom since Angular 6.1, which is great for Angular Elements (Angular components packaged as Web components that you can use alone). But there was a missing feature to be able to use <slot>, a new standard HTML element, introduced by the Web Component specification. This feature is now available, enabling components with a template like:

@Component({
  selector: 'ns-card',
  template: `
    <header>
      <slot name="card-header"></slot>
    </header>
    <slot></slot>`,
  encapsulation: ViewEncapsulation.ShadowDom,
  styles: []
})
export class CardComponent {
}

That can later be used as an Angular Element like this:

<ns-card>
  <span slot="card-header">Become a ninja with Angular</span>
  <p>A wonderful book from Ninja Squad</p>
</ns-card>

Router

A new warning has been added if you try to trigger a navigation outside of the Angular zone, As it doesn’t work if you do so, Angular now logs a warning (only in development mode). This is pretty rare but can happen for example if you try to redirect your users when an error occurs in the application by providing a custom ErrorHandler (as the handleError method will run outside the ngZone to avoid a potential infinite loop). The warning looks like:

Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?

Sadly, this introduces warnings in your unit tests if you use the router in some of them, and looks like it’s an issue in Angular itself (see this issue if you want to add a thumb up).

Another internal work that we can’t really see has been the rewrite of the router to use a single Observable under the hood, that will automatically cancel the previous navigations. It will not affect you, but should fix a bunch of issues when multiple navigations were triggered at the same time and will allow new features more easily in the future.

Deprecations

As it’s usually the case with major releases, a few things have been deprecated. If you are using <ngForm> to declare a form in your template (you don’t have to, as form also activates the NgForm directive), this selector is now deprecated and should be replaced by <ng-form>.

As you can see, the release contains very few interesting features, but Ivy is making progress and Angular 8.0 will probably have more cool stuff!

In the meantime, the upgrade of your applications should be very easy.

All our materials (ebook, online training and training) are up-to-date with these changes if you want to learn more!


Angular Performances Part 5 - Pure pipes, attribute decorator and other tips

This is the last part of this series (check the first part, the second one, the third one and the fourth one if you missed them), and this blog post is about how you can improve the runtime performances of your Angular application with pure pipes, the attribute decorator and other tips. If you are the lucky owner of our ebook, you can already check the other parts if you download the last ebook release.

Now that we have talked about first load, reload, profiling and change detection strategies we can continue our exploration of the tips for better runtime performances.

Pure pipes

As you know, you can build your own pipes to format and display your data. For example, to display the full name of a user, you can either write a method in your component:

@Component({
  selector: 'ns-menu',
  template: `
      <p>{{ userName() }}</p>
      <p>...</p>
      <p>{{ userName() }}</p>
  `
})
export class MenuComponent {

  user: UserModel = {
    id: 1001,
    firstName: 'Jane',
    lastName: 'Doe',
    title: 'Miss',
  };

  userName() {
    return `${this.user.title}. ${this.user.firstName} ${this.user.lastName}`;
  }
}

or write a custom pipe to encapsulate this logic:

@Component({
  selector: 'ns-menu',
  template: `
      <p>{{ user | displayName }}</p>
      <p>...</p>
      <p>{{ user | displayName }}</p>
  `
})
export class MenuComponent {

  user: UserModel = {
    id: 1001,
    firstName: 'Jane',
    lastName: 'Doe',
    title: 'Miss',
  };
}

with DisplayNamePipe looking like:

@Pipe({
  name: 'displayName'
})
export class DisplayNamePipe implements PipeTransform {

  transform(user: UserModel): string {
    return `${user.title} ${user.firstName} ${user.lastName}`;
  }

}

This takes a little bit more work, but writing a pipe allows to reuse it in other components.

What you may not know is that using a pipe is also more performant. By default, a pipe is “pure”. In computer science, we call “pure” a function that has no side effect, and whose result only depends on its entries. A pure pipe is pretty much the same: the result of its transform method only depends on arguments. Knowing that, Angular applies a nice optimization: the tranform method is only called if the reference of the value it transforms changes or if one of the other arguments changes (yes, a bit like the OnPush strategy for components).

It means that whereas a method of a component is called on every change detection, a pure pipe will only be executed when needed, and only once in a template if it is used with the same input value and arguments (as in my example).

By default, a custom pipe is pure, so that’s great! But sometimes it’s not a right fit.

In my example, if we mutate the user to set its firstName to a different value, the pipe never refreshes… It’s pretty much the same issue that we had with the OnPush strategy: the reference of the value doesn’t change, so the pipe does not run again.

Here you have two solutions:

  • carefully use the pipe with immutable objects (do not mutate the user, create a new user with the new firstName);
  • mark the pipe as “impure”, and Angular will run it every time. You lose a tiny bit in performance, but you are sure that the displayed value is refreshed.

To mark a pipe as impure, just add pure: false in its decorator:

@Pipe({
  name: 'displayName',
  pure: false
})
export class DisplayNameImpurePipe implements PipeTransform {

  transform(user: UserModel): string {
    return `${user.title} ${user.firstName} ${user.lastName}`;
  }

}

To sum up:

  • a pure pipe is not called as often as a method in a component
  • but it doesn’t run again if the input value is mutated, so use carefully.

Split your template wisely

Based on what we learned, here is a trick that doesn’t use a specific Angular API, but can be easily understood.

Let’s say you have a component displaying a huge list of results, and an input allowing to update this list. As you don’t want to update the list on every key pressed, you are debouncing what the user types, and then update the list. Something like:

@Component({
  selector: 'ns-results',
  template: `
    <input [formControl]="search">
    <h1>{{ resultsTitle() }}</h1>
    <div *ngFor="let result of results">{{ result }}</div>
  `
})
export class ResultsComponent implements OnInit {

  search = new FormControl('');
  results: Array<string> = [];

  constructor(private searchService: SearchService) {
  }

  ngOnInit() {
    this.search.valueChanges
      .pipe(
        debounceTime(500),
        switchMap(query => this.searchService.updateResults(query))
      )
      .subscribe(results => this.results = results);
  }

  resultsTitle() {
    return `${this.results.length} results`;
  }
}

You may think that the change detection is not very often called, as you update the list only when the user has stopped typing. But in fact the change detection is called on every event in the template (so here on every key pressed). You can check it out by adding a simple console.log in resultTitle, and see it called in the developer console on every key pressed.

To avoid detecting change on the list elements even if not needed (as the results will not change on every new value, but only after some time), the idea is to split your view into two parts, and to introduce a sub-component to display the results. This component can be switched to OnPush and the change detection will only update it when really needed, and not on every key press.

@Component({
  selector: 'ns-results',
  template: `
    <input [formControl]="search">
    <ns-results-list [results]="results"></ns-results-list>
  `
})
export class ResultsComponent implements OnInit {

  search = new FormControl('');
  results: Array<string> = [];

  constructor(private searchService: SearchService) {
  }

  ngOnInit() {
    this.search.valueChanges
      .pipe(
        debounceTime(500),
        switchMap(query => this.searchService.updateResults(query))
      )
      .subscribe(results => this.results = results);
  }
}

With the sub-component looking like:

@Component({
  selector: 'ns-results-list',
  template: `
    <h1>{{ resultsTitle() }}</h1>
    <div *ngFor="let result of results">{{ result }}</div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ResultsListComponent {

  @Input() results: Array<string> = [];

  resultsTitle() {
    return `${this.results.length} results`;
  }
}

This is a simple pattern to use, often referred to as the smart/dumb component pattern: a smart component deals with data loading, event handling, etc., and simply passes the data to display as input to a second, dumb component. The only responsibility of the dumb component is to display the data, and to emit events to its parent smart component using outputs. This dumb component is the one with the large template, containing many expressions. But since its state only changes when its smart parent passes a new input, it can use OnPush and thus saves a lot of expression evaluations.

Attribute decorator

When using an @Input() in a component, Angular assumes that the value passed as input can change, and does what it takes to detect the change and pass the new value to the component. Sometimes, it’s not really necessary, as you may want to only pass a value once to initialize the component and never change it. In this very specific case, you can use the @Attribute() decorator instead of the @Input() one.

Let’s consider a button component, to which you want to pass a type to set its aspect (something like primary, success, warning, danger…).

Using an input, it would look like:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'ns-button',
  template: `
    <button type="button" class="btn btn-{{ btnType }}">
      <ng-content></ng-content>
    </button>`
})
export class ButtonComponent {

  @Input() btnType;
}

that you can use with:

<ns-button btnType="primary">Hello!</ns-button>
<ns-button btnType="success">Success</ns-button>

Since the input is a simple string that never changes, you can switch to use an attribute:

import { Attribute, Component } from '@angular/core';

@Component({
  selector: 'ns-button',
  template: `
    <button type="button" class="btn btn-{{ btnType }}">
      <ng-content></ng-content>
    </button>`
})
export class ButtonComponent {

  constructor(@Attribute('btnType') public btnType: string) {}
}

This produces a “bind-once” like effect, avoiding Angular to do unnecessary work. But keep in mind this only works with non-dynamic, string inputs.

Conclusion

This series of blog posts hopefully taught you some techniques which can help solve performance problems. But remember the golden rules of performance optimization:

  • don’t
  • don’t… yet
  • profile before optimizing.

As a famous computer scientist said:

Premature optimization is the root of all evil. - Donald Knuth

So strive to make the code as simple and correct and readable as possible, and only start thinking about profiling, then optimizing, if you have a proven performance problem.

If you enjoyed this blog post, you may want to dig deeper with our ebook, and/or with a complete exercise that we added in our online training. The exercise takes an application and walks you through what we would do to optimize it, measuring the benefits of each steps, showing you how to avoid the common traps, how to test the optimized application, etc. Check it out if you want to learn more!


Angular Performances Part 4 - Change detection strategies

This is the fourth part of this series (check the first part, the second one and the third one if you missed them), and this blog post is about how you can improve the runtime performances of your Angular application with change detection strategies. If you are the lucky owner of our ebook, you can already check the other parts if you download the last ebook release.

Now that we have talked about first load, reload and profiling we can continue our exploration of the tips for better runtime performances.

Change detection strategies

When we explained how Angular detects the changes in your application, we showed the tree of components and said that Angular starts by checking the root component, then its children, then its grand-children, until all components are checked. Then all the necessary DOM updates are applied in one batch.

But you may be wondering if it is a very good idea to check every component on every change. And you’re right, that’s often not really necessary.

Angular offers another change detection strategy: it’s called OnPush and it can be defined on any component.

With this strategy, the template of the component will only be checked in 2 cases:

  • one of the inputs of the component changed (to be more accurate, when the reference of one of the inputs changes);
  • an event handler of the component was triggered.

This can be very convenient when the template of a component only depends on its inputs, and can give a serious boost to your application if you display a lot of components on screen! But once again, be very cautious before applying this optimization: if the preconditions end up not being respected, you will lose your hairs wondering why the component (or any of its descendants) isn’t always repainting itself after a change.

Let’s take a small example to demonstrate.

Imagine that we have 3 components. A very simple ImageComponent:

@Component({
  selector: 'ns-img',
  template: `
      <p>{{ check() }}</p>
      <img [src]="src">
  `
})
export class ImageComponent {
  @Input() src: string;

  check() {
      console.log('image component view checked');
  }
}

used in a PonyComponent:

@Component({
  selector: 'ns-pony',
  template: `
    <p>{{ check() }}</p>
    <ns-img [src]="getPonyImageUrl()"></ns-img>
  `
})
export class PonyComponent {
  @Input() ponyModel: PonyModel;

  check() {
    console.log('pony component view checked');
  }

  getPonyImageUrl() {
    return `images/pony-${this.ponyModel.color}-running.gif`;
  }
}

used itself in a RaceComponent:

@Component({
  selector: 'ns-race',
  template: `
    <h2>Race</h2>
    <p>{{ check() }}</p>
    <div *ngFor="let pony of ponies">
      <ns-pony [ponyModel]="pony"></ns-pony>
    </div>
    <button (click)="changeColor()">Change color</button>
  `
})
export class RaceComponent {

  ponies: Array<PonyModel> = [{ id: 1, color: 'green' }, { id: 2, color: 'orange' }];
  colors: Array<string> = ['green', 'orange', 'blue'];

  check() {
    console.log('race component view checked');
  }

  changeColor() {
    this.ponies[0].color = this.randomColor();
  }

}

The RaceComponent displays two ponies, and the user can change the color of the first one by clicking on the Change color button.

With the current default change detection strategy, every time that we have a change in the application, all 3 components are checked.

We added a check() method in each component, called in each template: it allows us to track if the component is checked or not. And indeed in our example, we can see in our console:

pony component view checked
image component view checked
pony component view checked
image component view checked
race component view checked

(we can see that twice actually, because we are in development mode, see the section about enableProdMode above).

OnPush

But in this case, it’s a waste of time: we know that if the pony doesn’t change, the template of the PonyComponent doesn’t need to be checked. Same thing for the ImageComponent: if the src input is the same, there is no need to recompute the image URL. So let’s switch these components to OnPush, by adding a changeDetection attribute in their @Component decorator:

@Component({
  selector: 'ns-img',
  template: `
    <p>{{ check() }}</p>
    <img [src]="src">
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ImageComponent {
  @Input() src: string;

  check() {
    console.log('image component view checked');
  }
}

Same thing in PonyComponent:

@Component({
  selector: 'ns-pony',
  template: `
    <p>{{ check() }}</p>
    <ns-img [src]="getPonyImageUrl()"></ns-img>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PonyComponent {
  @Input() ponyModel: PonyModel;

  check() {
    console.log('pony component view checked');
  }

  getPonyImageUrl() {
    return `images/pony-${this.ponyModel.color}-running.gif`;
  }
}

When we click to change the color, we will only see in the console:

race component view checked

Which is awesome, because it means that we don’t check the components that we don’t need to check \o/.

OnPush and the mutability trap

But… there is a slight problem: the pony’s color doesn’t change any more!

I picked this example on purpose: even if OnPush is really powerful, it can be tricky and optimizing existing components is not only about adding a few OnPush here and there.

Why doesn’t it work in our case?

Take a closer look to our RaceComponent, and its changeColor method:

changeColor() {
  this.ponies[0].color = this.randomColor();
}

This method mutates the pony in the ponies collection, and this pony is the input of our PonyComponent. Now that we shifted our component to be OnPush, Angular will only run the change detection if the reference of the pony input changes. And when you mutate an object, it’s still the same object, so the reference doesn’t change, and Angular thinks there is no need to run the change detection…

So, is this change detection strategy completely useless? Not really, but it does require you to be more careful.

The simple way to fix our issue is to not mutate our pony in changeColor, but to create a new object:

changeColor() {
  const pony = this.ponies[0];
  // create a new pony with the old attributes and the new color
  this.ponies[0] = { ...pony, color: this.randomColor() };
}

Once you’ve done that, the application is faster and correct. If the user clicks on the button, the changeColor method creates a new pony object with the old attributes and the new color. As this is a new object, Angular will run the change detection in the PonyComponent (an input changed), and then the src input of the ImageComponent will also change, and the image will display the correct color. And, of course, if another event triggers the change detection in RaceComponent, the children component will not be checked (if their inputs did not change).

As you can see, you can quickly fall into a trap when migrating a component to an OnPush strategy, so be careful (unit tests are your friend).

One way to avoid this would be to use a library that enforces immutability. Immutable.js (by Facebook) is such a library. I’ve never used it professionally, so I can’t say if it’s a good fit in an Angular application or not, but you do see it mentioned often on the internets.

There is a last topic we need to talk about: observables.

OnPush, Observables and the async pipe

Let’s say we now have only one component, our well-known PonyComponent. It subscribes to an observable from a ColorService that returns a new color every second. We obviously expect the image displayed to change every second. The developer of this component thought that an OnPush change detection strategy couldn’t hurt. What do you think?

@Component({
  selector: 'ns-pony',
  template: `
      <p>New color every 1s</p>
      <img [src]="'pony-' + color + '.gif'">
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PonyComponent implements OnInit, OnDestroy {
  color = 'green';
  subscription: Subscription;

  constructor(private colorService: ColorService) {
  }

  ngOnInit() {
    this.subscription = this.colorService.get()
      .subscribe(color => this.color = color);
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }
}

Sadly, this doesn’t work. With the OnPush strategy, Angular only refreshes the template if one of the inputs changed (here, there is no input), or if an event was triggered (there is none either). So the color field is updated every second, but the template is never refreshed…

This can be fixed by using the pipe called async.

The async pipe can be used to subscribe to a Promise or an Observable. Let’s use it in our PonyComponent:

@Component({
  selector: 'ns-observable-on-push-with-async',
  template: `<img *ngIf="color | async as c"
                  [src]="'pony-' + c + '.gif'">`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PonyComponent {
  color: Observable<string>;

  constructor(colorService: ColorService) {
    this.color = colorService.get();
  }
}

Now our component is working! The async pipe will trigger the change detection when a new value is received. And you can see that we store the result of async to use it with as. It also frees us to subscribe to the observable in the component, and to remember to unsubscribe when the component is destroyed: async does it for us.

Note that async can lead to several HTTP requests if used several times in a template, and that you can use the “smart/dumb” component pattern to make it easier to use OnPush.

ChangeDetectorRef

There are a few last tricks regarding change detection that I want to show you. They are for more advanced use cases but, you never know, it can be handy one day.

Let’s take an hypothetical use case: you have an observable that emits data very very frequently. In my example, it’s a clock that emits every 10 milliseconds:

@Component({
  selector: 'ns-clock',
  template: `
      <h2>Clock</h2>
      <p>{{ getTime() }}</p>
      <button (click)="start()">Start</button>
  `
})
export class ClockComponent implements OnDestroy {

  time = 0;
  timeSubscription: Subscription;

  start() {
    this.timeSubscription = interval(10).pipe(
      take(1001), // 0, 1, ..., 1000
      map(time => time * 10)
    ).subscribe(time => this.time = time);
  }

  getTime() {
    return this.time;
  }

  ngOnDestroy() {
    this.timeSubscription.unsubscribe();
  }

}

The component uses the Default change detection strategy, so every time the observable emits a new value, the change detection is triggered, the template is refreshed and the clock value displayed is updated.

But, do we really need a hundred updates per second? Our eyes can’t see that fast, and it’s putting pressure on our browser for nothing. And remember that not only this component will be checked a hundred times per second, but the whole application too!

Maybe in that case it would be enough to refresh the time displayed every second for example. To do so, you can completely opt out from the automatic change detection in your component, and handle things yourself, by injecting in your component a ChangeDetectorRef. This class offers a few methods:

  • detach()
  • detectChanges()
  • markForCheck()
  • reattach()

The first two work together: you can indicate to Angular to not care about the component with detach and then manually call detectChanges when you want the change detection to run:

@Component({
  selector: 'ns-clock',
  template: `
    <h2>Clock</h2>
    <p>{{ getTime() }}</p>
    <button (click)="start()">Start</button>
  `
})
export class ClockComponent implements OnDestroy {
  time: number;
  timeSubscription: Subscription;

  constructor(private ref: ChangeDetectorRef) {
    this.ref.detach();
  }

  start() {
    this.timeSubscription = interval(10).pipe(
      take(1001), // 0, 1, ..., 1000
      map(time => time * 10)
    ).subscribe(time => {
      this.time = time;
      // manually trigger the change detection every second
      if (this.time % 1000 === 0) {
        this.ref.detectChanges();
      }
    });
  }

  getTime() {
    return this.time;
  }

  ngOnDestroy() {
    this.timeSubscription.unsubscribe();
  }

}

As you can see, we slightly changed the component to inject ChangeDetectorRef, detach the component from the change detection, and then manually run detectChanges() to trigger it when we need it (every second in our case). The time field is still updated a hundred times per second, but now the clock displayed to our users is only updated every second!

Note that this only triggers a change detection on that component (and its children) every time we run detectChanges().

But there is a way to go one step further, and completely handle it manually, by updating the DOM yourself (and not triggering a complete change detection):

@Component({
  selector: 'ns-clock',
  template: `
      <h2>Clock</h2>
      <p #clock></p>
      <button (click)="start()">Start</button>
  `
})
export class ClockComponent implements OnDestroy {
  time: number;
  timeSubscription: Subscription;
  @ViewChild('clock') clock: ElementRef<HTMLParagraphElement>;

  constructor(private ref: ChangeDetectorRef) {
    this.ref.detach();
  }

  start() {
    this.timeSubscription = interval(10).pipe(
      take(1001), // 0, 1, ..., 1000
      map(time => time * 10)
    ).subscribe(time => {
      this.time = time;
      if (this.time % 1000 === 0) {
        this.clock.nativeElement.textContent = `${time}`;
      }
    });
  }

  ngOnDestroy() {
    this.timeSubscription.unsubscribe();
  }

}

Here we grab a reference to the element we need to update, and then we update the DOM manually when needed, without triggering a change detection.

Another way to do this is possible: you can completely run the code outside of Zone.js, the library that triggers the change detection. To do so, you can inject NgZone, and then use its runOutsideAngular method to execute code outside of its scope:

constructor(private zone: NgZone) {
}

start() {
  this.zone.runOutsideAngular(() => {
    this.timeSubscription = interval(10).pipe(
      take(1001), // 0, 1, ..., 1000
      map(time => time * 10),
    ).subscribe(time => {
      this.time = time;
      if (this.time % 1000 === 0) {
        this.clock.nativeElement.textContent = `${time}`;
      }
    });
  });
}

This produces the same results, but here the rest of the component would still be checked automatically by Angular. runOutsideAngular is more suited to use cases where you want only specific portions of code to run out of the watch of Zone.js/Angular.

As I was saying, this example is a bit advanced, but ChangeDetectorRef can be handy for some use cases. Imagine that the example changing the color of a pony every second doesn’t use an observable, but a simple setInterval.

@Component({
  selector: 'ns-pony',
  template: `<img [src]="getPonyImageUrl()">`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PonyComponent implements OnInit, OnDestroy {

  @Input() ponyModel: PonyModel;
  private intervalId: number;

  ngOnInit() {
    this.intervalId = window.setInterval(() => {
      this.ponyModel.color = this.randomColor();
    }, 1000);
  }

  ngOnDestroy(): void {
    window.clearInterval(this.intervalId);
  }

No visual update… And in that case, we can’t use the async pipe as we did with an observable…

But we can use the markForCheck method of ChangeDetectorRef to manually trigger the change detection in an OnPush component:

@Component({
  selector: 'ns-pony',
  template: `<img [src]="getPonyImageUrl()">`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PonyComponent implements OnInit, OnDestroy {

  @Input() ponyModel: PonyModel;
  private intervalId: number;

  constructor(private ref: ChangeDetectorRef) {
  }

  ngOnInit() {
    this.intervalId = window.setInterval(() => {
      this.ponyModel.color = this.randomColor();
      this.ref.markForCheck();
    }, 1000);
  }

  ngOnDestroy(): void {
    window.clearInterval(this.intervalId);
  }

And it works again!

If you enjoyed this blog post, you may want to dig deeper with our ebook, and/or with a complete exercise that we added in our online training. The exercise takes an application and walks you through what we would do to optimize it, measuring the benefits of each steps, showing you how to avoid the common traps, how to test the optimized application, etc. Check it out if you want to learn more!

See you soon for part 5!


Angular Performances Part 3 - Profiling and runtime performances

This is the third part of this series (check the first part and the second one if you missed them), and this blog post is about how you can profile the runtime performances of your Angular application and how you can improve these runtime performances. If you are the lucky owner of our ebook, you can already check the other parts if you download the last ebook release.

Now that we have talked about first load and reload, we can start talking about runtime performances. But if you run into a performance issue, before trying any of the following tips, you should start by measuring and profiling the application.

Browsers nowadays offer nice developer tools, especially Chrome, which allows to record your application, and analyze its behavior with quite some details. You can even simulate some conditions, like using a slower processor, or using a 3G network. You can also dive into the call hierarchy, and see how much time each function call is consuming.

Profiling

But Angular also offers a precious tool: ng.profiler. It’s not very well-known, but it can be handy as it allows to measure how long a change detection run in the current page took.

You can then try to apply one of the tips we’ll see, and measure again to see if there is any improvement.

In your main.ts file, replace the application bootstrapping code with the following:

platformBrowserDynamic().bootstrapModule(AppModule)
  .then(moduleRef => {
    const applicationRef = moduleRef.injector.get(ApplicationRef);
    const componentRef = applicationRef.components[0];
    // allows to run `ng.profiler.timeChangeDetection();`
    enableDebugTools(componentRef);
  })
  .catch(err => console.log(err));

Then go to the page you want to profile, open your browser console, and execute the following instruction:

> ng.profiler.timeChangeDetection()
ran 489 change detection cycles
1.02 ms per check

You can see how many change detection cycles it ran (it should be at least 5 cycles or during at least 500ms), and the time per cycle. This is a super useful metric, as many of the tricks we are going to show you directly act on the change detection system. You’ll be able to try them, run the profiler again, and compare the results.

You can also record the CPU profile during these checks to analyze them with ng.profiler.timeChangeDetection({ record: true }).

The Angular team recommends to have a time per check below 3ms, to leave enough time for the application logic, the UI updates and browser’s rendering pipeline to fit within the 16 milliseconds frame (assuming a 60 FPS target frame rate).

Let’s discover these tips!

Runtime performances

Angular’s magic relies on its change detection mechanism: the framework automatically detects changes in the state of the application and updates the DOM accordingly. So, as a general rule of thumbs, you’ll want to help Angular and limit the change detection triggering and the amount of DOM to update/create/delete.

To be honest, most applications will be fine, even under heavy load. But some of us will have to recode Excel in the browser for their enterprise, or will have a component with a tree displaying 10,000 customers, or another unreasonable thing to do in a browser. These things are tricky, whatever framework you use. They tend to update a lot of DOM, and have to check a lot of components. A few of the following tricks can help. And a few of these tricks are really mandatory, like the first one.

enableProdMode

When you are in development mode (by default), Angular will run the change detection twice every time there is a change. This is a security to make sure you are not doing strange things, like updating data without following the one-way data flow. If you break the rules, Angular will warn you about it in development, by throwing an exception that will force you to fix your code. But if you are not careful, you will deploy the application in this mode, and change detection will still run twice, slowing your application.

To go in production mode, you need to call a function provided by Angular called enableProdMode. This method will disable the double check, and also make the generated DOM “lighter” (less attributes on the elements, attributes that are added to debug the application).

As usual the CLI got you covered, and the call to enableProdMode is already present in the generated application, wrapped in an environment check: if you build with the production environment, your app will be in production mode.

trackBy in ngFor

This is a simple tip that can really speed things up on *ngFor: add a trackBy. To understand why, let me explain how modern JS frameworks (at least all major ones) handle collections. When you have a collection of 3 ponies and want to display them in a list, you’ll write something like:

<ul>
  <li *ngFor="let pony of ponies">{{ pony.name }}</li>
</ul>

When you add a new pony, Angular will add a DOM node in the proper position. If you update the name of one of the ponies, Angular will change just the text content of the right li.

How does it do that? By keeping track of which DOM node references which object reference. Angular will have an internal representation looking like:

node li 1 -> pony #e435 // { id: 3, color: blue }
node li 2 -> pony #8fa4 // { id: 4, color: red }

It works great, and if you change an object for another one, Angular will destroy the node and build another one.

node li 1 (recreated) -> pony #c1ea // { id: 1, color: green }
node li 2 -> pony #8fa4 // { id: 4, color: red }

If the whole collection is updated with new objects, the complete DOM list will be destroyed and recreated. Which is fine, except when you just refresh a list with almost the same content: in that case, Angular destroys the complete node list and recreates it, even if there is no need to. For example, when you fetch the same results from the server, you will have the same content, but different references as your collection will have been recreated.

The solution for this use-case is to help Angular track the objects, not by their references, but by something that you know will identify the object, typically an ID.

For this, we use trackBy, which expects a method:

<ul>
  <li *ngFor="let pony of ponies trackBy: ponyById">{{ pony.name }}</li>
</ul>

with the method defined in the component:

ponyById(index: number, pony: PonyModel) {
  return pony.id;
}

As you can see, this method receives the current index and the current entity, allowing you to be creative (or simply track by index, but that’s not recommended).

With this trackBy, Angular will only recreate a DOM node if the id of the pony changes. On a very big list which doesn’t change much, it can save a ton of DOM deletions/creations. Anyway, it’s quite cheap to implement and doesn’t have cons, so don’t hesitate to use it. It’s also a requirement if you want to use animations. If a DOM element’s style is supposed to be animated (by transitioning smoothly from the previous value to the new one), and the list of ponies is replaced by a new one when refreshed, then trackBy is a must: without it, the animation will never happen, because the style of the element never changes. Instead, it’s the element itself which is being replaced by Angular.

We have more tips for you, but you’ll have to wait until next week to read about them!

If you enjoyed this blog post, you may want to dig deeper with our ebook, and/or with a complete exercise that we added in our online training. The exercise takes an application and walks you through what we would do to optimize it, measuring the benefits of each steps, showing you how to avoid the common traps, how to test the optimized application, etc. Check it out if you want to learn more!

See you soon for part 4!


The Gradle Kotlin DSL is now documented

More than 2 years ago, I wrote

Kotlin has also been announced as the future language of choice for Gradle, and I can’t wait to be able to use it for my Gradle builds.

It turns out I had to wait quite a bit. Using the Gradle Kotlin DSL is possible for some time now, but it was a bit of a frustrating experience due to the lack of documentation, to the point that I wrote a migration guide a few months ago.

As promised by the Gradle team, a much better, more complete, official migration guide now exists.

The huge, fantastic Gradle user guide, however, still only shows Groovy samples. But not for long. I’ve spent some time, along with other folks, translating all the samples of the user guide from Groovy to Kotlin. The result is already available in the Gradle nightly.

So you have no excuse anymore. Try the Kotlin DSL. It works, it is quite close to the Groovy DSL, but with less black magic involved, and it does allow auto-completion and navigation to the sources in IntelliJ.

Translating the samples has been a great experience. And it helped finding and fixing a few issues, too. Contributing to an open-source project you like and respect is always gratifying. You get the feeling that what you’re doing matters. Gradle folks have been nothing but kind, understanding, helpful, grateful… and demanding.

I didn’t just decide to contribute though. That’s always intimidating: where to start? How to get help? Will I help, or will I be a burden for the maintainers?

I contributed because the Gradle team asked me to. First after I wrote my migration guide, and after when they opened this epic issue, asking for help from contributors, and providing detailed instructions and examples on how to accomplish the task.

I wish more big open-source projects do that. Tagging issues with “ideal-for-contribution” is also nice. What might seem like grunt work for project maintainers or experienced contributors is an interesting challenge and learning experience for casual, less-experienced developers who are willing to help.

So, if you’re an open-source project maintainer and you read this, please make it easy to start contributing on your project. Ask for help. And communicate on public channels (blogs, tweets, etc.) about it. I’m apparently not the only one to have this opinion, so here is some more food for thoughts.


Angular Performances Part 2 - Reload

This is the second part of this series (check the first post if you missed it), and this blog post is about how you can speed up the reloading of an Angular application. In future posts, we’ll talk about how to profile your running application, and how to improve runtime performances. If you are the lucky owner of our ebook, you can already check the other parts if you download the last ebook release.

So, let’s assume a user visits your application for the first time. How to make sure that, when he/she comes back later, the application starts even faster?

Caching

You should always cache the assets of your application (images, styles, JS bundles…). This is done by configuring your server and leveraging the Cache-Control and ETag headers. All the servers of the market allow to do so, or you can use a CDN for this purpose too. If you do so, the next time your users open the application, the browser won’t have to send a request to fetch them because it will have them already!

But a cache is always tricky: you need to have a way to tell the browser “hey, I deployed a new version in production, please fetch the new assets!”.

The easiest way to do this is to have a different name for the asset you updated. That means instead of deploying an asset named main.js, you deploy main.xxxx.js where xxxx is a unique identifier. This technique is called cache busting. And, again, the CLI is there for you: in production mode, it will name all your assets with a unique hash, derived from the content of the file. It also automatically updates the sources of the scripts in index.html to reflect the unique names, the sources of the images, the sources of the stylesheets, etc.

If you use the CLI, you can safely deploy a new version and cache everything, except the index.html (as this will contain the links to the fresh assets deployed)!

Service Worker

If you want to go a step further, you can use service workers.

Service Workers are an API that most modern browsers support, and to simplify they act like a proxy in the browser. You can register a service worker in your application and every GET requests will then go through it, allowing you to decide if you really want to fetch the requested resource, or if you want to serve it from cache. You can then cache everything, even your index.html, which garanties the fastest startup time (no request to the server).

You may be wondering how a new version can be deployed if everything is cached, but you’re covered: the service worker will serve from cache and then check if a new version is available. It can then force the refresh, or ask the user if he/she wants it immediately or later.

It even allows to go offline, as everything is cached!

Angular offers a dedicated package called @angular/service-worker. It’s a small package, but filled with cool features. Did you know that if you add it to your Angular CLI application, and turn a flag on ("serviceWorker": true in angular.json), the CLI will automatically generate all the necessary stuff to cache your static assets by default? And it will only download what has changed when you deploy a new version, allowing blazing fast application start!

But it can even go further, allowing to cache external resources (like fonts, icons from a CDN…), route redirection and even dynamic content caching (like calls to your API), with different strategies possible (always fetch for fresh data, or always serve from cache for speed…). The package also offers a module called ServiceWorkerModule that you can use in your application to react to push events and notifications!

This is quite easy to setup, and a quick win for your reload start time. It’s also one of the steps to build a Progressive Web App, and to score a perfect 100% on Lighthouse, so you should check it out.

If you enjoyed this blog post, you may want to dig deeper with our ebook, and/or with a complete exercise that we added in our online training. The exercise takes an application and walks you through what we would do to optimize it, measuring the benefits of each steps, showing you how to avoid the common traps, how to test the optimized application, etc. Check it out if you want to learn more!

See you soon for part 3!


What's new in Angular CLI 6.2?

Angular CLI 6.2.0 is out (in fact we even have a 6.2.1 available)!

If you want to upgrade to 6.2.1 without pain (or to any other version, by the way), I have created a Github project to help: angular-cli-diff. Choose the version you’re currently using (6.0.0 for example), and the target version (6.2.1 for example), and it gives you a diff of all files created by the CLI: angular-cli-diff/compare/6.0.0…6.2.1. You have no excuse for staying behind anymore!

Let’s see what we’ve got!

Linter

The first thing is not really a new feature, but rather a bugfix, but it was annoying me, so I’m glad it landed!

With the previous CLI versions, if you ran ng lint, the linter was executed on every application in the project (usually your main application and the e2e application). Now, TSLint comes with a super awesome option called --fix, which automatically fixes some of the issues it found, I love it. And you can use it with the CLI! But running ng lint --fix was failing with the previous versions because it couldn’t figure if you wanted to run it on your main application or the e2e application… So you had to run ng lint app --fix and then ng lint app-e2e --fix.

This is now solved, and if you run ng lint --fix, the task will be executed on all your applications!

The fix is slightly more general than that, and this kind of command will now execute on all your applications if it is possible.

You can also now simply run:

ng lint src/app/app.component.ts

if you want to lint just a file.

To conclude this part about the linter, an option that disappeared in CLI 6.0 but existed before is also back: --lint-fix. This option can be used with every schematic, and will automatically fix the lint issues in the new generated files. You might be wondering why that would be useful: aren’t the files generated by the CLI already correct? They are indeed, but they use the default tslint.json. So if you have defined a different preference for TSLint for example to use double quotes instead of single quotes for strings, then by using this option, the generated files will automatically use your preferences.

ng generate component pony --lint-fix

Watch mode for libraries

As you hopefully know if you read our article about the release of Angular CLI 6.0.0, it is now possible to have multiple applications and libraries in your CLI project. But, as I noted in the article, a slightly annoying thing was that, when you made a change to the library source, you had to rebuild it manually if you wanted the rest of the project to see it, because there was no watch mode for ng build in a library.

That’s now no longer the case, and you can use ng build --watch for a library too, so the rest of your project will see the modifications without any manual steps anymore!

Ivy support

Angular 7 is still some weeks/months away, but the CLI is getting ready for the big novelty of this release: the new Ivy renderer (check out our previous article about Ivy).

You can give Ivy a try by generating a new application with:

ng new my-app --experimental-ivy

This will generate a new application with a few options activated for Ivy. It mainly adds in tsconfig.app.json:

"angularCompilerOptions": {
  "enableIvy": "ngtsc"
}

to activate Ivy. Be warned though, this is still very experimental!

That’s all for this small release, but the CLI team is already working on CLI 7.0, with some cool features incoming (an interactive prompt for the command, a better minifier, support of Angular 7…). Stay tuned !

All our materials (ebook, online training and training) are up-to-date with these changes if you want to learn more!


Angular Performances Part 1 - First load

We have just finished a new chapter of our ebook about performances, and we thought we could share it with you in a series of blog posts. It took us a long time, but we wanted to write something more complete than what you can usually find. There are a lot of tips to make Angular faster (whatever faster means for you, we’ll come back to this in a minute), but you usually don’t have the other side of the story: what are the traps of these optimizations, are they what you are looking for, and should you really use them.

This is the first part of this series, and this blog post is about the first load of an Angular application. In future posts, we’ll talk about how to make reloading faster, then about how to profile your running application, and how to improve runtime performances. If you are the lucky owner of our ebook, you can already check the other parts if you download the last ebook release.

Warning: be careful with premature optimization. Always measure before and after. Beware of the benchmarks you find on the internets: it’s pretty easy to make them say what the authors want.

Let’s start!

Performances

Performances can mean a lot of things: speed, CPU usage (battery consumption), memory pressure…​ Everything is not important for everybody: you have different needs if you are programming for a mobile website, an e-commerce platform, or a classic CRUD application.

Performances can also be split in different categories, that, once more, won’t all matter to you: first load, reload, and runtime performances.

First load is when you open an application for the first time. Reload is when you come back to that application. Runtime performances is what happens when the application is running. Some of the following advices are very generic, and could be applied to any framework. We wrote them because we think it’s worth knowing. And because when you talk about performances, the framework is sometimes the bottleneck, but really (really) often not.

First load

When you load a modern Web application in your browser, a few things happen. First, the index.html is loaded and parsed by the browser. Then the JS scripts and other assets referenced are fetched. When one of the assets is received, the browser parses it, and executes it if it is a JS file.

Assets sizes

So the first tip is very obvious: be careful with your assets sizes!

The assets loading phase depends on how many assets you want to load. A lot will be slow. Big ones will be slow. Especially if the network is not that good, which happens more often than you think: you might test your application on a fiber optic connection, but some of your actual users might be in the middle of nowhere, using slow 3G. Here is what you can do.

Bundle your application

When you write your Angular application, you have imports all over the place, and your code is split across hundreds of files. But you don’t want your users to load hundred of files! So before shipping your application, you want to make a “bundle”: group all the JavaScript files into one file.

Webpack’s job is to take all your JavaScript files (and CSS, and template HTML files) and build bundles. It’s not an easy tool to master, but the Angular CLI does a pretty good job at hiding its complexity. If you don’t use the CLI, you can build your application with Webpack, or you can pick another tool that may produce even better results (like Rollup for example). But be warned that this requires quite a lot of expertise (and work) to not mess things up, just to save a few extra kilobytes. I would recommend staying with the CLI. The team working on it is doing a very good job to keep up with the latest Angular, TypeScript and Webpack releases.

More than that, they built some tools to decrease the bundling size. For example, they wrote a plugin that goes through the generated JavaScript, and adds specific comments to help UglifyJS remove dead code.

Tree-shaking

Webpack (or the other tool you use) starts from the entry point of your application (the main.ts file that the CLI generated for you, and that you probably never touched), and then resolves all the imports tree, and outputs the bundle. This is cool because the bundle will only contains the files from your codebase and your third party libraries that have been imported. The rest is not embedded. So even if you have a dependency in your package.json that you don’t use anymore (so you don’t import it anymore), it will not end up in the bundle.

It’s even a bit smarter than that. If you have a file models exporting two classes, let’s say PonyModel and RaceModel, and then only import PonyModel in the rest of the application, but never RaceModel, then Webpack only puts PonyModel in the final bundle, and drops RaceModel. This process is called tree-shaking. And every framework and library in the JavaScript ecosystem is fighting hard to be tree-shakable! In theory, it means that your final bundle contains only what is really needed! But in practice, Webpack (and others) are a bit conservative, and can’t figure some stuff. For example, if you have a class Pony with two methods eat and run, but you only use run, the code of the eat method will be in the final bundle. So it’s not perfect, but it does a good job.

A few techniques can be used in Angular specifically to have a better tree-shaking. First, don’t import modules that you don’t use. Sometimes you give a try to a library offering a wonderful component, and you add the NgModule of this library to the imports of your NgModule. Then you don’t use it anymore, but maybe forget about the module import, and don’t remove it…​ Bad news: this module and the third party library will be in the final bundle (for now, maybe it will be better in the future). So only import and use what you really need.

Another trick is to use providedIn for your services. If you declare a service in the providers of your NgModule, it will always end up in the bundle whether you actually use it or not, simply because it’s imported and referenced in the module. Whereas if you don’t register in the providers of your NgModule, but use providedIn: 'root' instead, then if you never use this service, it will not end up in the bundle.

Minification and dead code elimination

When your bundle has been built, the code is usually minified and dead code will be eliminated. That means all variables, methods names, class names…​ are renamed to use a one or two characters name through the entire codebase. This is a bit scary and sounds like it could break things, but UglifyJS has been doing a great job for years now. UglifyJS will also eliminate dead code that it can find. It does its best, and I was saying above, the CLI team built a tool that prepares the code with special comments on unneeded code, so UglifyJS can remove it safely.

Other assets

While the above sections were about JS specifically, your application also contains other assets, like styles, images, fonts…​ You should have the same concerns about them, and do your best to keep them at a reasonable size. Applying all kind of crazy techniques to optimize your JS bundle sizes, but loading several MBs of images wouldn’t have a big impact on your page loading time and your bandwidth! As this is not really the scope of this post, I won’t dig into this topic, but let me point out a great online resource by Addy Osmani about image optimization: Essential Image Optimization.

Compression

All the modern browsers accept a compressed version of an asset when they ask the server for it. That means you can serve a compressed version to your users, and the browser will unzip it before parsing it. This is a must do because it will save you tons of bandwidth and loading time!

Every server on the market has an option to activate the compression of assets. Generally the first user to request an asset will pay the cost of the compression on the fly, and then the following ones will receive the compressed asset directly.

The most common compression algorithm used is GZIP, but some others like Brotli are also popular.

Lazy-loading

Sometimes, despite doing your best to keep your JS bundle small, you end up with a big file because your app has grown to several dozens of components, using various third party libraries. And not only this big bundle will increase the time needed to fetch the JavaScript, it will also increase the time needed to parse it and execute it.

One common solution to this problem is to use lazy-loading. It means that instead of having a big bundle of JavaScript, you split your application in several parts and tell Webpack to bundle it in several bundles.

The good news is Angular (its router, and its module system, in particular) makes this task relatively easy to achieve. The other good news is that the CLI knows how to read your router configuration to build several bundles automatically. You can read our chapter about the router if you want to learn more.

Lazy-loading can vastly improve the loading time, as you can make the first bundle really small, with only what’s needed to display the home page, and let Angular load the rest on demand when your user navigates to another part. You can also use prefetching strategies to tell Angular to start loading the other bundles when it’s idle.

Note that lazy-loading adds complexity to your application (and a few traps with dependency injection), so I would advise to go this way only if it really makes sense.

Ahead of Time compilation

In development mode, when you open the application in your browser, it will receive the JavaScript code resulting from the TypeScript compilation, and the HTML templates of the components. These templates are then compiled by Angular to JavaScript directly in your browser.

This is not optimal in production for two reasons mainly:

  • every user pays the cost of this template compilation on every reload;
  • the Angular compiler must be shipped to your users (and it’s big).

This process is called Just in Time compilation. But there is another type of compilation: Ahead of Time compilation. With this mode, you compile your templates at build time, and ship the resulting JavaScript with the rest of the application to your users. It means that the templates are already compiled when your users open the application, and that we don’t need to ship the Angular compiler anymore.

So the parsing and starting time of the application will be way better. And, on the paper, not shipping the compiler should lead to smaller bundles, and faster load times. But in fact, the generated JavaScript is generally far bigger than the uncompiled HTML templates. So the bundles tend to be bigger after an AoT compilation. The Angular team has been working hard on this, with big improvements in Angular 4 and Angular 6 (with its experimental Ivy project). If the bundles are still too big and slow your loading time, consider lazy-loading as explained above.

Server side rendering

I’d like to start by saying that this technique is for 0.0001% of you. Server side rendering (or universal rendering) is the technique that consists of pre-rendering the application on the server before serving it to the users. With this, when a user asks for /dashboard, she will receive a pre-rendered version of the dashboard, instead of receiving index.html and then let the router do its job after Angular has finished to start.

It can lead to vast improvements in perceived startup time. Angular offers a package @angular/universal that allows to run the application not in a browser but on a server (usually a NodeJS instance). You can then pre-render the pages and serve them to your users. The page will display very fast and then Angular will start its job and run as usual.

It’s also a big win if you want your web site to be crawlable by search engines which don’t execute JavaScript, since you can serve them pre-rendered pages, instead of a blank page.

It’s also a way to display previews of your website on social networks like Twitter or Facebook. These sites will try to screenshot the shared URL, but since they don’t execute JavaScript, they won’t see anything of your dynamically generated page, unless you serve them a page generated on the server. So if you want to be sure that the preview is perfect, like if you are running a news site, or an e-commerce site, you need to add server-side rendering.

The bad news is that it’s not as easy as adding the @angular/universal package. You application needs to follow some best practices (no direct DOM manipulation for example, as the server won’t have a real DOM to manipulate). Then you need to setup your server and think about the strategy you want to adopt. Do you want to pre-render all pages or just a few? Do you want to pre-render the whole page, with the data fetching and authorization check it will need, or just some critical parts of the page? Do you want to pre-render them on build, or to pre-render them on demand and cache them? Do you want to do this for all the possible profiles and languages or just some? All these questions depends on the type of application you are building, and the effort can vary greatly depending on your goal.

So, again, I would advise you to use server side rendering only if it is critical for your application, and not based on the hype…​

If you enjoyed this blog post, you may want to dig deeper with our ebook, and/or with a complete exercise that we added in our online training. The exercise takes an application and walks you through what we would do to optimize it, measuring the benefits of each steps, showing you how to avoid the common traps, how to test the optimized application, etc. Check it out if you want to learn more!

See you soon for part 2.


What's new in Angular CLI 6.1?

Angular CLI 6.1.0 is out (in fact we even have a 6.1.1 available)!

It is less feature rich than the previous releases: most of the work in this release consists in refactorings and bug fixes.

If you want to upgrade to 6.1.1 without pain (or to any other version, by the way), I have created a Github project to help: angular-cli-diff. Choose the version you’re currently using (6.0.0 for example), and the target version (6.1.1 for example), and it gives you a diff of all files created by the CLI: angular-cli-diff/compare/6.0.0…6.1.1. You have no excuse for staying behind anymore!

Let’s see what we’ve got!

Internal refactoring

Even if that’s not super useful to you as a developer, the devkit project (upon which the CLI relies a lot internally) is now in the same repository than the angular-cli project.

It used to be slightly painful to open issues and contribute code, because it was hard to figure out which repository the issue/code belonged to.

The angular/devkit repository has been archived, and imported back into the angular/angular-cli repository, which is now the only source of truth.

ES2015 modules everywhere

If you check angular-cli-diff/compare/6.0.0…6.1.1, you’ll see that one of the changes is that "module": "es2015" is now used in all tsconfig.json files. It means that we now have the same behaviour when serving/building/testing the app.

Vendor source map

A new option has been introduced called vendorSourceMap allowing to have source maps for vendor packages. You can use it with:

ng build --prod --source-map --vendor-source-map

This can be useful for debugging your production packages and see what is really included, thanks to source-map-explorer.

For example, this is with sourceMap only:

Source maps

and the same source maps built with vendorSourceMap:

Vendor source maps

This is all for this small release, except the support of TypeScript 2.8 and 2.9 and the support of Angular 6.1 of course. You can check out what’s new in Angular 6.1 in our previous blog post.

All our materials (ebook, online training and training) are up-to-date with these changes if you want to learn more!


Posts plus anciens