Buy more Angular online trainings for less money

We added a nice little feature to our ebook/online training sales platform: you can now buy more licenses at the discounted price you would have paid if you bought all of them at once!

For example, you bought 5 licenses at 686€ (because this is the discounted price for 5 licenses, instead of 995€). Now the rest of the team also wants to learn Angular, so you need to buy 5 more licenses to have 10. Until now it would also have cost you 686€ for these 5 extra licenses. But now it only costs 509€! Why 509? Because the discounted price for 10 licenses is 1195€, minus 686€, what you already paid, gives 509€!

You just have to buy with the same email you used previously, and the discount will be automatically applied. Or you can add licenses from the team management section you usually use to give licenses to your team members.

And it works even if you bought only one license until now: the second one you buy will cost you only 122€ instead of 199€!

Check out our ebook and online training to lean more.


What's new in Angular CLI 8.3?

Angular CLI 8.3.0 is out!✨

If you want to upgrade to 8.3.0 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 (7.2.1 for example), and the target version (8.3.0 for example), and it gives you a diff of all files created by the CLI: angular-cli-diff/compare/7.2.1…8.3.0. 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 in this release.

Deploy command

Th CLI has gained a new deploy command! In fact it’s a simple alias to ng run MY_PROJECT:deploy, and does really nothing out of the box. If you try it in your project, you’ll see the following message:

Cannot find "deploy" target for the specified project.
You should add a package that implements deployment capabilities for your
favorite platform.
For example:
  ng add @angular/fire
  ng add @azure/ng-deploy
  ng add @zeit/ng-deploy
Find more packages on npm https://www.npmjs.com/search?q=ng%20deploy

As you can see, you need to add a builder to your project, depending on the platform you are targeting. For example if you want to deploy to https://zeit.co/now, you can run ng add @zeit/ng-deploy which will automatically configure your project by adding the necessary configuration to your angular.json file and also create a now.json file. You can then simply run ng deploy when you want to build and deploy your application 🚀.

npm lists a lot of different builders, for example to deploy on Github. The builder builds your application and then pushes the result on the gh-pages branch of your repository.

Faster production builds

You have probably noticed that since the differential loading feature was introduced in Angular CLI 8.0 the production build now runs twice (once for the modern browsers, targeting ES2015, and once for the legacy browser, targeting ES5). The feature itself is really cool, but ng build --prod was effectively taking twice the time. Angular CLI 8.3 changes how the command runs:

  • the ES2015 version is built first
  • than the resulting bundles are directly downleved to ES5, instead of rebuilt from scratch

The larger your application is, the biggest gain you’ll see. I tried it in one of our projects:

  • with CLI 8.2: ng build --prod ran in 31,7s for ES2015 and 28,8s for ES5, for a total of 138s.
  • with CLI 8.3: ng build --prod ran in 32,0s for ES2015 and 🔥~10s🔥 to downlevel to ES5, for a total of 🔥98s🔥.

As this is brand new, if you experience an issue, you can still fall back to the previous behavior with NG_BUILD_DIFFERENTIAL_FULL=true ng build --prod for the moment.

Home page redesign

The home page of a newly generated project has completely changed, and it looks much nicer. It also includes helpful links to begin, and features some common commands.

Look at that 😍:

Angular CLI new home page

As you can see, this 8.3 release has some interesting new features!

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 8.2?

Angular 8.2.0 is here!

Angular logo

All hands are on deck to fix Ivy remaining issues, so not a lot to say for this 8.2 release 🙃. But let’s try nevertheless!

TypeScript 3.5

Angular 8.2 now supports TypeScript 3.5! 🌈

You can check out out what TypeScript 3.5 brings on the Microsoft blog.

ZoneJS 0.10.0

ZoneJS is now part of the main Angular repository, and has also been released in version 0.10.0. You can check out the changelog here.

Ivy Template Type Checker

Ivy has a more accurate template type checker, able to catch much more errors in your templates. But the first iteration was generating errors looking like:

__ng_typecheck__.ts:930:14 - error TS2551: Property 'scoe' does not exist on type 'ScoreComponent'. Did you mean 'score'?

__ng_typecheck__.ts is not part of my application, it was just a big file generated by the compiler to check all the templates. The problem is that the error didn’t give any clue about where the error was…

Now, in version 8.2, we do have proper source location ✨!

src/app/shared/score/score.component.html(1,29): Property 'scoe' does not exist on type 'ScoreComponent'. Did you mean 'score'?

Which is obviously wayyyy better. If you encountered this in a previous attempt to use Ivy, you can give it another go.

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 CLI 8.2?

Angular CLI 8.2.0 is out!✨

Of course this brings us the support of the brand new Angular 8.2 version, but also a lot of new features.

If you want to upgrade to 8.2.0 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 (7.2.1 for example), and the target version (8.2.0 for example), and it gives you a diff of all files created by the CLI: angular-cli-diff/compare/7.2.1…8.2.0. 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 in this release.

Component style budget

Angular CLI supports budgets, a feature to check that your generated bundles are not over a certain size, since version 1.7 (check out our explanation here).

A new budget, anyComponentStyle, has been added in version 8.2, allowing to check your component CSS sizes. This is a very nice feature because I’ve audited quite a few projects where there was no problem in the JS bundles, but where bad practices with CSS imports resulted in bloated CSS files. As component CSS are self-contained, it’s quite easy to make a mistake and import the whole Material or Bootstrap CSS into each component…

You can add this check to your existing budgets by adding the following configuration into angular.json:

"budgets": [
  {
    "type": "anyComponentStyle",
    "maximumWarning": "6kb",
    "maximumError": "10kb"
  }

You can of course adjust the thresholds, but this is the default configuration if you generate a new project. Or you can wait for the v9 release, and the automatic migration will add this configuration for you.

TypeScript configuration changes and build times

If you generate a new application with Ivy enabled, you’ll notice that the tsconfig.app.json file has slightly changed. We went from a configuration that was including every TS file, and excluding the specs:

"files": [
  "src/main.ts",
  "src/polyfills.ts"
],
"include": [
  "src/**/*.ts"
],
"exclude": [
  "src/test.ts",
  "src/**/*.spec.ts"
]

to this configuration, which only lists the entry point:

"files": [
  "src/main.ts",
  "src/polyfills.ts"
],
"include": [
  "src/**/*.d.ts"
]

You may wonder why this is interesting 😀. Well, with the former configuration and under certain conditions, the TypeScript compiler would sometimes pick up redundant files and cause slower builds! The new configuration might speed up the build/rebuild times for large projects!

So why is it not enabled for every project, but only in Ivy ones then? Because View Engine projects allow to lazy load modules with the “magic syntax”

loadChildren: './admin/admin.module#AdminModule'

that TS does not understand, whereas Ivy projects must use the new lazy-loading syntax

loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)

that TS understands. The compiler will pick up changes in the files of the lazy-loaded module as well in an Ivy project or a View Engine (VE) project using the new syntax, but would not be able to catch them in a VE project using the old syntax. You can thus give it try on your project, if you migrated to the new lazy-loading syntax introduced in 8.0.

Note that with this configuration, the compiler now warns you if a file is not used in the build. I spotted a few files that were not used anymore in some of our projects thanks to that new configuration 😅.

Speaking of build time improvements, the CLI is keeping up with the latest Webpack releases, and Webpack 4.38.0 has some really good improvements for rebuild times involving lazy-loaded chunks. If you have a large application with many lazy-loaded modules, you should definitely give a try to CLI 8.2.

index HTML file input/output

The angular.json config lets us configure where the index.html file is in our application. But before 8.2, the same name was used for the output file, which was not super flexible if you wanted to output a file not named index.html or in a different path. This is now possible by using:

index: { input: 'src/index.html', output: 'main.html' }

deferred scripts

The scripts generated by your application are now added to index.html with the defer attribute. This is not the case in the “modern” build, which uses script type="module" that are already deferred by default.

As you can see, this 8.2 release has some interesting new features!

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 8.1?

Angular 8.1.0 is here!

Angular logo

To be honest, not much to say for this 8.1 release 🙃. But let’s try nevertheless!

Ivy

As you may have understood if you read our last blog posts, Ivy is still a big part of the work done by the Angular team for this release. The plan is still to enable it by default in v9, with no regression if possible. As some users have been trying it since v8, the team is squashing bugs in corner cases, and tries to squeeze some perf improvements here and there. Some instructions were redesigned, the styles and animations APIs are getting a makeover: overall it looks good.

And I’m amazed at the amount of work the team has to do to make sure that none of the (thousands of) Google applications using Angular are broken. Which is good news for everybody in the community, because Ivy will have been thoroughly tested when it goes live!

Indexing API

A new package called indexer has been added to the Angular repository. Behind this mysterious name is an API to allow for generation of semantic analysis of components and their templates. So far the scope of the API is very limited, but the idea is to allow language analysis tools to more easily parse Angular templates.

Right now the indexer is targeted for internal Google usage if I understand correctly (with the language analysis tooling called Kythe). But we can hope to see tools built by the community that would use it and allows us to analyze our applications.

That’s all for Angular 8.1 🙂 You can check out our other article about the CLI 8.1 release which contains much more features!

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 CLI 8.1?

Angular CLI 8.1.0 is out!✨

Of course this brings us the support of the brand new Angular 8.1 version, but also a lot of new features.

If you want to upgrade to 8.1.0 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 (7.2.1 for example), and the target version (8.1.0 for example), and it gives you a diff of all files created by the CLI: angular-cli-diff/compare/7.2.1…8.1.0. 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 in this release, and start with new options for several commands.

Fun with flags

ng generate component –skip-selector

It is now possible to generate a component without a selector, by using the --skip-selector option. This can be handy when you are generating components that will only be instantiated dynamically, for example by the router. In that case, the component doesn’t really need a selector, so this option allows you to generate a component skeleton without one.

ng generate module –route

The module schematics can now take a --route option to indicate that you want to generate a lazy-loaded module. For example:

ng generate module admin --module users --route admin

will generate a new module AdminModule in its own directory, as it already previously did. But it will now also automatically add a route (here admin), to lazy-load this module in the (already existing in my example) users.module.ts:

export const USERS_ROUTES: Routes = [
  ...
  // automatically added by the schematic
  { path: 'admin', loadChildren: () => import('../admin/admin.module').then(m => m.AdminModule) }
];

@NgModule({
  imports: [CommonModule, ..., RouterModule.forChild(USERS_ROUTES)],
  declarations: [...]
})
export class UsersModule {}

Note that it also creates a new component AdminComponent, already registered in the route configuration of the new AdminModule:

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

@NgModule({
  declarations: [AdminComponent],
  imports: [CommonModule, RouterModule.forChild(routes)]
})
export class AdminModule { }

ng test –include

You can now specify a file or a directory when running ng test thanks to the new --include flag:

# all specs in src/app/admin/*
ng test --include app/admin
# just src/app/user.service.spec.ts
ng test --include app/user.service.spec.ts

You could already focus a test suite by changing the describe function to fdescribe or the it function to fit, but ng test was still rebuilding all your tests. By specifying --include, only the provided files are rebuilt, so it’s faster and doesn’t care if you have compilation errors in other files 🌈. And of course, you won’t forget to replace fdescribe by describe before committing anymore.

ng doc –version

ng doc is not very well-known but it is quite handy, as you can search the official documentation directly from your command line. For example ng doc component opens your browser to the search results for component on angular.io. The command now allows to specify a specific version to search, for example ng doc --version 6 component. It is also possible to use ng doc --version next to search the docs of the next Angular version. And if you don’t specify a version, the command now searches the docs for the Angular version you are using in your project (whereas it was looking in the docs of the most recent Angular version until now). I’m really happy about this tiny new feature, because it was the first open-source contribution of a developer I mentored during the HackCommitPush event in Paris! 🚀

ng build –cross-origin

You can now define the crossorigin attribute setting of elements that provide CORS support. 3 values are currently possible, very similar to what the official specification allows:

  • none which doesn’t do anything and is the default. CORS will not be used at all.
  • anonymous which automatically adds crossorigin="anonymous" to your scripts. There will be no exchange of user credentials via cookies, client-side SSL certificates or HTTP authentication, unless it is in the same origin. That still checks for the origin though.
  • use-credentials which automatically adds crossorigin="use-credentials" to your scripts, meaning that user credentials will be needed even if the file is from the same origin.

ng upgrade –allow-dirty

ng upgrade has now a new --allow-dirty option to allow updating when the repository contains modified or untracked files. Previously, trying to run ng upgrade in a project with unsaved modifications was always resulting in an error.

AoT by default for Ivy

The framework team has been working hard at squashing bugs in Ivy, and also improved the build mechanisms, resulting in faster AoT builds. The CLI team now considers that the performances with AoT and Ivy enabled are good enough to always serve your application with AoT enabled. If you generate a new project with --enable-ivy, you’ll see that the aot option in angular.json is now true by default. In their experiments, the CLI team found that the AoT builds with Ivy enabled were much faster than with View Engine, and pretty much on par with JiT builds. I gave it a try on one of our projects, and here are the results of how much time rebuilds are taking after a modification:

Ivy disabled, JiT mode: 190-250ms (initial 11.5s)
Ivy disabled, AoT mode: 630-1700ms (initial 11.8s)
Ivy enabled, AoT mode: 210-270ms (initial 13.0s)

So I have a slightly slower initial compilation, but then the AoT rebuilds are roughly as fast as the JiT rebuilds without Ivy✨!

TypeScript configuration changes

A side-note about the TypeScript configuration to conclude. If you check out the differences between version 8.0 and 8.1, you’ll notice that the tsconfig.json file lost the emitDecoratorMetadata option. This option was only needed for JiT development for the dependency injection (you can read an old blog post of mine about that). As it was only useful for that use-case, the CLI is now handling it itself when building your application in dev mode. So you can now remove this option from your project!

The default configuration now includes downlevelIteration, a TS compiler option to enable iterating over iterators. Check out this article if you want to have a better understanding of this option.

You will also note that two angularCompilerOptions are now enabled by default:

"angularCompilerOptions": {
  "fullTemplateTypeCheck": true,
  "strictInjectionParameters": true
}

The first one is one of my favorites, as it allows a deeper check of your templates. I explained this option when it was introduced in Angular 5.0. strictInjectionParameters errors when an injection type can’t be determined.

As you can see, this 8.1 release was packed with new features!

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


Proxies in JavaScript

ES2015 introduced a new feature called Proxy, allowing us to do some cool meta-programming code in our applications 🤓.

Basics

JavaScript always had some meta-programming capabilities. The use of get and set are a good example. If you have a basic object:

const pony = { name: 'Rainbow Dash' };

You can use:

console.log(pony.name);
// logs 'Rainbow Dash'

But you can also define a getter in your object, and do something every time the property is accessed. Even if, from the outside, it still looks like a simple property access:

const pony = {
  get name() {
    console.log('get name');
    return 'Rainbow Dash';
  }
};
console.log(pony.name);
// logs 'get name'
// logs 'Rainbow Dash'

But what if you want to do so on an existing object that you did not write yourself? Well, JavaScript offers Object.defineProperty since circa 2011:

const pony = { name: 'Rainbow Dash' };
Object.defineProperty(pony, 'name', {
  get() {
    console.log('get name');
    return 'Rainbow Dash';
  }
});

This is pretty cool, and lots of libraries and frameworks rely on this. Vue.js, for example, relies on this mechanism to trigger a re-rendering of the components displayed on a page, every time the state of one of the components is updated (this is a bit of a simplification but this is roughly the gist of it, see the source code of defineReactive if you want to learn more). To do so, the framework rewrites every property with a setter, that just sets the initial property, but also “warns” the framework that the property changed.

Object.defineProperty(component, 'user', {
  set() {
    this.user = user;
    heyVueAPropertyChanged(); // 🔥
  }
});

And it does this for every property declared when the component is initialized. This is cool, but doesn’t cover some very simple use cases. For example, adding a property to an existing object after initialization:

component.newProperty = 'hello';
// won't call heyVueAPropertyChanged() 😢

To support that case, Vue 2.x requires the usage of Vue.set(component.newProperty, 'hello'), which is not really intuitive, but does the job.

Object.defineProperty only works with objects, as the name says, and not with other types, like arrays. So again, in Vue 2.x, you can’t use myArray[3] = 'hello', because Vue won’t pick it up 😭 (see the official documentation).

Proxies to the rescue

This is where proxies, a new JavaScript feature adopted in the ES2015 specification, can be handy. 🌈

Proxies are a general computer-science concept that describes an intermediary between a caller and a callee. In ES2015, a proxy can target objects, but also arrays, functions, or… other proxies (but not other built-in types like Date).

const target = {};
const handler = {};
const uselessProxy = new Proxy(target, handler);

A nice thing here is that the type of uselessProxy is not Proxy but object (the type of the target). But there is no strict equality: uselessProxy === target; // false. The handler can do some smarter things, like ‘trapping’ properties:

const handler = {
  get(obj, prop) {
    console.log(`${prop} was accessed`);
    return obj[prop];
  }
};
const target = { foo: 'bar' };
const proxy = new Proxy(target, handler);
proxy.foo;
// logs 'foo was accessed'
// logs 'bar'

There are a lot of different traps available: get and set of course, but also has, apply, construct, defineProperty, deleteProperty, etc…

For Vue.js, this is very interesting, as proxies solve the issue of dynamic property added:

const handler = {
  set(obj, prop, value) {
    obj[prop] = value;
    console.log(`${prop} was updated with ${value}`);
  }
};
const target = { };
const proxy = new Proxy(target, handler);
proxy.foo = 'bar';
// logs 'foo was updated with bar'

That’s why Vue.js 3.0 will use Proxies instead of Object.defineProperty and will not need Vue.set (most probably, as Vue 3.0 is still a closed source prototype at the time of writing). And as mentioned, it also works for arrays, so myArray[3] = 'hello' will also be picked up by a proxy (and Vue 3).

Note that you can build revocable proxies with

const { proxy, revoke } = Proxy.revocable(target, handler);
revoke();
proxy.foo;
// TypeError: illegal operation attempted on a revoked proxy

Also note that proxies come with a performance cost. It’s always a bit hard to measure and compare, but it is still several times slower than defineProperty for setting a property for example. Nevertheless it would be possible to imagine proxies getting popular, especially in UI frameworks. Someone can imagine building a library for React that would avoid calling setState (and of course someone has) or not using ZoneJS in Angular, and use a proxy-based reactivity system. This was even considered by the core team, but declined.

We’ll see if Vue 3.0 bets on this, and how it comes of!


What's new in Angular 8.0?

Angular 8.0.0 is here!

Angular logo

A personal announcement first: I’m now officially part of the Angular team as a collaborator, in an effort from the core team to include more developers from the community. Angular 8.0 has a little bit more code of mine than the other releases 😊.

This release is mostly about Ivy and the possibility to give it a try, but it also includes a few features and breaking changes. Hopefully the update should be very easy, as the Angular team wrote a bunch of schematics that will do the heavy lifting for you.

TypeScript 3.4

Angular 8.0 now supports TypeScript 3.4, and even requires it, so you’ll need to upgrade.

You can checkout out what TypeScript 3.3 and TypeScript 3.4 brings on the Microsoft blog.

Ivy

Ivy is obviously a huge part of this release, and it took most of the effort from the team these last month. There is so much to say about Ivy that I wrote a dedicated article about it.

TL;DR: Ivy is the new compiler/runtime of Angular. It will enable very cool features in the future, but it is currently focused on not breaking existing applications.

Angular 8.0 is the first release to officially offer a switch to opt-in into Ivy. There are no real gains to do so right now, but you can give it a try to see if nothing breaks in your application. Because, at some point, probably in v9, Ivy will be the default. So the Angular team hopes the community will anticipate the switch and provide feedback, and that we’ll catch all the remaining issues before v9.

We tried it on several of our apps and already caught a few regressions, so we would strongly advise to not use it blindly in production 😄.

If you feel adventurous, you can add "enableIvy": true in your angularCompilerOptions, and restart your application: it now uses Ivy! Check our article and the official guide for more info.

Bazel support

As for Ivy, we wrote a dedicated article on how to build your Angular applications with the new Bazel support 🛠.

Bazel

Forms

markAllAsTouched

The AbstractControl class now offers a new method markAllAsTouched in addition to the existing markAsDirty, markAsTouched, markAsPending, etc. AbstractControl is the parent class of FormGroup, FormControl, FormArray, so the method is available on all reactive form entities.

Like markAsTouched, this new method marks a control as touched but also all its descendants.

form.markAllAsTouched();

FormArray.clear

The FormArray class now also offers a clear method, to quickly remove all the controls it contains. You previously had to loop over the controls to remove them one by one.

// `users` is initialized with 2 users
const users = fb.array([user1, user2]);
users.clear();
// users is now empty

Router

Lazy-loading with import() syntax

A new syntax has been introduced to declare your lazy-loading routes, using the import() syntax from TypeScript (introduced in TypeScript 2.4.

This is now the preferred way to declare a lazy-loading route, and the string form has been deprecated. This syntax is similar to the ECMAScript standard and Ivy will only support this.

So you can change your loadChildren declarations from:

loadChildren: './admin/admin.module#AdminModule'

to:

loadChildren: () => import('./races/races.module').then(m => m.RacesModule)

A schematic offered by the CLI will automatically migrate your declarations for you, so this should be painless if you run ng update @angular/cli. Check out our article about Angular CLI 8.0 to learn more about that.

Location

To help people migrating from AngularJS, a bunch of things have been added to the location services in Angular.

PlatformLocation now offers access to the hostname, port and protocol, and a new getState() method allows to get the history.state. A MockPlatformLocation is also available to ease testing. All this is really useful if you are using ngUpgrade, otherwise you probably won’t need it.

Service worker

Registration strategy

The service worker registration has a new option that allows to specify when the registration should take place. Previously, the service worker was waiting for the application to be stable to register, to avoid slowing the start of the application. But if you were starting a recurring asynchronous task (like a polling process) on application bootstrap, the application was never stable as Angular considers an application to be stable if there is no pending task. So the service worker never registered, and you had to manually workaround it. With the new registrationStrategy option, you can now let Angular handle this. There are several values possible:

  • registerWhenStable, the default, as explained above
  • registerImmediately, which doesn’t wait for the app to be stable and registers the Service Worker right away
  • registerDelay:$TIMEOUT with $TIMEOUT being the number of milliseconds to wait before the registration
  • a function returning an Observable, to define a custom strategy. The Service Worker will then register when the Observable emits its first value.

For example, if you want to register the Service Worker after 2 seconds:

providers: [
  ServiceWorkerModule.register('/ngsw-worker.js', {
    enabled: environment.production,
    registrationStrategy: 'registerDelay:2000'
  }),
  // ...
]

Bypass a Service Worker

It is now also possible to bypass the Service Worker for a specific request by adding the ngsw-bypass header.

this.http.get('api/users', { headers: { 'ngsw-bypass': true } });

Multiple apps on sub-domains

Previously, it was not possible to have multiple applications using @angular/service-worker on different sub-paths of the same domain, because each Service Worker would overwrite the caches of the others… This is now fixed!

Notable and breaking changes

A few things have changed and require some work from your part. Some of the changes are driven by Ivy, and are there to prepare our applications. But the cool news is that the Angular team already wrote schematics to make our life easier.

Simply run ng update @angular/core and the schematics will update your code. What do these schematics do? Let’s find out!

Queries timing

The ViewChild and ContentChild decorators now must have a new option called static. Let me explain why with a very simple example using a ViewChild:

<div *ngIf="true">
  <div #dynamicDiv>dynamic</div>
</div>

Let’s get that element in our component and log it in the lifecycle hooks ngOnInit and ngAfterViewInit:

@ViewChild('dynamicDiv') dynamicDiv: ElementRef<HTMLDivElement>;

ngOnInit() {
  console.log('init dynamic', this.dynamicDiv); // undefined
}

ngAfterViewInit() {
  console.log('after view init dynamic', this.dynamicDiv); // div
}

Makes sense as AfterViewInit is called when the template initialization is done.

But in fact, if the queried element is static (not wrapped in an ngIf or an ngFor), then it is available in ngOnInit also:

<h1 #staticDiv>static</h1>

gives:

@ViewChild('staticDiv') staticDiv: ElementRef<HTMLDivElement>;

ngOnInit() {
  console.log('init static', this.staticDiv); // div
}

ngAfterViewInit() {
  console.log('after view init static', this.staticDiv); // div
}

This was not documented, or recommended, but that’s how it currently works.

With Ivy though, the behavior changes to be more consistent:

ngOnInit() {
  console.log('init static', this.staticDiv); // undefined (changed)
}

ngAfterViewInit() {
  console.log('after view init static', this.staticDiv); // div
}

A new static flag has been introduced to not break existing applications, so if you want to keep the old behavior even when you’ll switch to Ivy, you can write:

@ViewChild('static', { static: true }) static: ElementRef<HTMLDivElement>;

and the behavior will be the same as the current one (the element is also accessible in ngOnInit).

Note that if you add static: true on a dynamic element (wrapped in a condition or a loop), then it will not be accessible in ngOnInit nor in ngAfterViewInit!

static: false will be how Ivy behaves by default.

To not break existing applications and to ease the migration, the Angular team wrote a schematic that automatically analyzes your application, and adds the static flag. It even offers two strategies:

  • one based on your templates, which will make sure that your application works (so it tends to mark queries as static even when they aren’t). You are sure it works, but it exposes you to problems if you wrap your static element in a condition or a loop later.
  • one based on your usage of the query, which is more error-prone (as it is harder for the schematic to figure it out), but will not mark the queries as static if they don’t need to be. So most queries will have static: false, which will be the default in Ivy.

The first strategy is used by default when you run ng update because it is the safest, but you can try the usage strategy by using NG_STATIC_QUERY_USAGE_STRATEGY=true ng update.

You can check out the official guide for more information.

This is what the migration looks like (with a failure in one component):

------ Static Query Migration ------
With Angular version 8, developers need to
explicitly specify the timing of ViewChild and
ContentChild queries. Read more about this here:
https://v8.angular.io/guide/static-query-migration

Some queries could not be migrated automatically. Please go
those manually and apply the appropriate timing.
For more info on how to choose a flag, please see:
https://v8.angular.io/guide/static-query-migration
⮑   home/home.component.ts@43:3: undefined

Note that this only concerns ViewChild and ContentChild, not ViewChildren and ContentChildren (which will work the same way in Ivy and View Engine).

Template variable reassignment

Currently with View Engine, doing something like:

<button
  *ngFor="let option of options"
  (click)="option = 'newButtonText'">{{ option }}</button>

works.

In Ivy, that won’t be the case anymore: it will not be possible to reassign a value to a template variable (here option). To prepare the switch to Ivy, a schematic analyzes your templates when you upgrade to Angular 8.0 and warns you if that’s the case.

You then have to manually fix it:

<button
  *ngFor="let option of options; index as index"
  (click)="options[index] = 'newButtonText'">{{ option }}</button>

DOCUMENT

The DOCUMENT token moved from @angular/platform-browser to @angular/common. You can manually change it in your application, but a provided schematic will take care of it for you.

Deprecated webworker package

The @angular/platform-webworker package enabled running your Angular application in a Web Worker. As this proved trickier than expected (for building the application, SEO…), and not that good performance-wise, the package has been deprecated and will be removed in the future.

Deprecated HTTP package removed

@angular/http has been removed from 8.0, after being replaced by @angular/common/http in 4.3 and officially deprecated in 5.0, 18 months ago. You have probably already migrated to @angular/common/http, but if you didn’t, now you have to: the provided schematic will only remove the dependency from your package.json.

You can also find all the deprecated APIs in the official deprecations guide.

That’s all for Angular 8.0! You can check out our other articles about Ivy, the CLI 8.0 release or the new Bazel support.

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 CLI 8.0?

Angular CLI 8.0.0 is out!✨

Of course this brings us the support of the brand new Angular 8.0 version, but also a lot of new features.

If you want to upgrade to 8.0.0 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 (7.2.1 for example), and the target version (8.0.0 for example), and it gives you a diff of all files created by the CLI: angular-cli-diff/compare/7.2.1…8.0.0. 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 in this release!

Angular 8 and TypeScript 3.4 support

This was obviously expected: Angular 8.0 is now supported, and even required, by the CLI. Note that as Angular 8.0 now requires TypeScript 3.4, you will need to also update your TypeScript version. You can checkout out what TypeScript 3.3 and TypeScript 3.4 brings on the Microsoft blog.

The CLI now also supports the new style of lazy-loading declarations using TypeScript import, introduced in Angular 8.0. It is even required if you want to use Ivy (see below).

So you can change your loadChildren declarations from:

loadChildren: './admin/admin.module#AdminModule'

to:

loadChildren: () => import('./races/races.module').then(m => m.RacesModule)

The import feature was introduced in TypeScript 2.4 and is similar to the ECMAScript standard. If you want to use import in your CLI project, you must enable it by using "module": "esnext" in the root tsconfig.json file.

If you updated your CLI version by running ng update @angular/cli you won’t even have to do it manually, as an update schematic will automatically take care of it for you!

Differential loading

This is one of the cool new features of the CLI 8.0.0 as it allows to specify which browsers you want to target, and the CLI will automatically build the necessary JS bundles with the required polyfills for your targets.

A first step was done in this direction with CLI 7.3 and its conditional ES5 browser polyfill loading. This release goes one step further.

The default target in tsconfig.json is now es2015 which means the default target of ng build is now the modern browsers that support ES6 features. But if you need to support older browsers like IE9, then you can specify it by using the browserslist file. This file already exists in your CLI project but was use for the CSS part only. It is now also used for the JS generation.

The default content is:

> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

You can check out the details on the browserslist repository, but a cool trick is to run:

npx browserslist

in your project to see what your current browserslist configuration actually means 🚀. Or you can also check browserl.ist and enter your query.

The CLI uses this configuration to generate only one “modern” build if you only target modern browsers, or build the application twice if you asked for IE 9-11 support for example. The dist directory then contains the same bundle twice after ng build --prod:

index.html
main-es2015.407919b7ee8dd339e9bc.js      // smaller version
main-es5.145b0a190c32187f268c.js         // slightly bigger one
polyfills-es2015.40c67a1b836fd165fb67.js // 43Kb
polyfills-es5.b96063cf2c012927fe18.js    // 110Kb
runtime-es2015.293c0dc955d5bcd5c818.js   // same size
runtime-es5.645890afb0d6a6596d07.js      // same size

The index.html file references all of them, but the es5 scripts are marked with the nomodule attribute, and the es2015 scripts have a type="module" attribute. The nomodule attribute indicates to modern browsers (that supports ECMAScript modules) to ignore this script, so they are not even fetched on modern browsers. And the older browsers will ignore the scripts with type="module". So each browser loads only what it really needs, with only older browsers downloading the extra JS needed.

The default configuration is the recommend one, and will trigger the two builds. You currently have to set a very restricted query to only have the es2015 build, like > 4% (to get rid of UC Browser for Android which is still used a lot).

Note that core-js has been updated to v3, and is now directly handled by the CLI itself, so it’s no longer needed as a dependency of your application. Also the property es5BrowserSupport introduced in CLI 7.3 is now unnecessary and has been deprecated.

dart-sass replaces node-sass

The CLI now uses dart-sass instead of node-sass to build your Sass files. The Dart implementation of Sass is now the reference implementation and has replaced the historic Ruby one. It is also notoriously faster.

It should not have an impact on the generated files, but there are some differences between the implementations and I heard that the compiler might be slightly stricter.

You can also install fibers if you want to speed things up (npm install --save-dev fibers). Vue CLI, which also recently migrated to dart-sass, mentions that the compilation can be twice as fast with fibers installed.

Note that all of this was already possible previously, but it is now the default, and is technically a breaking change. You can still use node-sass if you wish, by installing it explicitly.

Ivy support

You probably know that the main feature in Angular 8.0 is Ivy. You can checkout our dedicated article to Ivy to learn more The CLI provides a switch to give it a try. You can test it in a new project with:

ng new project --enable-ivy

Or in a existing project by adding the following option in your tsconfig.app.json file:

"angularCompilerOptions": {
  "enableIvy": true
}

When using Ivy, you need to compile your third party Angular modules with ngcc (the Angular Compatibility Compiler). This tool generates the code necessary to compile your application with Ivy enabled (by generating the ngComponentDef field, ngModuleDef field, etc. for each dependency you use).

But no need to worry about it, as the CLI now has a Webpack plugin that takes care of it for you! Your workflow will not change, even if behind the scenes the CLI does an extra-step for you when necessary.

If you give it a try, remember that the Ivy support is still quite new 😋.

Web worker support

This version provides a new generate schematic to add a Web Worker to one of your component. This can be handy if you want to delegate a computational heavy task to a dedicated thread in the browser instead of blocking the main one.

Let’s say that your PictureComponent (in src/app/picture) needs to do some CPU intensive work, like applying filters to an image.

You can run:

ng generate web-worker picture/picture

This will generate a new file called picture.worker.ts in src/app/picture, containing the following boilerplate code:

addEventListener('message', ({ data }) => {
  const response = `worker response to ${data}`;
  postMessage(response);
});

That’s where you would put your heavy code computation.

and adds this other boilerplate code to your PictureComponent:

if (typeof Worker !== 'undefined') {
  // Create a new
  const worker = new Worker('./picture.worker', { type: 'module' });
  worker.onmessage = ({ data }) => {
    console.log(`page got message: ${data}`);
  };
  worker.postMessage('hello');
} else {
  // Web Workers are not supported in this environment.
  // You should add a fallback so that your program still executes correctly.
}

to get you started.

The sample posts a simple string, but you can post an object or an array. It will be serialized and then deserialized so the worker receives a copy.

The schematic will also configure your CLI project if this is the first time you add a Web Worker. It will exclude the worker.ts files from your main TypeScript configuration, and add a new TypeScript configuration named tsconfig.worker.json that handles the worker.ts file. The angular.json file is also modified to add:

"webWorkerTsConfig": "tsconfig.worker.json"

Then, when you’ll run ng build, the CLI will package the Web Worker in a dedicated bundle (using googlechromelabs/worker-plugin).

Note that this is different from running Angular itself in a Web Worker via @angular/platform-webworker, which is not yet supported in Angular CLI.

Usage analytics data

The CLI can now collect usage analytics data. If you opt-in, some stats are collected and sent to the CLI team, to help them prioritize features and improvements. You can’t really miss this new feature, as you’ll be asked after installing the new CLI version globally 🧐.

You can opt-in with ng analytics on. A few metrics are collected if you opted in globally: command used, flags used, OS, Node version, CPU count and speed, RAM size, command initialization and execution time, and errors with their crash data if any occurs. If you opted-in in the project, it will even collect for build commands the number and size of your bundles (initial, lazy and total), the assets, polyfills and CSS sizes, and the number of ngOnInit in your code.

If you use ng update to update you CLI project, you will be asked about whether you want to collect and send analytics or not (or when you install the CLI globally).

Would you like to share anonymous usage data with the Angular Team at Google under
Google’s Privacy Policy at https://policies.google.com/privacy? For more details and
how to change this setting, see http://angular.io/analytics.

You can manually trigger the prompt again with ng analytics prompt. You can turn it off at any time with ng analytics off.

You can find more details on the official documentation.

I think this will be really helpful for the CLI team, as they’ll have a real insight about what’s going on in the real world (build time, test time, build sizes, etc.).

It is also possible to gather these usage analytics in your own Google Analytics, to see how your teams are using the CLI. This can be configured globally with ng config --global cli.analyticsSharing.tracking UA-123456-12. More information about that can be found here.

Project layout change

You’ll notice that the project layout changed quite a bit:

  • there is no more a dedicated project for e2e tests in the angular.json file
  • the tsconfig.*.json, karma.conf.js files have migrated to the root of the workspace, and the relative paths they contained were updated to reflect that.

SVG templates support

It is now possible to have a file with an svg extension as template (instead of only HTML previously). This was the first PR from @oocx and he detailed the feature himself in an article that you can check if you want to learn more.

Codelyzer 5.0

The default TSLint configuration loads additional rules from the excellent Codelyzer, which has recently been released in version 5.0. As this new version of Codelyzer renames some of its rules, the CLI offers a schematic to automatically update your TSLint configuration when you upgrade using ng update @angular/cli. Note that Codelyzer v5 also offers new rules and deprecated some, take a look at the changelog if you want to learn more.

The update schematic will also removes the es6 imports from your polyfills.ts file, as they are now added automatically if needed by the CLI (see our article about CLI 7.3).

NPM/PNPM support

After NPM and Yarn, The CLI now supports another package manager: PNPM.

Also note that the ng add command gained a new --registry flag, allowing to add packages from a private NPM registry (ng update already offered it).

New Architect API

This is just a note about the internals of the CLI. The Architect API, responsible for running pretty much everything under the hood, has been completely overhauled. Check out this blog post on the official Angular blog if you want to learn more about it.

As you can see, this 8.0 release was packed with new features!

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


Build your Angular application with Bazel

One of the new features of Angular 8 is the possibility to (more easily) build your CLI application with Bazel.

Bazel is a build tool developed and massively used by Google, as it can build pretty much any language. The Angular framework itself is built with Bazel.

Bazel

The key advantages of Bazel are:

  • the possibility of building your backends and frontends with the same tool
  • the incremental build and tests
  • the possibility to have remote builds (and cache) on a build farm

The second point is the most useful for most developers. Bazel allows you to declare tasks with clear inputs and outputs. Then when you run a command, Bazel builds a task graph, and only runs the necessary ones, depending on which inputs and outputs changed since the last run (very similar to what Gradle does in the Java world). This can bring impressive gains on rebuild times.

This talk by Alex Eagle at ng-conf 2019 can be interesting to learn more about what Bazel can do.

Be warned though: the first build will be painfully slow, as Bazel is aiming for exactly reproducible builds. For example, if you launch your tests on Firefox, it will download a complete version of Firefox, to make sure all developers are running the tests in the exact same browser! So if you want to launch the tests on a big project (like the Angular framework), you can go grab a coffee. But after this first build, a change in the codebase will only trigger the smallest rebuild possible. It’s especially useful if your application is made of several modules and libraries.

You can check out this slide deck from the Google team if you want to dive deeper into Bazel. You’ll learn how it works under the hood and how to do crazy stuff like querying the build graph, profiling your build, etc.

You have two options to give a try to Bazel with the CLI: in a new project or in an existing project.

Starting a new project with Bazel

The Angular team wrote a collection of schematics that you can install globally:

npm i -g @angular/bazel

and then you can use this schematic with Angular CLI to generate a new application already configured for Bazel:

ng new bazel-project --defaults --collection=@angular/bazel

The generated application is very similar to a “classic” Angular CLI project, with a few different files:

  • the angular.json file references builders from @angular/bazel to build, serve and test the application. Note that the classic angular.json file is backed up as angular.json.bak.
  • a script called protractor.on-prepare.js is added to configure Protractor in the e2e project.
  • a file called initialize_testbed.ts configures the unit tests (equivalent to the classic test.ts file).
  • the tsconfig.json file is slightly tweaked, and the original is backed up in tsconfig.json.bak.
  • a file called angular-metadata.tsconfig.json is added for the Angular compiler.
  • a file named rxjs_shims.js.
  • two files named main.dev.ts and main.prod.ts.

You won’t see any Bazel files added, and that might seems strange, but the CLI actually keeps them in memory. If at any time you want to go back, simply restore the .bak files and delete the new ones.

It also adds a bunch of dependencies to your application:

  • @angular/bazel, the Bazel builders for Angular CLI
  • @bazel/bazel, well, that’s Bazel
  • @bazel/ibazel, the Bazel watcher
  • @bazel/karma, the rules for testing with Karma and Bazel
  • @bazel/typescript, the rules for building with TypeScript and Bazel

Once the application is generated, you can use the usual commands: ng serve, ng test and ng build but now they use Bazel! Note that all commands run with AoT compilation, whereas in the “classic” CLI you have to turn it on explicitely.

Adding Bazel to an existing project

The Angular team created a schematic to ease the migration to Bazel if you want to test it:

ng add @angular/bazel

This backs up the existing configuration files and adds the files and dependencies mentioned in the previous section. Note that this is just a basic setup, and it’s very likely your project won’t build, because the schematic does not analyze your dependencies and assets. So you are going to need a few hours/days to properly configure it. Let’s see how.

Customizing the Bazel build

If you created your project from scratch or used ng add, you end up in the same situation: with a basic Bazel configuration. As soon as you are going to add another dependency, or if you already have some in your project, you’ll need to customize the build, because Bazel needs to be very explicit on what depends on what.

But as mentioned, the Bazel files are nowhere in sight! We need to make them appear in our project. For that, use the option leaveBazelFilesOnDisk, like:

ng build --leaveBazelFilesOnDisk

This will trigger a build and make the Bazel files (WORKSPACE, BUILD.bazel, .bazelrc and .bazelignore) appear. Now we can customize the build.

Adding a new dependency

If you look into BUILD.bazel, you’ll see the definition of ng_module:

ng_module(
    name = "src",
    srcs = glob(
        include = ["**/*.ts"],
        exclude = [
            "**/*.spec.ts",
            "main.ts",
            "test.ts",
            "initialize_testbed.ts",
        ],
    ),
    assets = glob([
      "**/*.css",
      "**/*.html",
    ]) + ([":styles"] if len(glob(["**/*.scss"])) else []),
    deps = [
        "@npm//@angular/core",
        "@npm//@angular/platform-browser",
        "@npm//@angular/router",
        "@npm//@types",
        "@npm//rxjs",
    ],
)

This is the declaration of an NgModule that includes all TS files except the test related ones, with assets including all CSS and HTML files (and SCSS files if there are some). The interesting part is the deps attribute. It lists every dependency, which can be NPM modules like here, or another ng_module of your app for example. This ng_module will only rebuild if:

  • one of the srcs or assets files changes
  • one of the dependencies changes

The most common task is to add a dependency to your project. For example, if you build a component that uses the forms support from Angular, then you need to list that dependency:

deps = [
    "@npm//@angular/core",
    "@npm//@angular/platform-browser",
    "@npm//@angular/router",
    "@npm//@angular/forms",
    "@npm//@types",
    "@npm//rxjs",
],

If you want to add an external Angular module, like ng-bootstrap, you must also add it to the deps attribute:

deps = [
    "@npm//@angular/core",
    "@npm//@angular/platform-browser",
    "@npm//@angular/router",
    "@npm//@angular/forms",
    "@npm//@types",
    "@npm//rxjs",
    "@npm//@ng-bootstrap/ng-bootstrap",
],

and include it into the angular-metadata.tsconfig.json, as the Angular compiler needs to build the external components:

"include": [
  "node_modules/@angular/**/*",
  "node_modules/@ng-bootstrap/ng-bootstrap/*"
],

It gets more complicated and cumbersome if you want to add a third-party library that doesn’t have the good taste to be packaged as Bazel would want to. For example, if you want to use Moment.js, you’ll need to add it to the dependencies as expected:

deps = [
    "@npm//@angular/core",
    "@npm//@angular/platform-browser",
    "@npm//@angular/router",
    "@npm//@angular/forms",
    "@npm//@types",
    "@npm//rxjs",
    "@npm//moment",
],

But after a ng serve, you’ll notice that moment.js is reported missing in the browser. In fact, you’ll need to manually configure require.js to load it! I warned you, we are far from the usual magic of the CLI that takes care of everything for us.

Add a require.config.js file into your project, with the following content:

require.config({
  paths: {
    'moment': 'npm/node_modules/moment/min/moment.min'
  }
});

and then add this file and moment.min.js in the ts_devserver rule:

ts_devserver(
    name = "devserver",
    port = 4200,
    entry_module = "project/src/main.dev",
    serving_path = "/bundle.min.js",
    scripts = [
        "@npm//node_modules/tslib:tslib.js",
        ":rxjs_umd_modules",
    ],
    static_files = [
        "@npm//node_modules/zone.js:dist/zone.min.js",
    ],
    data = [
        "favicon.ico",
        "@npm//node_modules/moment:min/moment.min.js",
    ],
    index_html = "index.html",
    deps = [
      ":require.config.js",
      ":src",
    ],
)

And now you have a working ng serve again.

Advanced customization

As you can see, it can take quite a bit of work to customize your project. Fortunately, you can get inspiration from a very good example project created by the Angular team: angular-bazel-example. It provides explanations and sources for the most common features. But some of them, like lazy loading, are quite painful to set up.

Bazel will reveal its full potential on big projects, where you have multiple modules and libraries depending on each others. In that case, the rebuild times will be greatly improved, as Bazel will analyze the graph and only rebuild what’s necessary. But it’s also in that case that the setup is going to take a lot of time.

It will probably be easier to setup in the future though, as the Angular team is still working on this. Bazel should reach 1.0 around September and we can hope for more auto-configuration (for setting up lazy-loading for example). Keep in mind that the Bazel build support is still considered an experiment, and has the “Labs” label. You can check out more resources on bazel.angular.io. At the time of writing, Bazel is impressive but still for the thrill seekers!

If you want to learn more about Angular, check out our (ebook, online training and training)!


Posts plus anciens