What's new in Angular 10.0?

Angular 10.0.0 is here! 10 major versions is quite a milestone (well, it’s 8 in fact, as there are no Angular version 1 and 3, but you get the point)

Angular logo

Despite being a nice round number, this is a small release in terms of features. But I’m super happy to see that the team has been digging into the open issues on Github: it’s no secret that issues accumulated over these past months/years without much feedback from the Angular team, busy as they were working on Ivy. We should see some improvements on this front!

Let’s see what version 10.0 brings us.

TypeScript 3.9

This release comes with the support of TypeScript 3.9, and requires us to update our applications to use this version (TS 3.8 is no longer supported). You can check out which new features TS 3.9 offers on the Microsoft blog.

IE9, IE10, and IE mobile are no longer supported

As these old browsers now have a very small fraction of the market, they are no longer officially supported by the Angular framework.

Deprecations and breaking changes

The Bazel builder is now deprecated. It never reached a stable state as it was still in the “Angular Labs”, and has not been actively used or maintained. It does not mean that there will not be a solution for using Bazel with Angular applications, but instead of wrapping Bazel in the CLI, it will probably come in another form.

WrappedValue has been deprecated. It was used to wrap a value, to force a change detection even if the value did not change. The async pipe used to use it internally, and no longer does. You probably never needed it, so that should not really impact you.

A fix in forms has also introduced a breaking change: valueChanges used to fire twice on a number input. this was to handle a special case with IE9. As IE9 is no longer supported, this is no longer the case. Again, that should not impact you, unless you were relying on this behavior.

Service worker

The service worker package offers registration strategies since Angular 8.0. You can check out the article we wrote at that time. It now adds the possibility to set a timeout for the registerWhenStable strategy, with registerWhenStable:TIMEOUT. If the application does not stabilize after the timeout, the ServiceWorker registers anyway. It can be handy if your application has an recurrent asynchronous task, as it will never stabilize. If you do not specify a timeout, the ServiceWorker will now register after 30 seconds by default.

It is now also possible to specify caching options with cacheQueryOptions for asset or data requests.

Router

The signature of CanLoad changed, and it now matches the signature of CanActivate. The guard can now also return an UrlTree. CanActivate had this option since Angular 7.1 (see our explanation in this blog post, and CanLoad can now do the same.

You can also check out our blog post about the CLI v10 to see what’s new there.

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

Angular CLI 10.0.0 is out!✨

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

This new release supports Angular 10 of course, and now requires TypeScript 3.9.

One of the new features is the support for “Solution Style” tsconfig.json files. This allow IDEs to more easily find which project a TS file belongs to, when you have several tsconfig files (it’s better explained in the release post if you want to learn more 🤓).

As an Angular CLI project does have several tsconfig files, this improvement is useful to us! The CLI now generates projects with a base tsconfig, extended by the the app one, the unit tests one, and the e2e tests one. The tsconfig.json file now only references the others. If you update your application using the ng update command, a schematics will automatically do this refactor for you.

Evergreen applications by default

New applications are now only targeting evergreen browsers by default. This means that the browserslist configuration now only includes the latest releases of each major browser when generating a new application. It also means that a newly generated application does not have differential loading, so it does not build twice! Differential loading was introduced in Angular CLI v8.0, and is great if you need to support older browsers. If you want to have differential loading in a new application, you can generate your application using the new --legacy-browsers flag:

ng new my-app --legacy-browsers

Or you can manually update the browserslist config to finely tune which browsers you want to support (--legacy-browsers adds IE9-11 to the config), and the CLI will automatically build your application once or twice accordingly.

Note that if you only target modern browsers, the resulting JS files are no longer suffixed with es2015.

Stricter applications

The --strict flag introduced in version 9.1 for ng new now goes further:

  • it enables strict: true in your tsconfig.base.json, and adds a bunch of others flags (forceConsistentCasingInFileNames, noFallthroughCasesInSwitch and noImplicitReturns)
  • it adds strictTemplates and strictInjectionParameters to angularCompilerOptions in your tsconfig.base.json
  • it generates an extra package.json file with sideEffects: false (see below)
  • it lowers the budgets for initial load and component styles in angular.json, and adds the strict settings to the application schematics
  • it adds the no-any rule to your tslint.json

Bundle optimizations

If you generate a new application with the --strict flag, you’ll see that an extra package.json file is now present in src/app. It does not contain any dependencies, only:

{
  "name": "my-app",
  "private": true,
  "description": " ... ",
  "sideEffects": true
}

The long description explains that this file is only useful for bundlers, to signal if our code has non-local side effects or not. You can probably safely change the value of the sideEffects option to false, and the CLI/Webpack will optimize the generated bundle more aggressively. You can of course manually add this file to your application to give it a try. I didn’t spot any stellar improvements in bundle sizes for my applications though…

Warnings when depending on CommonJS packages

Bundlers like Webpack have a hard time optimizing CommonJS packages. The CLI now warns you when you build or serve your application if you use CommonJS dependencies:

WARNING in src/app/chart/chart.component.ts depends on chart.js. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

If you want to learn more about this, check out this article, it’s very well explained.

If you can’t do otherwise, you can add the following option to your angular.json file to remove the warning:

"build": {
  "builder": "@angular-devkit/build-angular:browser",
  "options": {
    // ...
    "allowedCommonJsDependencies": ["chart.js"]
  }

Deprecations and removals

A few deprecated commands and options have been removed:

  • ng get/set no longer exist: use ng config instead.
  • the es5BrowserSupport, elementExplorer, evalSourceMap, vendorSourceMap, profile, skipAppShell and typescriptMismatch options are removed as well.

A schematic takes care of updating the angular.json file for you.

Note that you can also remove the @angular/language-service package from your package.json. This package was needed by VSCode extension to have autocompletion/type-checking in the templates. It is no longer necessary to install it ourselves, as the extension now directly embeds it (and I think most IDE extensions do).

Automatic migrations in v10

When running ng update @angular/cli, some schematics are going to update your code. The command:

  • renames browserslist to .browserslistrc.
  • changes the target for TypeScript from esnext to es2020, which is currently the same thing, but using es2020 makes sure there is no changes in behavior when es202x comes out.
  • removes the deprecated builder options in angular.json (see above).
  • refactors the tsconfig files as explained in the first section
  • adds the deprecation rule to your TSLint config if you don’t have it.
  • bumps a few dependencies

As you can see, this 10.0 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!


2020-05-27

Getting started with Vue 3

Disclaimer This blog post is a chapter of our ebook Become a Ninja with Vue. Enjoy! But keep in mind that, unlike the ebook, it won’t be kept up to date with changes in Vue in the future.

Vue always marketed itself as a progressive framework that, unlike other alternatives like Angular or React, you can adopt progressively. You can take your existing static HTML, or jQuery application and easily sprinkle a bit of Vue on top of it.

So first I’d like to demonstrate how easy it is to set up Vue.

Let’s make an empty index.html file:

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
  </head>
  <body>
  </body>
</html>

Now let’s add some HTML for Vue to handle:

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
  </head>
  <body>
    <div id="app">
      <h1>Hello </h1>
    </div>
  </body>
</html>

The curly braces around user is Vue templating syntax, indicating that user should be replaced by its value. We’ll explain everything in details in the following chapter, don’t worry.

If you load the page in your browser, you’ll see that it displays Hello {{ user }}. That’s normal, as we haven’t used Vue yet.

Now let’s add Vue. Vue is released on NPM and some sites (called CDNs, for Content Delivery Network) make NPM packages available for inclusion in our HTML pages. Unpkg is one of them. We can use it to add Vue to our page. Of course, you could also choose to download the file and serve it by yourself.

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
  </body>
</html>

NOTE: We are using the latest version of Vue in this example. You can specify any version you want by adding @version after https://unpkg.com/vue in the URL.

If you reload the application, you’ll see that Vue emits a warning in the console, informing us that we are using a development version. You can use vue.global.prod.js to use the production version, and make it disappear. The production doesn’t do any checks in our code, is minified, and is bit faster.

We now need to create our application. Vue offers a createApp function to create an application. To call it, we need a root component.

To create a component, we simply need to create an object that defines it. This object can have various properties, but for now we’ll just add a setup function. Again we’ll explain thoroughly later, but the name is explanatory enough: this function is here to set up the component, and Vue is going to call it for us when the component is initialized.

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const RootComponent = {
        setup() {
          return { user: 'Cédric' };
        }
      };
    </script>
  </body>
</html>

The setup function just returns an object with a property user and a value for this property. But if you reload your page, still nothing happens: we need to call createApp with our component.

NOTE: You need a recent enough browser to load this page, as, as you can see, it uses a “modern” JavaScript syntax.

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const RootComponent = {
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

createApp creates an application that needs to be “mounted” in some place in the DOM: here we use the div with the id app. If you reload the page, you should now see Hello Cédric. Congratulations, you have your first Vue application.

Maybe we can add another component? We’ll build an other component, displaying the number of unread messages.

Let’s add a new object called UnreadMessagesComponent, with a similar setup property:

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const UnreadMessagesComponent = {
        setup() {
          return { unreadMessagesCount: 4 };
        }
      };
      const RootComponent = {
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

Unlike the root component which is using the template inside the #app div, we want to define a template for UnreadMessagesComponent. This can be done by adding a script tag with a special type text/x-template. This type guarantees that the browser won’t care about this script. You can then reference the template by its id inside the component definition:

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
    <script type="text/x-template" id="unread-messages-template">
      <div>You have {{ unreadMessagesCount }} messages</div>
    </script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const UnreadMessagesComponent = {
        template: '#unread-messages-template',
        setup() {
          return { unreadMessagesCount: 4 };
        }
      };
      const RootComponent = {
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

We want to be able to insert the unread messages component inside our main template. To do that, we need to tell the root component it’s allowed to use the unread messages component, and we need to assign it a PascalCase name:

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
    <script type="text/x-template" id="unread-messages-template">
      <div>You have {{ unreadMessagesCount }} messages</div>
    </script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const UnreadMessagesComponent = {
        template: '#unread-messages-template',
        setup() {
          return { unreadMessagesCount: 4 };
        }
      };
      const RootComponent = {
        components: {
          UnreadMessages: UnreadMessagesComponent
        },
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

We can now use the tag <unread-messages></unread-messages> (which is the dash-case version of UnreadMessages) to insert the component where we want:

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
    <script type="text/x-template" id="unread-messages-template">
      <div>You have {{ unreadMessagesCount }} messages</div>
    </script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
      <unread-messages></unread-messages>
    </div>
    <script>
      const UnreadMessagesComponent = {
        template: '#unread-messages-template',
        setup() {
          return { unreadMessagesCount: 4 };
        }
      };
      const RootComponent = {
        components: {
          UnreadMessages: UnreadMessagesComponent
        },
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

Comparing to other frameworks, a Vue application is super easy to start: just pure JavaScript and HTML, no tooling, components are simple objects. Even someone that doesn’t know Vue can understand what’s going on. And this is one of the strengths of the framework: it’s easy to start, easy to grasp, and you can progressively learn the features.

We could stick to this minimal setup for our projects, but, let’s face it, it will not scale for long. We will soon have too many components to fit in one file, we would really love to use TypeScript instead of JavaScript, to add tests, to add some kind of code analysis, etc.

We could set up all the needed tools by hand, but instead let’s leverage the work of the community and use the excellent Vue CLI.

Come back next week if you want to learn how, or pay what you want for our complete ebook Become a Ninja with Vue!


2020-05-27

Commencer avec Vue 3

Disclaimer Cet article est un chapitre de notre livre Deviens un Ninja avec Vue. Bonne lecture ! Garde en tête que, contrairement à notre livre, cet article ne sera pas maintenu à jour avec de futurs changements de Vue.

Vue s’est toujours présenté comme un framework évolutif qui, au contraire d’alternatives comme Angular ou React, peut être adopté progressivement. On peut parfaitement prendre une page HTML statique, ou une application basée sur jQuery, et y ajouter un peu de Vue.

Donc, pour commencer, j’aimerais montrer comme c’est simple de mettre en place Vue dans une page HTML.

Créons une page HTML vide index.html :

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
  </head>
  <body>
  </body>
</html>

Ajoutons-y un peu de HTML que Vue devra gérer :

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
  </head>
  <body>
    <div id="app">
      <h1>Hello </h1>
    </div>
  </body>
</html>

Les accolades autour de user font partie de la syntaxe de Vue. Elles indiquent que user doit être remplacé par sa valeur. Nous expliquerons tout cela en détails dans le prochain chapitre, pas d’inquiétude.

Si tu ouvres cette page dans ton navigateur, tu verras qu’elle affiche Hello {{ user }}. C’est normal : nous n’avons pas encore utilisé Vue.

Faisons-le. Vue est publié sur NPM et il existe des sites (appelés CDNs, pour Content Delivery Network) qui hébergent les packages NPM et permettent ainsi de les inclure dans nos pages HTML. Unpkg est l’un d’entre eux, et on peut donc l’utiliser pour ajouter Vue à notre page. Bien sûr, tu pourrais aussi choisir de télécharger le fichier et de l’héberger toi-même.

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
  </body>
</html>

NOTE: Cet exemple utilise la dernière version de Vue. Tu peux spécifier n’importe quelle version explicitement en ajoutant @version dans l’URL, après https://unpkg.com/vue.

Si tu recharges la page, tu verras que Vue affiche un avertissement dans la console, nous informant qu’on utilise une version dédiée au développement. Tu peux utiliser vue.global.prod.js pour utiliser la version de production, et faire disparaître l’avertissement. La version de production désactive toutes les validations sur le code, est minifiée, et est donc plus rapide et plus légère.

Il nous faut à présent créer notre application, avec la fonction createApp. Mais cette fonction a besoin d’un composant racine.

Pour créer ce composant, il nous suffit de créer un objet qui le définit. Cet objet peut avoir de nombreuses propriétés, mais pour l’instant, nous allons seulement y ajouter une fonction setup. Pas de panique, nous reviendrons en détails sur la définition d’un composant et sur cette fonction. Mais son nom est assez explicite : elle prépare le composant, et Vue appellera cette fonction lorsque le composant sera initialisé.

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const RootComponent = {
        setup() {
          return { user: 'Cédric' };
        }
      };
    </script>
  </body>
</html>

La fonction setup ne fait que retourner un objet avec une propriété user et une valeur pour cette propriété. Si tu recharges la page, toujours pas de changement : il nous reste toujours à appeler createApp avec notre composant racine.

NOTE: nous utilisons du JavaScript moderne dans cet exemple, et il te faut donc utiliser un navigateur suffisamment récent, qui supporte cette syntaxe.

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const RootComponent = {
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

createApp crée une application qui doit être “montée”, c’est-à-dire attachée à un élément du DOM. Nous utilisons ici la div avec l’identifiant app. Si tu recharges la page, tu devrais voir Hello Cédric s’afficher. Bravo, tu viens de créer ta première application Vue.

Peut-être pourrions-nous ajouter un autre composant ?

Créons un composant qui affiche le nombre de messages non lus. Il nous faut donc un nouvel objet UnreadMessagesComponent, avec une fonction setup similaire :

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const UnreadMessagesComponent = {
        setup() {
          return { unreadMessagesCount: 4 };
        }
      };
      const RootComponent = {
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

Cette fois, au contraire du composant racine dont la vue est directement définie par la div #app, nous voudrions définir un template pour le composant UnreadMessagesComponent. Il suffit pour cela de définir un élément script avec le type text/x-template. Ce type garantit que le navigateur ignorera simplement le contenu du script. On peut ensuite référencer le template par son identifiant dans la définition du composant.

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
    <script type="text/x-template" id="unread-messages-template">
      <div>You have {{ unreadMessagesCount }} messages</div>
    </script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const UnreadMessagesComponent = {
        template: '#unread-messages-template',
        setup() {
          return { unreadMessagesCount: 4 };
        }
      };
      const RootComponent = {
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

On veut pouvoir insérer ce nouveau composant à l’intérieur du composant racine. Pour pouvoir faire ça, nous devons autoriser le composant racine à utiliser le composant unread messages, et lui assigner un nom en PascalCase.

On peut ensuite utiliser <unread-messages></unread-messages> (qui est la version dash-case de UnreadMessages) pour insérer le composant où on le veut.

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
    <script type="text/x-template" id="unread-messages-template">
      <div>You have {{ unreadMessagesCount }} messages</div>
    </script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
    </div>
    <script>
      const UnreadMessagesComponent = {
        template: '#unread-messages-template',
        setup() {
          return { unreadMessagesCount: 4 };
        }
      };
      const RootComponent = {
        components: {
          UnreadMessages: UnreadMessagesComponent
        },
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

We can now use the tag <unread-messages></unread-messages> (which is the dash-case version of UnreadMessages) to insert the component where we want:

<html lang="en">
  <meta charset="UTF-8" />
  <head>
    <title>Vue - the progressive framework</title>
    <script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
    <script type="text/x-template" id="unread-messages-template">
      <div>You have {{ unreadMessagesCount }} messages</div>
    </script>
  </head>
  <body>
    <div id="app">
      <h1>Hello {{ user }}</h1>
      <unread-messages></unread-messages>
    </div>
    <script>
      const UnreadMessagesComponent = {
        template: '#unread-messages-template',
        setup() {
          return { unreadMessagesCount: 4 };
        }
      };
      const RootComponent = {
        components: {
          UnreadMessages: UnreadMessagesComponent
        },
        setup() {
          return { user: 'Cédric' };
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
    </script>
  </body>
</html>

En comparaison des autres frameworks, une application Vue est extrêmement simple à mettre en œuvre : juste du pur JavaScript et HTML. Pas d’outillage nécessaire. Les composants sont de simples objets. Même un développeur qui ne connaît pas Vue peut sans doute comprendre ce qui se passe. Et c’est l’une des forces du framework : c’est facile de démarrer, facile à comprendre, et les fonctionnalités peuvent être apprises progressivement.

On pourrait se contenter de cette approche minimale, mais soyons réalistes : ça ne tiendra pas très longtemps. Trop de composants vont devoir être définis dans le même fichier. On voudrait aussi pouvoir utiliser TypeScript au lieu de JavaScript, ajouter des tests, de l’analyse de code, etc.

Nous pourrions installer et configurer toute une série d’outils nous-mêmes. Mais profitons plutôt du travail de la communauté et utilisons l’excellente Vue CLI.

Reviens la semaine prochaine pour apprendre comment, ou paye le prix que tu veux pour notre ebook complet Deviens un Ninja avec Vue !


Deviens un Ninja avec Vue - notre ebook pour apprendre Vue 3 !

Nous sommes très contents d’annoncer la sortie de notre ebook et formation en ligne sur Vue 3 ! 🚀

Vous savez que nous sommes fans d’Angular, mais nous aimons aussi beaucoup Vue. Vue 3.0 est une ré-écriture complète de Vue 2.x. Elle amène un bien meilleur support de TypeScript, une nouvelle façon de définir les composants avec l’API de Composition, et plein d’autres choses intéressantes. Je contribue au framework et aux librairies les plus populaires de l’éco-système depuis un moment. J’apprécie beaucoup Vue, et cet ebook et formation en ligne contiennent tout ce que j’ai appris.

Comme d’habitude, notre ebook est à prix libre 😊. Tu peux également donner une partie du montant pour soutenir l’équipe Vue. L’ebook est sans DRM, disponible dans tous les formats, et aussi bien en français qu’en anglais.

👉 https://books.ninja-squad.com/vue

Nous sommes aussi impatients de partager notre formation en ligne, le Pack Pro Vue, avec 25+ exercices pour construire la version Vue de Ponyracer. Vous pourrez construire l’application étape par étape, avec les instructions, tests et solution fournis à chaque exercice. Vous pouvez avoir un aperçu sur https://vue-exercises.ninja-squad.com si vous voulez tester les premiers exercices gratuitement.

Vue 3.0 n’est pas encore en version finale, mais comme nous l’avons fait pour notre matériel Angular, nous maintiendrons tout cela à jour à chaque nouvelle version. Et toutes les mises à jour seront gratuites évidemment.

Comme plus de mille personnes ont aimé notre Pack Pro Angular, mais que certaines ne pouvaient pas se l’offrir, nous avons décidé de vendre notre Pack Pro Vue à 99€ par licence personnelle (illimitée dans le temps). Et, bien sûr, les équipes qui achètent plusieurs licences à la fois ont un prix dégressif.

Enfin, pour fêter cette sortie, nous baissons le prix de notre Pack Pro Angular au même prix de 99€. Cette sortie est donc une bonne nouvelle à la fois pour les fans d’Angular et ceux que Vue intéressent.

Prenez soin de vous dans ces temps difficiles. Nous espérons que vous aimerez découvrir et apprendre Vue 3 autant que nous ❤️.

Deviens un Ninja avec Vue 3


Become a Ninja with Vue - our ebook to learn Vue 3!

We are super happy to release our new ebook and online training about Vue 3! 🚀

You know that we are Angular fans, but we also really enjoy Vue. Vue 3.0 is a complete rewrite of Vue 2.x. It brings first class TypeScript support, a new way of defining components with the Composition API, and tons of cool stuff. I have been contributing to the framework and the popular libraries of the eco-system for a while. I really enjoy it, and this ebook and online training contain everything I learnt.

As usual, you can pay what you want for our ebook 😊. You can also give part of the price to support the Vue team. The ebook is DRM-free, available in all formats, and has an English and a French version.

👉 https://books.ninja-squad.com/vue

We’re really excited to share our online training as well, the Vue Pro Pack, with 25+ exercises to build the Vue version of Ponyracer. You’ll get to build the application step by step, with the instructions, tests and solution provided in each exercise. Check out https://vue-exercises.ninja-squad.com if you want to try the first exercises for free!

Vue 3.0 is not stable yet, but as we did for our Angular materials, we’ll keep everything up-to-date and add new chapters/exercises with the new releases. And all updates will be free of course!

As more than a thousand people already enjoyed our Angular Pro Pack, but some could not afford it, we decided to set the price of our Vue Pro Pack to 99€ for an unlimited personal licence. And, of course, teams get a discount when buying several ones.

And to celebrate the release, we decided to also lower the price of our Angular Pro Pack to the same price of 99€. So this is good news for both the Angular fans and the Vue curious.

Take care in these tough times. We hope you’ll enjoy discovering and learning Vue 3 as much as we did ❤️.

become a Ninja with Vue 3


What's new in Angular 9.1?

Angular 9.1.0 is here!

Angular logo

This is a small release in terms of features but a big release in terms of bug fixes. As more and more people are updating their applications to Ivy, the Angular team fixed a few remaining issues for corner cases. All in all, it looks like the upgrade has been fairly easy for most applications (which I still find unbelievable when you know how different the compilers/runtimes are!).

The team has also been digging into the opened issues on Github: it’s no secret that issues accumulated over these past months/years without much feedback from the Angular team, busy as they were working on Ivy. A lot of issues have been closed because they were already fixed by Ivy, and all should now be properly labeled, to allow the team to plan what should be worked on. This is exciting, and we should see long awaited requests answered in the next months.

Let’s see what version 9.1 brings us.

TypeScript 3.8

This release comes with the support of TypeScript 3.8. You can check out which new features TS 3.8 offers on the Microsoft blog.

Template compiler

The Ivy compiler introduced a new strictTemplates option in v9 (see our Angular 9.0 blog post for more info). This flag is a shortcut to enable a bunch of checks, that can be individually enabled/disabled. A new option called strictLiteralTypes has been introduced if you want to relax the check on literal types in templates (View Engine interpreted them as any whereas Ivy is stricter and infers their proper type by default).

i18n

The locale data now contain the writing direction of the locale (‘rtl’ or ‘ltr’). A utility function getLocaleDirection offered by the @angular/common package can help you retrieve this information in your application.

ngcc

The Angular compatibility compiler (the piece that compiles the dependencies of your application to make them compatible with Ivy) should now be a bit faster, a bit more reliable and a bit more accurate. This is good news as we need to run this compiler on every CI build, and, as you have probably witnessed, every time a dependency changes on your machine (the CLI runs it for you). It’s especially painful for those using Yarn, as Yarn blows away the whole node_modules directory every time a dependency changes, forcing ngcc to re-compile every dependency again. So every gain of speed on this compiler is welcome until we can get rid of it, once all the dependencies are directly released in an Ivy compatible format. But that’s going to take a while.

zone.js

Even if this is not really about Angular, zone.js was recently released in version 0.10.3 and it comes with a few new features.

Passive events

Passive events can be very handy if you want to do something on an event that happens very often, like scroll or mousemove, but don’t want to slow down the scrolling of your application: it’s here to tell the browser that it can proceed with scrolling without waiting for the listener function to return.

Angular doesn’t have a syntax to easily declare a passive event in an application, but zone.js now offers a global variable to configure it. For example, if your declare (window as any)['__zone_symbol__PASSIVE_EVENTS'] = ['scroll']; then all the scroll event listeners you’ll declare in your application will be passive.

Better Jest support

Until now, zone.js automatically added support for Jasmine and Mocha when importing zone-testing (the CLI imports it in the test.ts file of your project). It now also offers built-in support for Jest, a popular testing framework.

This support already existed via the community library jest-preset-angular, which is still needed, but the library now avoids to mingle with Zone.js itself and only focuses on the Jest part.

MessagePort

Zone.js can now handle the Channel Message API. If you listen to messages in your Angular application, the callback can now automatically run in the zone. You can see how to disable it, like every zone module, in this document.

tickOptions

The tick() function that we use in asynchronous tests can now receive an extra parameter tickOptions. tickOptions has for the moment only one property: processNewMacroTasksSynchronously. It has been introduced for a very specific use-case with nested timeouts. By default, this property is true and reflects the current behavior, where all timeouts, even the nested ones not yet installed, are resolved when calling tick. You can now give the extra option to tick to force it to resolve only the currently installed timeouts.

You can also check out our blog post about the CLI v9.1 to see what’s new there.

I’m not sure I can publicly talk about it yet, so all I will say is that long-awaited work should start soon, and hopefully land in the upcoming v10!

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

Angular CLI 9.1.0 is out!✨

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

TSLint 6.1

As Angular 9.1 now supports TypeScript 3.8, the CLI does support it as well. The CLI also supports TSLint 6.1 (which supports the new TypeScript syntaxes introduced in version 3.8). This is a bit weird, as TSLint is officially deprecated since version 6.0, in favor of typescript-eslint.

The CLI team plans to migrate to typescript-eslint as soon as possible, but, in the meantime, it still supports TSLint, and its new release 6.1.

Note that TSLint 6.0 introduced a lot of changes in the tslint:recommended config, that the CLI extends.

To avoid these breaking changes in our applications, the default tslint.json configuration has been updated, and the CLI 9.1 ships with a migration you can run to update your configuration. The migration will be run automatically in version 10, but until then, you can run it manually if you want with:

ng update @angular/cli --migrate-only tslint-version-6

Fun with flags 🤓

ng e2e

The Protractor builder now accepts two flags grep and invertGrep to only run the matching spec names. Not the file name, the spec name, i.e. what you specified in the describe() and it() functions:

describe('App', () => {
  it('should have a navbar', () => { });
  it('should say hello on home', () => { });
  it('should have a login button on home', () => { });
});

For example if you only want to run the specs whose name matches ‘home’, you can run ng e2e --grep home.

invertGrep can be used to run the specs that don’t match the grep regex: ng e2e --grep home --invert-grep runs all the specs except the ones containing “home”.

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

Angular 9.0.0 is here!

Angular logo

Ivy, sweet Ivy

This is a long awaited release for the community, as Ivy is now the default compiler/renderer in Angular 🌈.

If you want to learn more about Ivy itself, check out our dedicated blog post.

In a few words, if you’re in a hurry, Ivy is a complete rewrite of the underlying compiler and renderer. The main goals are:

  • a cleaner architecture of the framework, which is a stepping stone to optimizations and new features in the future
  • a faster and stricter compilation, to help developers and avoid slowing them down
  • smaller bundle sizes, especially in big applications right now, and all over the place in the future.

As you can probably imagine, Ivy is a very big change internally, and the team worked a lot to ensure that our applications are compatible. Bundle sizes should improve in the future, as well as runtime performances (which are currently roughly on par with View Engine, faster in some cases, slower in others).

As this is a big change, I strongly encourage you to thoroughly test this update, more thoroughly than the v5, v6, v7 or v8 updates. If you encounter a problem, open an issue with a reproduction, and stay on v8 or use v9 without Ivy for the moment (enableIvy: false).

The new design will allow some cool features in the future, like high order components, a better i18n, etc. For this last point, guess what? It’s already here!

Internationalization with $localize

A new package appears with this release: @angular/localize. This package is now in charge of all i18n concerns, and offers quite a few interesting things.

In fact there are so many topics to cover that we wrote a dedicated article about it: Angular i18n with $localize.

This article talks about compile-time i18n, the much awaited possibility to have translations in code, and how all this works under the hood. Check it out!

Note that even if you are not using i18n in your application, but that one of your dependencies does (like ng-bootstrap for example), then you have to add @angular/localize to your application. This is fairly straightforward:

ng add @angular/localize

But really you should check out the blog post we wrote or the updated chapter in our ebook.

Other i18n goodies

Unrelated to this new package, the locale data now include the directionality of the locale (ltr or rtl). You can get this information by using getLocaleDirection(locale).

Angular 9 also offers the possibility to configure the default currency! The currency pipe allows to specify which currency you want to use by providing an ISO string like USD, ‘EUR’… If you don’t provide one, it uses USD by default. So it is a bit cumbersome to have to specify the currency every time, if your application only uses EUR for example.

Angular 9 introduced the possibility to configure the default currency globally using the token DEFAULT_CURRENCY_CODE:

{ provide: DEFAULT_CURRENCY_CODE, useValue: 'EUR' },

And you can then use currency without specifying EUR in a component. You can also get the currency via dependency injection of course:

@Component({
  selector: 'ns-currency',
  template: `
    <p>The currency is {{ currency }}</p>
    <!-- will display 'EUR' -->
    <p>{{ 1234.56 | currency }}</p>
    <!-- will display '1 234,56 €' -->
  `
})
class DefaultCurrencyOverriddenComponent {
  constructor(@Inject(DEFAULT_CURRENCY_CODE) public currency: string) {}
}

It also offers a getLocaleCurrencyCode(locale) function to retrieve the default currency for a specific locale.

Note that in Angular 10 the behavior will change, and the currency pipe will always use the default currency of the configured locale, even you don’t specify the DEFAULT_CURRENCY_CODE!

Better type-checking

In the Ivy section, I was mentioning that the compilation is a bit stricter. And indeed it is smarter! If you use fullTemplateTypeCheck, you’ll have the same level of strictness that you had before. But if you want to go one step further, you can try the strictTemplates option in your tsconfig.json:

"angularCompilerOptions": {
  "strictTemplates": true
}

Until now, you could for example give a string to @Input() that was expecting a number: you now get a nice compilation error. ngFor elements were previously typed as any, and are now properly typed. So:

<div *ngFor="let user of users">{{ user.nam }}</div>

is now caught by the compiler if you typed nam instead of name. The $event parameter and #ref variables in templates are now also properly typed.

strictTemplates is just a shortcut to activate a bunch of strictness flags, so if one particular check bothers you, you can disable it. For example, if you don’t want to check the type of the inputs:

"angularCompilerOptions": {
  "strictTemplates": true,
  "strictInputTypes": false
}

Check out the official list of flags in the documentation.

As a component author, there is a convoluted way to accept other types than the declared one for your input. It is mostly useful for library maintainers, and you can check out the official documentation for an example.

Better auto-completion

The language service (the package responsible for the nice auto-completion we have in our IDEs) has been improved and now offers some really nice new features. For example if you hover on a component or a directive in template, you’ll see if it is the former or the latter and from which module it comes from. It should be way smarter and more robust overall.

TypeScript 3.7

This release also comes with the need to upgrade to at least TypeScript 3.6, and you can even use TypeScript 3.7. You can check out which new features TS 3.6 and TS 3.7 offers on the Microsoft blog posts (optional chaining, yay \o/).

Automatic migrations

If you are using the CLI ng update @angular/core command, you’ll notice that several automatic migrations will run.

If you are still using the deprecated Renderer, the schematic updates your code to use Renderer2. You can read more about that in the official deprecation guide. The Renderer class was deprecated for a long time and has been removed from Angular.

If you are using a base class for a component or a directive, that base class must be annotated with a simple @Directive() decorator for Ivy. For example:

class WithRouter {
  constructor(public router: Router) {}
}

@Component({
  // ...
})
export class MenuComponent extends WithRouter {
  // uses `this.router` from `WithRouter`

Then after the migration, WithRouter has a @Directive() decorator added on its class:

@Directive()
class WithRouter {
  constructor(public router: Router) {}
}

Note that this @Directive() decorator does not have a selector: this was not possible before v9, and it has been introduced for this use-case specifically.

The @Directive() decorator is also added to your base class if it has decorated fields, like @Input(), @Output(), @ViewChild(), @HostBinding(), etc..

Another migration adds an @Injectable() decorator on all services that don’t have one. It was not necessary for View Engine (check this blog post if you want to know why) but it is now with Ivy. So everything that is referenced as a service in your application must now have an @Injectable() decorator.

ModuleWithProvider must also provide its generic type, so a schematic adds it if it is missing in your code.

You may also remember the static flag added in Angular 8.0, to ease the migration to Ivy. If you don’t, check out what we wrote about it at that time in the Query timing section. This flag is now no longer required now that Angular uses Ivy. So a migration will remove every static: false you have in your codebase, as it is the default value.

All the migrations are properly documented in the official documentation for the v9 update.

Dependency injection

Until now, when using @Injectable(), you could give only two values: an Angular module or root (which is an alias for the root module of your application). It now also accepts platform and any. The latter provides a unique service instance in every module (including lazy modules) that injects the token, and the former could be useful if you have several Angular applications or Angular Elements on the same page, and want them to share a service instance.

Deprecations

entryComponents is no longer necessary

Until now you had to declare the component dynamically loaded, typically in a modal, in the entryComponents of a module. This is no longer necessary with Ivy! You can safely remove entryComponents from your modules.

TestBed.inject

The TestBed.get method that you probably use all over your unit tests has been deprecated and replaced by TestBed.inject. TestBed.get returns any, so you had to manually type the value returned. It is now no longer necessary with TestBed.inject. You can then replace:

const service = TestBed.get(UserService) as UserService;

by

const service = TestBed.inject(UserService);

Breaking changes

NgForm

The directive NgForm used to have ngForm as a possible selector and it’s now no longer the case. It had already been deprecated in Angular 7.0.

Hammer

Until v9, an Angular application was offering Hammer.JS support by default, even if you were not using it. To gain a few kB in our bundles, this is no longer the case, and you’ll have to import HammerModule explicitly in your root module if you want to keep using Hammer.

Intl API

The i18n pipes (number, percent, currency, date) were using the Intl API, and were rewritten to not depend on it in Angular 5.0. The current version of these pipes works without the Intl API. If you really wanted to keep the old version, you had to import DeprecatedI18NPipesModule in your application when migrating to Angular 5.0. This is no longer possible as all the deprecated pipes have been removed.

This is a big update, and I’m sure you’re dying to try it 😎. You can also check out our blog post about the CLI v9 to see what’s new there.

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

Angular CLI 9.0.0 is out!✨

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

Ivy by default

This is probably the most awaited feature in the Angular community: Ivy is now production ready, and the CLI flag enableIvy is now true by default! You can still switch it back to false if you encounter an issue.

You’ll notice that the first build/serve of your application is slightly longer: this is because ngcc needs to compile your dependencies. Once this is done, the dependencies are “Ivy compatible”, and the following builds don’t need to run ngcc again (except if you add a new dependency for example). This should be mostly transparent, as the Angular team did its best to support the most popular libraries. If you encounter an issue with one of your dependencies though, open an issue on the Angular repository, and someone will take a look.

The build and serve commands now use the AoT compiler by default, and you should have re-build times close to what we had in JiT mode previously. In our applications, we even noticed that the tests were way faster, which is super cool! 🚀

Automatic migrations in v9

When running ng update @angular/cli, some schematics are going to update your code:

  • aot: true is added to the default configuration in angular.json. The CLI team is now confident that always working in AoT mode is possible and fast enough with Ivy.
  • enableIvy: true is removed (if present) from your TS config, and the include section is updated to only include the files needed.
  • the anyComponentStyle budget, added in CLI 8.2, is automatically added to your project configuration with a 6kb limit warning.
  • (if you are developing a PWA) the ngsw-config.json file is updated to include manifest.webmanifest which is now necessary in modern Chrome versions.
  • the styles and scripts option lazy in angular.json has been deprecated and replaced by a new inject property which has the opposite meaning (lazy: true = inject: false if you don’t want to inject the style or script in your HTML page). The schematic automatically handles the migration.

If your project is a library and not an application, it is also automatically updated. The migration:

  • adds enableIvy: false to the TS config, to ensure compatibility with previous Angular versions.
  • removes the now useless tsickle dependency and the annotateForClosureCompiler from the TS config.

Multiple configurations support

The ng build command now allows to use several configurations! Previously you had to use only one, which was cumbersome because you had to duplicate every property in every configuration.

Now you can use:

ng build --configuration=production,fr

The command then uses the production configuration, merged with the fr configuration. The fr configuration can re-declares a property of the production configuration, to overwrite it.

Generate interceptors

The CLI offers a new generator to easily create interceptors!

ng generate interceptor auth

This creates an AuthInterceptor class in auth.interceptor.ts. But it does not register the interceptor for you. You have to do it manually as you usually do with { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor }. Still nice to have though!

Fun with flags

ng new

The enable-ivy flag has been removed (as Ivy is now enabled by default). A new --strict flag has been added. You can use it to generate a project with a stricter TypeScript configuration (with noImplicitAny, noImplicitReturns, noImplicitThis, noFallthroughCasesInSwitch, and strictNullChecks enabled).

A new option named package-manager has also been added, allowing to specify which package manager you want to use when creating the project. The supported values are npm, yarn, pnpm and cnpm. If you specify a value, then the value is stored in your angular.json file.

ng generate component

You can now specify a type when generating a component:

ng generate component --type container hello

This generates files with a container suffix (hello.container.ts, hello.container.html…), and a component named HelloContainer instead of HelloComponent.

You can also now add a displayBlock flag if you want to generate a style containing :host { display: block; }.

Also note that the styleext and spec flags have been definitely removed, so you must now use style and skipTests instead.

ng generate guard

You can now specify that you want a CanDeactivate guard in addition to the already supported CanActivate, CanActivateChild, and CanLoad. I realized it was missing when working on an application for a customer, so I added it 🤓.

ng serve

The serve command now accepts a --allowed-hosts flag, to specify the hosts allowed to access your application.

ng build

The build command now has an --experimental-rollup-pass flag. The name is explicit enough: this is an experiment! The build leverages Rollup to, hopefully, generate smaller bundles than a raw Webpack build. This is highly experimental and does not work with various dependencies, as they need to be packaged in a format that Rollup can work with. You can give it a try and see by yourself on your project though.

ng update

It is now possible to ask the CLI to create one commit per migration done by using ng update --create-commits.

i18n - internationalization support with @angular/localize

As Angular v9 brings a re-written support for i18n, the CLI also includes some i18n-related changes. In fact there is so much to tell, that the best is to check our dedicated article about internationalization.

TL;DR: it’s now much faster to generate the N localized versions of your application, as the CLI first compiles it, and then just generates the localized versions by replacing the messages by theirs translations in the compiled output. It is even generated in parallel if possible!

As the options to give the serve and build commands changed, the CLI offers an automatic migration from the old to the new options.

Note also a tiny but useful feature: when building an application with i18n, the document locale is now set using the lang attribute on the html root element. For example, if you build your application in French, then the index.html file contains <html lang='fr'>. Until now, you could of course do it by hand, but it was cumbersome. It’s now handled automatically!

ng add for library authors

You may know that the CLI supports a ng add command to add dependencies to your project:

  • if the dependency has an “add” schematic, it runs it.
  • if it does not, ng add simply adds the dependency to your package.json.

So, as a library author, you probably want to offer such a schematic, to simplify the setup of your library. The weird thing was that, if you wrote such a schematic, you had to handle the addition to the package.json file yourself. This has now been simplified with a save option, that you can configure for ng-add in the package.json of the library. save accepts:

  • false, if you don’t want to save it;
  • true or dependencies if you want to save it as a dependency;
  • devDependencies if you want to save it as a dev dependency.

Our own open-source libraries ngx-valdemort and ngx-speculoos are now up-to-date with Angular v9 and offer a ng-add schematics. You can easily give them a try with ng add ngx-valdemort or ng add ngx-speculoos 🙌.

As you can see, this 9.0 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!


Posts plus anciens