Cool things we learned - part 2 - frontend edition

In the nearly 7 years of our company, we mostly worked on existing applications for our customers. But recently, we completed two projects from scratch for two French customers. We just completed the second one, a small Progressive Web Application for helping citizens to report issues in their city/street (think “Broken lamp” for example). We also built the backend part of the application, and a backoffice to allow the local governments (cities, groups of cities, regions…) to see the reported issues and handle them. This is not a new concept, but our customer is an organization that promotes open-source in French administrations. So this application is open-source and will hopefully be used by French citizen, as soon as the local administrations deploy it.

If you missed it, check out part 1 about the backend.

Let’s talk about the stack we used on the frontend and a few cool things we tried and learned.

Angular PWA

As you may have guessed, we used Angular on the frontend. The application is mainly targeted to mobile users, so the plan was to build a Progressive Web Application. It was the first “real” one we built, but it was super straight-forward, thanks to Angular and its @angular/pwa package. Basically, in a CLI project, you run ng add @angular/pwa, and… You’re done! You’ll need to customize the icons and colors to replace the default ones, and the CLI will then generate all the required files for a proper PWA. With this default setup, and the application served over HTTPS, our user are offered the possibility to add the application to their home screen. This is not the only perk: the application will also start very fast as the assets are cached for offline use.

We tried to push things a little further and used the SwUpdate service offered by the @angular/pwa package to display a notification to our users when a new version of the application is available. This is because the application is displayed right away from cache when a user loads it, and then the Service Worker checks if a new version is available. If that’s the case, SwUpdate.available emits a new event, and you can ask your user if he/she wants to refresh the page to use the new version. We had a weird issue, but we figured it out, and, as good open source citizens, we documented it 😉.

Leaflet and ngx-leaflet

We needed to display a map in several places in the application, with pins marking the locations of the reported issues. Our customer really wanted to use Open Street Map, so Google Maps was not an option. We went with Leaflet and found ngx-leaflet, a nice little library offering an Angular directive. It proved super easy and straight-forward to use, and we did not regret to use it!

<!-- This displays a nice little map -->
<!-- with options, bounds and markers defined in your component -->
<div leaflet
    [leafletOptions]="mapOptions"
    [leafletFitBounds]="mapFitBounds"
    [leafletLayers]="mapMarkers">
</div>

Kudos to Asymmetrik and Ryan Blace for maintaining it!

Bootstrap and ng-bootstrap

Bootstrap is still our go-to CSS framework when we need to build a responsive application. The flex support is very good and allows to build applications that work well on mobile with little effort.

Boostrap recently introduced spinners and toasts, which are very handy to notify your users.

We also used ng-bootstrap to which we contribute now and then, and is always a pleasure to use (especially that typeahead component which always has a 😍 effect).

ngx-speculoos and ngx-valdemort

This is a shameless plug because we wrote these tiny librairies but we really like using them 😊.

ngx-speculoos helps you to write more concise and readable tests and ngx-valdemort is a life saver when it comes to validation messages in forms.

Cypress

You may know that the default end-to-end test tool in Angular CLI is Protractor. Which works well, but is sadly still missing features for Angular (it was built for AngularJS), for example to mock backend requests easily.

Lately, a new challenger rose: Cypress. I was a bit suspicious at first (Selenium and Protractor marked me for life), but after using it on several Vue projects (as it is one of the available possibilities when you setup a project with the Vue CLI), I really fell in love with it!

So this time, even if our project was a classic Angular CLI setup, we replaced the Protractor tests with Cypress ones. And it was a pleasure to use.

A few killing features:

  • easy to setup
  • easy to mock HTTP requests
  • easy to test different viewports (❤️ for responsive applications)
  • nice enough DSL

And my favorite: Cypress takes snapshot at each step of your tests, so you can debug very easily. Just by hovering the step of the failing test, you see exactly the state of the application and can play with it 🔥.

We ended up with 98.7% code coverage with unit tests, and some important pages of the application also covered by e2e tests with Cypress for the most common use-cases.

We had great fun building this little application: if your company wants help to build a product, let us know!


Cool things we learned - part 1 - backend edition

In the nearly 7 years of our company, we mostly worked on existing applications for our customers. But recently, we completed two projects from scratch for two French customers. We just completed the second one, a small Progressive Web Application for helping citizens to report issues in their city/street (think “Broken lamp” for example). We also built the backend part of the application, and a backoffice to allow the local governments (cities, groups of cities, regions…) to see the reported issues and handle them. This is not a new concept, but our customer is an organization that promotes open-source in French administrations. So this application is open-source and will hopefully be used by French citizen, as soon as the local administrations deploy it.

Let’s talk about the stack we used on the backend and a few cool things we tried and learned.

Kotlin

The backend part is developed using Kotlin. We really like Kotlin and have been using it on several internal applications, but this is the first time we were paid to build something with it 😄. My colleague Jean-Baptiste is already quite versed in Kotlin (see The Gradle Kotlin DSL is now documented) but that was my first real project with it.

And I must admit I really like it. Kotlin takes the pain away of a few things (like the null safety), and is a very pragmatic language with some beautiful patterns. I have been writing mostly TypeScript code these last years, and you can feel some similarities between the two, making them a good match in the same project, one for the backend, one for the frontend.

We used Spring Boot as a framework for the backend, and the Kotlin integration is great, even if it is still a work in progress for some parts (see below).

Mockk and SpringMockk

We started the project using Mockito, mostly as a reflex as we have been using it for a long time in our Java projects.

But we heard more and more about an alternative more suited for Kotlin: MockK.

And it’s indeed nicer to use, with a Kotlin DSL that feels more natural. One thing was lacking though: the Spring Boot integration tests support is based on Mockito for the @MockBean and @SpyBean annotations.

Our JB Nizet thought it would be a good idea to have a support for MockK in Spring Boot, and coded the SpringMockK library that offers @MockkBean and @SpykBean annotations!

He offered the Spring team to integrate it directly into Spring Boot, but, despite quite a few thumbs up on the issue, the team decided that the best way would be to make the existing annotations framework-agnostic, but that it would not happen soon.

So we are now maintaining a new open-source library 😀. We released 1.1.0 based on the latest MockK:

testImplementation("com.ninja-squad:springmockk:1.1.0")

Feel free to give a try if you are writing tests in Kotlin.

REST API documentation

When we develop a backend with a REST API, we try to document it as cleanly as possible. Spring REST Docs is a great help to do so. You can write a really nice documentation only using Asciidoc and tests. For example, you can check out the documentation of the REST API we wrote for our Angular trainings: ponyracer.ninja-squad.com/apidoc.

The current DSL is not really designed for Kotlin though, so, you know what? Yep, Jean-Baptiste wrote another open-source library: Spring REST Docs Kotlin, a Kotlin DSL to write Spring REST Docs tests.

It’s not yet released because it might be integrated directly into Spring REST Docs in the future (at least we hope so). Follow this issue if you are interested.

MailHog

We are not really Docker experts, but we often use it to ease the setup on our machines. This time we had a fairly common thing to do in our application: send emails. As you probably know, you need an SMTP server somewhere, so that’s always a bit cumbersome to setup and test. We stumbled upon a very cool Docker image for MailHog, that simplified our life quite a bit.

This is what part of our docker-compose.yml file looks like:

smtp:
  image: mailhog/mailhog
  container_name: smtp
  ports:
    - 25:1025
    - 8025:8025

MailHog gives you a SMTP testing server (that doesn’t really send emails) with a Web UI allowing to check the emails sent (looks like a classic email client inbox, but you see all the emails sent). Very handy!

Check out part 2 about the frontend!


What's new in Angular CLI 7.3?

Angular CLI 7.3.0 is out! For once, there is no Angular release at the same time. The next version for the framework should be 8.0.0 in a few months.

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

Conditional ES5 browser polyfill loading

If you target older browsers, you used to need to uncomment a few things in the polyfills.ts file. For example, if you want to target IE 9, 10 and 11, a few polyfills from core-js are needed. These polyfills allow to use modern JS features (that Angular needs) even in older browsers, and were commented in the dedicated polyfills.ts file, where you could remove the comments if you wanted to include them.

But since Angular CLI 7.3, you don’t have to do this anymore: it’s done for you automatically! The CLI generates a bundle containing all the polyfills needed for older browsers called es2015-polyfills.***.js and adds it in the index.html.

As adding these polyfills makes the application heavier, you might be wondering if this a good idea. But there a twist: the CLI adds the script in index.html with a nomodule attribute. This attribute indicates to modern browsers (that supports ECMAScript modules) to ignore this script, so it’s not even fetched on modern browsers! If you ever tried Vue CLI, this is very close to the “modern” build mode.

This new behavior is controlled via the es5BrowserSupport option in angular.json. It saves roughly 56Kb (19Kb compressed) on modern browsers, so that’s totally worth it. You can activate it by adding the option in your configuration, and update your polyfills.ts file (check angular-cli-diff/compare/7.2.0…7.3.0 to see how).

Guard schematics for all interfaces

In previous version of the CLI, when using the schematic to generate a new router guard, you ended up with a CanActivateGuard (which is probably the most used one, but not the only one).

In CLI 7.3, when you run the same schematic, you now have a multi-select choice looking like:

ng g guard logged-in
? Which interfaces would you like to implement? (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◯ CanActivate
◯ CanActivateChild
◯ CanLoad

You can choose one or more interfaces to implement, and of course the result will be a guard implementing these interfaces. Note that this multi-select question in interactive mode is also a new feature of the CLI. The cool thing is that you can also directly specify the interfaces you want:

ng g guard logged-in --implements CanActivate

TSLint extends tslint:recommended

This is a feature I really like because I added it 😉.

The default TSLint configuration now extends tslint:recommended, the recommended set of rules of the TSLint team.

While updating the TSLint configuration in the CLI, we also activated a few more rules. You can see the difference here.

Try it in your projects, you may catch a few hidden bugs (or at least make your code prettier)!

Note that the CLI now also officially supports the TSLint configuration file to be written in YAML (the default generated one is in JSON).

Catch errors in your e2e tests

A slight change has been applied to the default e2e test generated:

afterEach(async () => {
  // Assert that there are no errors emitted from the browser
  const logs = await browser.manage().logs().get(logging.Type.BROWSER);
  expect(logs).not.toContain(jasmine.objectContaining({
    level: logging.Level.SEVERE
  } as logging.Entry));
});

This afterEach function will run after each one of your tests (obviously) and will report eventual runtime errors. This can be really useful to catch hidden errors in your e2e tests.

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

Angular CLI 7.2.0 is out!

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

TypeScript 3.2 support

As Angular 7.2 now supports TypeScript 3.2 (check out our article about Angular 7.2), the CLI officially supports it too.

New flag and flag values for ng build

new resourcesOutputPath option

It is now possible to specify where resources will be placed, relative to outputPath. In short you can ouput your CSS in other instead of the root of the output folder with:

ng build --resources-output-path=other

sourceMap fine-grained values

The sourceMap flag of ng build used to take a boolean value: true to generate the source maps for styles and scripts, false to ignore them.

It can now take a more fine-grained value, as you can now give an object to configure if you want only the scripts source maps, the styles source maps, the vendor source maps, or the hidden source maps, a new feature to generate this special kind of source maps that some error reporting tools like Sentry use.

"sourceMap": {
  "scripts": true,
  "styles": true,
  "hidden": true,
  "vendor": true
}

The vendor option replaces the now deprecated vendorSourceMap flag.

optimization fine-grained values

Similarly, the optimization flag used to take a boolean value: true to activate scripts and styles optimization, false to ignore them (leading to faster builds).

Now you can activate one or the other, as optimization can now take an object to configure it:

"optimization": {
  "scripts": true,
  "styles": true
}

Build Event Log

A new flag called buildEventLog has been added to ng build. This flag needs a filename as a parameter and will generate the specified file, with a timeline of the build events. Currently, running ng build --build-event-log log.txt generates:

{"id":{"started":{}},"started":{"command":"build","start_time_millis":1544793799294}}
{"id":{"finished":{}},"finished":{"finish_time_millis":1544793807037,"exit_code":{"code":0}}}

As you can see, it only logs a started and finished events for now. This is heavily inspired by the Build Event Protocol, and we will probably get a more detailed report in the future (this is probably introduced with the future Bazel build in mind).

New flag for ng update

A new verbose flag is available for this command to detail what exactly is going on and help debug potential issues.

Flag deprecations

The CLI added the possibility to deprecate a flag in a schematic (with the x-deprecated field in a schema).

The team took the occasion to deprecate a few flags from the CLI itself:

  • evalSourceMap in ng build/serve as it could be used to improve build performances, but isn’t needed anymore.
  • vendorSourceMap in ng build/serve, as it has been replaced, see above.
  • skipAppShell in ng build/serve for a Web application as it had no effect.
  • styleext in ng generate, and should now be style. It is used to specify the extension of the style file of a new component (for example, ng generate component user --style scss).
  • spec in ng generate, and should now be skipTests. It is used to not generate tests (for example, ng generate component user --skip-tests).

Flag override warning

Note that you will now have a warning when you specify a flag several times in the same command. It used to pick the last one silently, and now it will still do the same and also warn you that there is something weird going on:

> ng build --aot --aot=false
Option aot was already specified with value true. The new value false will override it.

But it doesn’t warn you if you use: ng build --prod --aot=false.

That’s all for this small 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.2?

Angular 7.2.0 is here!

Angular logo

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

TypeScript 3.2 support

One of the new features is the support of TypeScript 3.2, which is the latest release! You can check out what was introduced in TypeScript 3.2 on the Microsoft blog.

ng new with Bazel support!

I was mentioning in our article about Angular 7.1 that the Bazel support was making progress, and this 7.2 release brings a cool new feature. It’s more a new CLI feature and maybe should be mentioned in my upcoming blog post about “What’s new in Angular CLI 7.2”, but the code of @angular/bazel lives in the Angular repo and not in the CLI repo.

This new feature is the possibility to generate a new project with Bazel build! 🚀

npm i -g @angular/bazel
ng new my-app --collection=@angular/bazel --defaults

And boom! You have a new project that uses Bazel.

You can then run the usual commands like ng serve/build/test, and they will not use the default CLI builders, but the Bazel ones. Note however that all the usual flags and options of the CLI are not supported yet.

This is still very experimental and early stage, so you will probably encounter various issues if you give it a try.

Router

History state

The router gains a new feature allowing to pass dynamic data to the component you want to navigate to, without adding them into the URL. This could be done by using a shared service, but it can be cumbersome to have to create a service to just pass a few data.

The router now uses the full capacity of the Browser History API, and allows to pass a state property to NavigationExtras, the options that you can pass to some router methods, like navigateByUrl.

this.router.navigateByUrl('/user', { state: { orderId: 1234 } });

or in a link, thanks to a new state input:

<a [routerLink]="/user" [state]="{ orderId: 1234 }">Go to user's detail</a>

The state will be persisted to the browser’s History.state property. Later, the value can be read from the router by using getCurrentNavigation:

const navigation = this.router.getCurrentNavigation();
this.orderId = navigation.extras.state ? navigation.extras.state.orderId : 0;

New options for runGuardAndResolvers

This is not a left over copy/paste from the 7.1 article: there are other new options for runGuardsAndResolvers in 7.2!

runGuardsAndResolvers is one of the configuration options for a route, allowing to define when the guards and the resolvers will be run for this route. By default, they run only when the path or matrix parameters change (value paramsChange). You can override this behavior by using another value for this option like paramsOrQueryParamsChange, to also trigger the guards and resolvers if a query parameter changes, or always to trigger them if anything changes. Angular 7.1 introduced a new possible value: pathParamsChange. Using this value, the guards and resolvers will run if a path parameter changes, but not if a query or matrix parameter changes. Angular 7.2 introduces another option: pathParamsOrQueryParamsChange. using this value, the guards and resolvers will run if a path parameter or a query parameter changes, but not if a matrix parameter changes.

I think a configuration object with boolean switches for path, query or matrix parameters would make things clearer at that point 😅.

But another new possibility in 7.2 is to define your own predicate function to indicate to runGuardsAndResolvers if it should run the guards and resolvers. The function should look like (from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean, for example:

runGuardsAndResolvers: (from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot)
  => to.paramMap.get('query') !== from.paramMap.get('query')

In that case, the guards and resolvers will only run if the query param changed.

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

Angular CLI 7.1.0 is out!

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

Package manager auto detection

The CLI should now do a better job to detect the package manager you use (NPM or Yarn), and use it for the various commands like ng update or ng add.

tslib as a dependency

The CLI applications have a new required dependency: tslib. This Microsoft library contains TypeScript helpers. The CLI now uses one of them to avoid repeating code for every class regarding imports. The use of these helpers is activated by an option importHelpers in the tsconfig.json file:

"experimentalDecorators": true,
"importHelpers": true,

By including these helpers, and avoiding to repeat the same code over and over, the sizes of your bundles should be slightly reduced (don’t expect miracles though).

@angular/http removed

@angular/http has been deprecated for a long time in favor of @angular/common/http, and it is now removed from the generated package.json file.

That’s all for this very small 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.1?

Angular 7.1.0 is here!

Angular logo

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

Beginning of Bazel support

A new @angular/bazel package appeared in the Angular repository, containing the stepping stones for building our Angular applications with Bazel. It also contains a schematics collection (with a target currently called bazel-workspace) to generate the necessary files in an Angular CLI application.

npm i -g @angular/bazel
ng generate @angular/bazel:bazel-workspace my-app // adds the Bazel build files to a CLI project

I guess that in a near future, we should be able to directly generate a CLI app with Bazel build (something like ng new my-app --collection=@angular/bazel).

The bazel-workspace target already allows to build, serve, test and launch the e2e tests with Protractor. This is still quite experimental.

Note that Bazel is now published on NPM directly, removing the need to install it manually.

Router

CanActivate guard can return a UrlTree

The signature of CanActivate changed and it now can return Observable<boolean|UrlTree>|Promise<boolean|UrlTree>|boolean|UrlTree instead of Observable<boolean>|Promise<boolean>|boolean. It means that whereas previously you would have returned a boolean (or something that yields a boolean later), you can now return the URL where you want to redirect your user.

So you can write:

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree {
  return this.userService.isLoggedIn() || this.router.parseUrl('/login');
}

instead of:

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
  const loggedIn = this.userService.isLoggedIn();
  if (!loggedIn) {
    this.router.navigateByUrl('/');
  }
  return loggedIn;
}

The difference is also that now the router will behave correctly if several guards trigger different redirects (it was not the case before, and that could lead to non deterministic behavior in redirections). Note that you can also use router.createUrlTree() to build a UrlTree with parameters.

New option for runGuardAndResolvers

runGuardsAndResolvers is one of the configuration options for a route, allowing to define when the guards and the resolvers will be run for this route. By default, they run only when the path or matrix parameters change (value paramsChange). You can override this behavior by using another value for this option like paramsOrQueryParamsChange, to also trigger the guards and resolvers if a query parameter changes, or always to trigger them if anything changes.

Angular 7.1 introduces a new possible value: pathParamsChange. Using this value, the guards and resolvers will run if a path parameter changes, but not if a query or matrix parameter changes.

Forms

updateOn in FormBuilder

The updateOn option is available since Angular 5, but it was only usable if you used the constructor of FormGroup directly:

this.userForm = new FormGroup({
  username: '',
  password: ''
}, {
  validators: Validators.required,
  updateOn: 'blur'
});

It is now possible to use it via the group helper method of the FormBuilder. Note that this updated group method can now take an AbstractControlOptions as the second parameter, allowing to have a more coherent API, and use exactly the same syntax as in FormGroup:

this.userForm = fb.group({
  username: '',
  password: ''
}, {
  validators: Validators.required,
  updateOn: 'blur'
});

The old form of options is now deprecated (it was using validator and asyncValidator instead of validators and asyncValidators).

Service Worker

It’s now possible to be notified when a user clicks on a push notification, via the notificationClicks observable on the service SwPush.

Ivy update

The Ivy rewrite is still in progress, but I noted that I missed a nice addition: there will be public discovery utils that can be used to debug your application in the browser. Several functions will be available in the browser console: getComponent(target), getDirectives(target), getHostComponent(target), getInjector(target), getRootComponents(target), and getPlayers(target).

In Chrome for example, you can inspect an element and that will store the current element in a variable called $0. Then in the browser console, you can do ng.getComponent($0) and it will return the component associated to the element! You can check out Jason Aden talk at AngularConnect for more info on the topic.

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 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!


Posts plus anciens