Kotlin logo

Cyril and Agnès already told you about our side project for Globe 42, a local non-profit organization which helps old migrants in Saint-Etienne. We started this project as a traditional Spring Boot Java backend, with an Angular frontend. The backend uses Spring MVC to expose RESTful endpoints, and uses JPA to access a PostgreSQL database. The whole application is built with Gradle.

We finally decided to migrate it to Kotlin: it’s a nice medium-sized project to learn more about it, and, having already played with Kotlin and liking it a lot, there was no reason not to do it.

We also decided to migrate the gradle scripts to the Kotlin DSL. If that’s what you’re interested about, you can jump to the last section of this article.

Here’s how it went. If you’re interested into the end result, the code is on GitHub.

Strategy

I did everything by myself, in a single pass: everything (except the gradle build) was migrated in a single (but long) day. Small refinements and adjustments were brought in later.

Beware though. Globe42 is a relatively small project (around 10,000 lines of Java code, not counting comments and blank lines, but including tests). For a larger project, it would probably be wiser to split such a migration into smaller pieces. But anyway, the strategy I adopted can probably be used.

This migration was also made easy by the facts that I already had this idea of migrating it to Kotlin when the project was started, and the code was written with most of the best practices making it easy to migrate and making the code Kotlin-friendly: constructor injection, immutable DTOs, etc.

I began without a real plan, taking the first package arbitrarily, and migrating it. This wasn’t a good idea: the package depended on other downstream packages (still written in Java). This means that the migrated code still used a lot of platform types, although I knew that these platform types would disappear later during the migration. I would thus have to come back to the migrated code later, once its downstream dependencies would have been migrated. It became clear that the good strategy was to start with the lowest layers of the code (entities, DTOs), then go up through the layers (DAOs, then services and controllers, and finally tests).

The migration was in fact largely automated by IntelliJ, which has a nice Convert Java file to Kotlin action. Note that, despite its name, this action can actually be executed on several files, or a whole directory at once.

Migration issues

The converter does a pretty good job, but isn’t perfect, and can’t read in your mind. Here are some of the things I had to change manually.

Constants

The code uses static final fields as values of annotation attributes:

    private static final String PERSON_GENERATOR = "PersonGenerator";
    
    @SequenceGenerator(name = PERSON_GENERATOR, sequenceName = "PERSON_SEQ")

The converter transforms the constant to a field of the companion object of the class:

    companion object {
        private val PERSON_GENERATOR = "PersonGenerator"
    }

    @SequenceGenerator(
        name = PERSON_GENERATOR,
        sequenceName = "PERSON_SEQ"
    )

But only const val can be used as a value of an annotation attribute. So that code doesn’t compile.

Field injections

The production code actually has one field injection:

    @PersistenceContext
    private EntityManager em;

The converter converts it to

    @PersistenceContext
    private val em: EntityManager? = null

This is technically correct. But not semantically correct. The code will never see em as null. It’s just that it will be initialized right after construction by Spring. So the semantically correct code is

    @PersistenceContext
    private lateinit var em: EntityManager

Another place where there are lots of field injections is in tests (using the @Mock and @InjectMocks annotations of Mockito, and the @MockBean annotation of Spring). Once again, all those have to manually be changed to lateinit var instead of nullable properties.

Not null fields of JPA entities

JPA entities work basically the same way as field-injected Spring beans. When reading an entity from the database, JPA constructs it by using the no-arg constructor, and then populates its fields. This means that, although a person always has a gender in the database, the gender field of the entity is initially null, and then populated by JPA.

So, the following code

    @NotNull
    private Gender gender;

is converted to

    @NotNull
    var gender: Gender? = null

Once again, this is technically correct, but not semantically correct. The gender is not supposed to be null. It’s just always supposed to be initialized after construction.

Note that even in the case of the creation of a new person (where our own code invokes the constructor and populates the entity), the gender is supposed to be set, either directly in the constructor, or right after construction, before it’s ever being read.

So I decided to change this code to

    @NotNull
    lateinit var gender: Gender

It should now be clearer why starting with the downstream layers of the code is a better idea. Having a Gender rather than a Gender? here allows upstream layers to rely on this non-null type, and thus makes the code simpler, more idiomatic, and easier to convert (since the Java code already made that assumption that the gender could never be null).

Entity IDs

We use Long for most of our entity IDs. And they are all auto-generated by JPA. Once again, this means that technically, the ID is nullable, but that semantically, the ID should never be read as null: either the entity is read by JPA and the ID is not null, or the entity is created, and we should make sure that the ID is generated (by flushing the EntityManager if necessary) before we read it.

Unfortunately, Kotlin doesn’t support lateinit var for Long.

The code

    lateinit var id: Long

doesn’t compile: 'lateinit' modifier is not allowed on properties of primitive types.

This is surprising to me. Maybe I’m missing something, but Kotlin could deal with this for me by using a java.lang.Long instead of a long, just as it does transparently when using a property of type Long? rather than Long.

But I can’t do much about that, and I preferred not using a primitive type as the ID (Hibernate recommends using nullable, non-primitive types for generated IDs). So I kept using var id: Long? for our IDs, even though it forces us to use the !! operator (in tests mainly). Maybe we’ll change this strategy later. If you have an explanation on why Kotlin doesn’t allow lateinit var on Long, I’d be happy to learn about it.

DTOs

Our DTOs (sent as JSON from the server, or received as JSON from the browser) were really meant, from the beginning, to be immutable data classes. Except data classes don’t exist (yet) in Java. And IntelliJ can’t read in your mind. So we converted all our DTOs to data classes by hand.

Note that we didn’t use data classes for the JPA entities. This is an anti-pattern to me, for the following reasons:

  • in general, I prefer not to have hashCode() and equals() methods in entities. And data classes do have such methods. equals() and hashCode() on entities are most of the time semantically incorrect because entities are mutable, and are stored in HashSets when used in toMany associations, which break the HashSet contract.
  • It’s sometimes possible, but hard, to write equals() and hashCode() methods correctly for entities, but they should not use their auto-generated ID. And data classes include all the fields of the class in those methods.

Stream operations

This is where the converter really does a bad job at converting code. This simple, idiomatic Java line of code:

    public List<CountryDTO> list() {
        return countryDao.findAllSortedByName()
                         .stream()
                         .map(CountryDTO::new)
                         .collect(Collectors.toList());
    }

is converted to this non-compiling Kotlin monstruosity:

    fun list(): List<CountryDTO> {
        return countryDao.findAllSortedByName().stream()
            .map<CountryDTO>(Function<Country, CountryDTO> { CountryDTO(it) })
            .collect<List<CountryDTO>, Any>(Collectors.toList())
    }

So I changed all these pieces of code to the following idiomatic Kotlin code:

    fun list(): List<CountryDTO> {
        return countryDao.findAllSortedByName().map(::CountryDTO)
    }

Tests

We use Mockito a lot in our tests. And using Mockito with Kotlin is only really possible with the mockito-kotlin library. So I had to manually change all the calls to when, verify, any, etc. by calls to the mockito-kotlin extension functions (whenever, etc.)

The idiomatic way of naming a test method in Kotlin is to use a real sentence. So I wrote and executed a simple script to change all the methods like

    fun shouldNotUpdateMediationCodeIfLetterStaysTheSame()

to

   fun `should not update mediation code if letter stays the same`()

Meta annotations

This is the only thing that we could not migrate to Kotlin. We have the following meta-annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ExtendWith(SpringExtension.class)
@WebMvcTest(
    excludeFilters = @ComponentScan.Filter(
        type = FilterType.ASSIGNABLE_TYPE,
        classes = {AuthenticationConfig.class}))
public @interface GlobeMvcTest {
    @AliasFor(annotation = WebMvcTest.class, attribute = "value")
    Class<?>[] value() default {};
}

I tried everything I could to convert this annotation to Kotlin, until I realized that it was actually not possible due to this known bug: it’s impossible to apply an annotation to an annotation method in Kotlin. So this is the only Java class remaining in our code.

Git history

Renaming files from .java to .kt and converting their content from Java code to Kotlin code in a single commit confuses Git, which thinks you just deleted a bunch of files and created a bunch of newer ones. To preserve the history and help reviewers, I had to rewrite the history, by first creating a commit which only renames files (without changing their content), then a second commit applying the changes.

Takeaways

The takeaway is the following: it’s possible to convert to Kotlin, and the automatic converter helps a lot, but you should start with the downstream, lower layers of the code, and you will have to apply manual adjustments to the converted code, either to fix it, or to make it cleaner and more idiomatic.

In the end, I’m very happy with the result. The code is easier to read. We didn’t actually find bugs thanks to the migration, but the code is now cleaner, and reduced from approximately 10,000 lines of code to 8,000 (mainly due to getters and setters being removed).

We found two small negative side effects though:

  • the code coverage, measured by Jacoco, went down significantly. The reason is that data classes contain a lot of generated code (equals, hashCode, copy, component1, component2, etc.) that are never actually used in the code. Not a big deal, but if you have a way to configure jacoco to ignore those methods, I’d be happy to learn about it.
  • the compilation time (which is a ridiculous time compared to the time needed to run the tests, and even more ridiculous compared to the time needed to build the frontend) went from 3 seconds in Java to 10 seconds in Kotlin. This shows how remarkably fast the Java compiler is, and how the Kotlin compiler can probably improve.

Migrating the Gradle build

Migrating the groovy-based gradle scripts to Kotlin was the next natural step. This is much faster to do, because there is much less code to migrate. The difficulty is the lack of documentation. So I wrote a migration guide.

Gradle’s reaction was excellent. Since I wrote it, eskatos, from the Gradle team, kindly improved it, and contacted me to tell me that it would soon become the basis for an official gradle guide, and to ask for contribution to the Kotlin DSL documentation.

So the Gradle documentation should soon include Kotlin examples and guides in addition to Groovy ones \o/.


JB Nizet


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


Depuis un an Ninja Squad donne de son temps pour le développement d’un logiciel un peu particulier. Il s’agit d’un outil sécurisé pour une association, Globe 42 qui propose un espace d’éducation populaire et de santé communautaire pour des personnes migrantes agées. Ninja Squad avait envie d’aider bénévolement cette association qui n’avait pas les moyens de s’offrir le développement d’une application permettant de simplifier leur quotidien.

Présentation de l’association Globe42

Mais qu’entend-on par « santé communautaire » ? D’après l’OMS c’est un « processus par lequel les membres d’une collectivité, géographique ou sociale, conscients de leur appartenance à un même groupe, réfléchissent en commun sur les problèmes de leur santé, expriment leurs besoins prioritaires et participent activement à la mise en place, au déroulement et à l’évaluation des activités les plus aptes à répondre à ces priorités ». L’approche consiste donc à co-construire, avec les personnes qui ont besoin de soins, les bons outils et les bonnes pratiques pour faire en sorte qu’elles aillent réellement mieux. Par exemple, quand un migrant qui parle mal le français et ne le lit pas, voit un médecin : comment faire en sorte qu’il comprenne bien le contenu de l’ordonnance, qu’il change ses pratiques alimentaires si besoin. Ce n’est pas simple à envisager si la prescription s’arrête à la visite d’un quart d’heure dans le cabinet médical. D’où l’idée d’un espace communautaire, où on peut à la fois apprendre le français, parler avec des personnes qui sont dans la même situation, partager un repas, des moments de convivialité, et apprendre à mieux prendre soin de soi.

Malika Lebbal a lancé cette association après plusieurs années de missions classiques d’assistante sociale, et plusieurs années également de bénévolat au sein d’un collectif de soutien pour des sans-papiers.

Malika Lebbal

Après 15 années d’expérience, Malika voulait donc se lancer dans un projet différent, un espace de santé communautaire, bienveillant, où on dépasse les positions parfois trop éloignées entre travailleurs sociaux et personnes qui ont besoin d’aide. Malika parle souvent d’un objectif de « partage de pouvoirs et de savoirs ». Elle s’est inspirée d’exemples comme La case de santé à Toulouse, La place de santé en Seine Saint-Denis, des centres de santé communautaire à Montréal ou à Bruxelles.

Globe42 nait ainsi en 2009 et se focalise rapidement sur les difficultés spécifiques des femmes migrantes âgées, sur le plan de l’accès aux droits et à la santé. L’association ouvre un local à Saint-Etienne, dans le quartier de Chavanelle, là où résident deux ninjas (ceux qui se sont reproduits, et qui ont leurs deux ninjas juniors dans l’école de quartier à 100 mètres du local de Globe42).

Affiche ouverture local Globe 42

Malika a entrepris en 2012 une formation continue, un Master 2. Elle a entamé une recherche action sur le thème de la santé des femmes migrantes âgées. Le choix de la recherche action n’était pas anodin : elle souhaitait que les femmes soient actrices de la recherche, et voyait « la recherche action comme un outil conscientisant avec une démarche collective d’appropriation des données et d’élaboration de réponses adaptées ».

Haaaa mais ça parle de données… un vrai besoin de collecte de données « éthique » (anonymisée, sécurisée) apparaît donc, un truc de ninjas ça !

L’application

Les membres de l’association assuraient, jusqu’alors, la gestion de ces données sur leurs membres sans l’aide de l’informatique, pour écarter toute faille de confidentialité qu’un non-spécialiste peut craindre, notamment vis-à-vis du cloud. Il y avait donc une vraie perte de temps et surtout elles ne pouvaient pas croiser certains chiffres qui pouvaient les aider : combien de personnes se rendent aux repas, aux médiations de santé ? Combien de temps passent les membres de l’association sur la médiation sociale, sur l’accueil… ? Elles géraient sur des carnets de note papier le suivi de chaque migrant : les procédures en préfecture, l’état d’avancement des demandes de cartes de séjour, bref, toutes ces informations étaient non informatisées !

Nous avons voulu donc aider cette association en proposant bénévolement nos services de développeurs. Non seulement nous nous offrions un side-project pour pratiquer les technologies du moment (Angular 6, Spring Boot 2, Kotlin, JUnit 5, …) sur une vraie application, mais nous en profitions pour aider une association qui le méritait, et dont on pouvait ainsi faciliter le travail.

Si cela vous intéresse, le code est sur Github. Merci au passage à Clever Cloud qui a accepté de donner une instance gratuite pour l’hébergement de l’application.

Le travail des ninjas

Il est compliqué de dire exactement combien de temps cela nous a pris, 70 à 80 jours peut-être depuis 18 mois, nous ne sommes pas des fans de l’imputation ! On s’est appliqués à suivre, comme dans n’importe quel projet corporate, un processus itératif : on passe du temps à discuter avec les membres de l’association, à comprendre leurs besoins (on participe aux repas du jeudi de l’association, qui mettent à l’honneur un plat d’un pays, cuisinés par une personne migrante et qui réunissent 20 à 30 personnes autour d’une grande tablée).

Repas à Globe42

On est un peu plus calés sur les cartes de séjour maintenant, on se doutait bien qu’il n’était pas facile d’être une personne migrante, mais la complexité administrative pour obtenir des titres de séjour aujourd’hui en France est assez impressionnante. Une fois que les besoins de l’association sont énoncés, priorisés, on se donne quelques semaines pour les implémenter. On se rend de nouveau au local de l’association pour un échange avec les membres (on privilégie le point présentiel, jamais de remote) : on leur fait une démo de ce qu’on a produit, on récolte leur avis, et on prend en compte de nouveaux besoins. Et ainsi de suite, on réitére. Entre chaque rencontre, les membres de l’association utilisent vraiment les nouvelles fonctionnalités, au quotidien. Nous n’avons pas de serveur de recette, suite à la démo et à la correction éventuelle de certains points si nécessaire, on relivre une nouvelle version de l’application en production. Les membres de l’association sont passés ainsi d’un mode tout papier à un mode un peu plus hybride (il y a encore du papier mais beaucoup moins !), un mode beaucoup plus informatisé.

L’engagement des personnes de ce collectif est tellement fort qu’on se sent tout petits vis-à-vis d’elles. Notre implication sur ce projet autour de la santé des personnes migrantes agées est bien sûr modeste, mais c’est une grande satisfaction pour nous de voir qu’on peut les aider à être plus efficaces, on se rend compte à quel point l’application a pu leur faciliter la vie, et ça pour des développeurs c’est quand même chouette!

Vous aussi devenez tech-activist ✊

En tant que développeur, on se demande parfois comment on peut aider des personnes, des associations, des centres sociaux, comment on peut être utile sur des projets sociaux. Sachez que vos compétences techniques peuvent grandement aider. On peut vous garantir qu’il y a pléthore de demandes, il suffit de pousser la porte de certaines structures de votre quartier !

Idalin Bobé lors de la mémorable keynote à MiXiT, en 2016, sur le Tech Activism, nous avait amenés à réfléchir à cette question : quelle contribution sociétale voulons-nous apporter à travers notre métier ? Elle nous encourageait à mettre à disposition, ne serait-ce que quelques heures par mois, nos compétences au service de projets à impact sociétal ou environnemental.

Idalin Bobé

On parle souvent des logiciels et applications, notamment ceux des GAFAM, qui introduisent des algorithmes régissant de manière souvent trop intrusive nos vies, qui peuvent parfois contribuer à ne pas faire en sorte que notre monde aille mieux. Et bien vous pouvez aussi contribuer, tout modestement cela soit-il, à inverser la tendance !


Agnès Crépet


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


Angular 6.0.0 is here!

Angular logo

It has a really big novelty which is not really a feature: the new Ivy renderer. As it is still experimental, I’ll close this article with it. We’ll start at first with the other new features and breaking changes.

We made a little video to give you an overview of the new features. If you want to dive deeper into what has changed, keep on reading after watching it ;).

Tree-shakeable providers

There is now a new, recommended, way to register a provider, directly inside the @Injectable() decorator, using the new providedIn attribute. It accepts 'root' as a value or any module of your application. When you use 'root', your injectable will be registered as a singleton in the application, and you don’t need to add it to the providers of the root module. Similarly, if you use providedIn: UsersModule, the injectable is registered as a provider of the UsersModule without adding it to the providers of the module.

@Injectable({
  providedIn: 'root'
})
export class UserService {

}

This new way has been introduced to have a better tree-shaking in the application. Currently a service added to the providers of a module will end up in the final bundle, even if it is not used in the application, which is a bit sad. And if you use lazy-loading, you can fall in a bunch of traps or end up with the service bundled in the “wrong” place.

It should not happen often in applications (if you write a service, you usually use it), but third party modules sometimes offer services that you don’t use, and you end up with a big bundle of useless JavaScript.

So it will be especially useful for library developers, but it is now the recommended way to register an injectable even for application developpers. The new CLI will even scaffold a service with providedIn: 'root' by default now.

In the same spirit, you can now declare an InjectionToken and directly register it with providedIn and give it a factory:

 export const baseUrl = new InjectionToken<string>('baseUrl', {
    providedIn: 'root',
    factory: () => 'http://localhost:8080/'
 });

Note that it also simplifies unit testing. We used to register the service in the providers of the testing module to be able to test it. Before:

beforeEach(() => TestBed.configureTestingModule({
  providers: [UserService]
}));

Now, if the UserService uses providedIn: 'root':

beforeEach(() => TestBed.configureTestingModule({}));

Don’t worry though: all the services registered with providedIn aren’t loaded in the test, they are instantiated lazily, only when they are really needed.

RxJS 6

Angular 6 now uses RxJS 6 internally, and requires you to update your application also.

And… RxJS 6 changed the way to import things!

In RxJS 5, you were probably writing:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';

const squares$: Observable<number> = Observable.of(1, 2)
  .map(n => n * n);

RxJS 5.5 introduced the pipeable operators:

import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { map } from 'rxjs/operators';

const squares$: Observable<number> = of(1, 2).pipe(
  map(n => n * n)
);

And RxJS 6.0 changed the imports:

import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';

const squares$: Observable<number> = of(1, 2).pipe(
  map(n => n * n)
);

So, one day, you’ll have to change the imports across your application. I say “one day” and not “right now” because RxJS released a library called rxjs-compat, that allows you to bump RxJS to version 6.0 even if you, or one of the libraries you’re using, is still using one of the “old” syntaxes.

The Angular team wrote a complete document to explain all this, it’s a must read when you’ll start your Angular 6.0 migration.

Note that a very cool set of tslint rules has been released called rxjs-tslint. It just contains 4 rules that, when added to your project, will automatically migrate all your RxJS imports and RxJS code to the brand new version with a simple tslint --fix! Because, if you don’t know about it, tslint has a fix option that will autocorrect all the violations it can! It can be used in an even simpler way by installing globally rxjs-tslint and running rxjs-5-to-6-migrate -p src/tsconfig.app.json. I gave rxjs-tslint a try on one of our projects, and it worked fairly well (run it at least twice to also collapse all the imports). Check out the project README to learn more: https://github.com/ReactiveX/rxjs-tslint.

If you want to discover more about RxJS 6.0, you can watch this talk by Ben Lesh at ng-conf.

i18n

The big one for i18n is the upcoming possibility to have “runtime i18n”, without having to build the application once per locale. This is not yet available (there are just prototypes for now), and it will need the Ivy renderer to work (continue reading to know what that is). So we will probably have to wait a few weeks/months before using it.

Another i18n-related change has landed, and this one is immediately available. The currency pipe was improved in a way that makes a lot of sense: it will not round every currency with 2 digits anymore, but will round the currency to the most appropriate digit number (which can be 3 like for the Arabic Dinar of Bahrain, or 0 like for the Chilean Pesos).

If you need to, you can retrieve this value programmatically by using the new i18n function getNumberOfCurrencyDigits.

Other formatting functions have also been exposed publicly, like formatDate, formatCurrency, formatPercent, and formatNumber.

Pretty handy if you need to apply the same transformations than what the pipes do, but from within your TypeScript code.

Animations

The polyfill web-animations-js is not necessary anymore for animations in Angular 6.0, except if you are using the AnimationBuilder. Your application may have won a few precious bytes! In the case that the browser does not support the element.animate API, Angular 6.0 will fallback to CSS keyframes.

Angular Elements

Angular Elements is a project that lets you wrap your Angular components as Web Components and embed them in a non-Angular application. This project has been existing for a few months but was in the “Angular Labs” previously (in other words, was still experimental). With v6, it’s now a little bit pushed in the front and officially part of the framework. As it is a big topic by itself, we have a dedicated blog post about it (coming soon).

ElementRef<T>

When you want to grab a reference to an element in your template, you can use @ViewChild or @ViewChildren or even inject the host ElementRef directly. The drawback, in Angular 5.0 or older, is that the said ElementRef had its nativeElement property typed as any.

In Angular 6.0, you can now type ElementRef more strictly if you want:

@ViewChild('loginInput') loginInput: ElementRef<HTMLInputElement>;

ngAfterViewInit() {
  // nativeElement is now an `HTMLInputElement`
  this.loginInput.nativeElement.focus();
}

Deprecations and breaking changes

Let’s talk about what you should be aware of before attempting a migration!

preserveWhitespaces: false by default

In the “bad things that can happen when you upgrade” section, note that preserveWhitespaces is now false by default. This option was introduced in Angular 4.4, and if you want to know what to expect, you should read our blog post about that. Spoiler: it may be completely fine or break your layouts.

ngModel and reactive forms

It used to be possible to have ngModel and formControl on the same form fields, but this is now deprecated and the support will be removed in Angular 7.0.

It was a bit confusing and was probably not doing exactly what you were expecting (ngModel was not the directive you know, but an input/output on the formControl directive doing slightly the same job, but not exactly the same job). We thought it was confusing too, so we removed the chapter talking about that in our ebook 6 months ago.

So using code like:

<input [(ngModel)]="user.name" [formControl]="nameCtrl">

will now yield a warning.

You can configure your app to emit the warning always (the default), once or never:

imports: [
  ReactiveFormsModule.withConfig({
    warnOnNgModelWithFormControl: 'never'
  });
]

Anyway, to prepare for Angular 7, you should migrate your code to use either a template-driven form or a reactive form.

Project Ivy: the new (new) Angular renderer

Soooo…. This is the 4th major release of Angular (2, 4, 5, 6), and the 3rd rewrite of the renderer!

For those who don’t know: Angular compiles your templates into equivalent TypeScript code. This TypeScript code is then compiled along with the TypeScript you wrote into JavaScript code, and the result is shipped to your users. And we are now on the 3rd version of this Angular renderer (the first was in the original release Angular 2.0, and the second in Angular 4.0).

This new version of the renderer does not change how you write your templates, but comes with improvements in several fields:

  • build time
  • bundle size

This is still very experimental, and the new Ivy renderer is behind a flag that you have to explicitly set in the compiler options (in the tsconfig.json file) if you want to give it a try.

"angularCompilerOptions": {
  "enableIvy": true
}

Be warned that it is probably not very reliable, so don’t use it in production right now. It will probably not even work right now. But it will become the default in a near future, so you can give it a spin to see if that works for your app, and what you gain.

Let’s dive into what differs between the old renderer, and the Ivy renderer. You can skip the following sections if you are not interested in the details.

Code generated with the old renderer

Let’s take a small example: a PonyComponent taking a PonyModel (with a name and a color) as input, and displaying an image depending on the color, and displaying the name of the pony.

It looks like:

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

  getPonyImageUrl() {
    return `images/${this.ponyModel.color}.png`;
  }
}

The renderer introduced in Angular 4 generated a class for each template, called a ngfactory. It would contain (simplified code):

export function View_PonyComponent_0() {
  return viewDef(0, [
    elementDef(0, 0, null, null, 4, "div"),
    elementDef(1, 0, null, null, 1, "ns-image", View_ImageComponent_0),
    directiveDef(2, 49152, null, 0, i2.ImageComponent, { src: [0, "src"] }),
    elementDef(3, 0, null, null, 1, "div"),
    elementDef(4, null, ["", ""])
  ], function (check, view) {
    var component = view.component;
    var currVal_0 = component.getPonyImageUrl();
    check(view, 2, 0, currVal_0);
  }, function (check, view) {
    var component = view.component;
    var currVal_1 = component.ponyModel.name;
    check(view, 4, 0, currVal_1);
  });
}

This is hard to read, but the main parts of this code are:

  • the structure of the DOM to create, containing element definitions (figure, img, figcaption), their attributes, and text node definitions. Each part of the DOM structure in the view definition array is represented by its index.
  • change detection functions, containing the code used to check if the expressions used in the template evaluate to the same values as before. Here, it checks the result of the getPonyImageUrl method and if it changes, updates the value of the input of the image component. Same with the name of the pony: if it changes, it updates the text node displaying it.

Code generated with Ivy

With Angular 6 and the enableIvy flag set to true, the same example doesn’t generate a separate ngfactory but inlines the information directly in a static field of the component itself (simplified code):

export class PonyComponent {

    static ngComponentDef = defineComponent({
      type: PonyComponent,
      selector: [['ns-pony']],
      factory: () => new PonyComponent(),
      template: (renderFlag, component) {
        if (renderFlag & RenderFlags.Create) {
          elementStart(0, 'figure');
          elementStart(1, 'ns-image');
          elementEnd();
          elementStart(2, 'div');
          text(3);
          elementEnd();
          elementEnd();
        }
        if (renderFlag & RenderFlags.Update) {
          property(1, 'src', component.getPonyImageUrl());
          text(3, interpolate('', component.ponyModel.name, ''));
        }
      },
      inputs: { ponyModel: 'ponyModel' },
      directives: () => [ImageComponent];
    });

    // ... rest of the class

}

Everything is now contained in this static field. The template attribute contains the equivalent of the ngfactory we used to have, but with a slightly different structure. The template function will be run on every change like before, but has 2 modes:

  • a creation mode when the component is first created and which contains the static DOM nodes to create
  • the rest of the function executed on every change (update the image source if necessary and the text node).

What does that change?

All decorators are now inlined directly into their classes (it’s the same for @Injectable, @Pipe, @Directive) and can be generated with only the knowledge of the current decorator. This is what the Angular team calls the “locality principal”: to re-compile a component, there is no need to analyze the application again.

The generated code is slightly smaller, but more importantly some dependencies are now decoupled, allowing for a faster recompilation when you change one part of the application. It also plays much nicer with modern bundlers like Webpack, and will now really tree-shake the parts of the framework that you don’t use. For example if you have no pipe in your application, the code in the framework that is necessary to interpret pipes is not even included in the final bundle.

Angular used to produce heavy code. That’s not necessarily a problem, but an Hello World application was way too heavy: 37kb after minification and compression. With Ivy-generated code, the tree-shaking process is much more efficient, resulting in smaller bundles \o/. The Hello World is now 7.3kb minified, and only 2.7kb after compression, which is a huuuuuge difference. The TodoMVC app is 12.2kb after compression. These numbers are from the Angular team, and we couldn’t come with some others as you still have to manually patch Ivy to make it work as we speak.

Check out the keynote from ng-conf if you want to learn more.

Compatibility with existing libraries

You might be wondering what will happen with libraries that have already been published using the previous packaging format if your project uses Ivy. Don’t worry, the renderer will produce Ivy-compatible version of the dependencies of your project, even if they are not compiled with Ivy. I’ll spare you the gory details, but it should be transparent to us.

New features

Let’s see what new features we’ll have with this new renderer.

Private properties in templates

The new renderer adds a new feature or potential change.

It is a direct result of the fact that the template function is inlined in a static field of the component: we can now have private properties of our components used in templates. This was not possible until then, and forced us to have all the fields and methods of the component used in the template to be public, as they ended up in a different class (the ngfactory). Accessing a private property from another class would have failed the TypeScript compilation. This is no longer the case: as the template function is inside a static field, it has access to the private properties of the component.

I saw a comment from the Angular team saying that it was not recommended to use private properties in templates, even if it is now possible, as it may not be the case in the future… So you should probably continue to use only public fields in your templates! Anyway, it makes unit tests easier to write, as the test can inspect the state of the component without having to actually generate and inspect the DOM to do so.

Runtime i18n

Note that this new renderer will now allow to have the much awaited possibility of having “runtime i18n”. This is not completely ready, but we saw a few commits that are good signs!

The cool thing is that you should not have to change your application a lot if you are already using i18n. But this time instead of building your application one time for each locale you want to support, you will be able to just load a JSON containing the translations for each locale, and Angular will take care of the rest!

Libraries with AoT code

Right now, a library released on NPM must publish a metadata.json file, and can’t publish the AoT code from its components. Which is sad, because we have to pay the cost of this build in our applications. With Ivy, the metadata file is no longer necessary and library authors should be able to directly ship AoT code to NPM!

Better stack traces

The generated code should now allow for better stack traces when you have an issue in your templates, by yielding a nice error with the line of the template at fault. It will even allow us to put break points in the templates and see what really is going on in Angular.

NgModule will disappear?

It is a far-fetched goal, but in the future we might not need NgModules anymore. This is what tree-shakeable providers are starting to tell us, and it looks like Ivy has the necessary starting blocks for the team to try to remove the need for NgModules (or at least make them less annoying). This is not for right now though, we’ll have to be patient.

This release doesn’t bring a lot of new features, but Ivy is definitely interesting for the future. Give it a try and tell us how it goes for you!

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


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


Angular CLI 6.0.0 is out with some nice new features!

The version number can be a bit surprising as the last release was… 1.7! The Angular team decided to now release the CLI with the rest of the framework, hence the big jump. Check out our article about Angular 6.0 if you haven’t!

But it is also a big major release because the internals have changed to offer us more possibilities! Note that the update might not be straightforward, as a few things have changed.

If you want to upgrade to 6.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 (1.2.1 for example), and the target version (6.0.0 for example), and it gives you a diff of all files created by the CLI: angular-cli-diff/compare/1.2.1…6.0.0. You have no excuse for staying behind anymore!

Let’s see what new features we have!

Support for libraries and multiple applications

This was a long time request from developers, and now we have it! It’s possible with this new version to have several applications in the same CLI project (now called a workspace), and to create libraries (a shared set of components, directives, pipes and services)!

It will now be easier to share a few components across multiple applications for example. A new schematic has been added to help you generate a library.

Just run ng generate library, and it will scaffold the necessary in the projects directory. It relies upon ng-packagr, which was the de facto tool to create Angular libraries, because it handles all the details of packaging the library following the official Angular Packaging Format. Based on ng-packagr, the CLI can now build a library, and produces all the required files (es5 bundle, esm2015 bundle, umd bundle, metadata file for AoT compilation, public API file…). I’m not an expert on the topic, but it looks like you just need to npm publish the result and you’re good to go!

You can also have several applications in your project, with ng generate application. Actually you already have two now by default: your main application and an application containing the e2e tests.

The cool thing is that you can directly import from the library into your applications in the same CLI project, even without publishing the library on NPM.

For example, let’s say you generated a shared library. By default the CLI will produced a shared directory inside projects, with a ShareComponent and a SharedService. You’ll have something like:

cli-6
- projects
-- shared
--- src
---- lib
----- share.module.ts
----- share.component.ts
----- share.service.ts
- src
-- app
--- app.module.ts
--- app.component.ts
--- ...

If you want to use the SharedService inside your application, for example in app.component.ts, you simply have to import:

import { Component } from '@angular/core';
import { SharedService } from 'shared';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  constructor(sharedService: SharedService) {
    // note the import at the top!
  }
}

And the CLI will handle it!

This opens great possibilities for large project, and for developers to open source libraries of useful components and services!

A slightly annoying thing right now: when you make a change to the library source, you’ll have to rebuild it manually if you want the rest of the project to see it, because there is no watch mode for ng build in a library (yet).

A new architecture

The CLI as you knew it has been broken down into several small pieces to allow the multi-projects/libraries architecture.

Most of what used to live in the CLI now lives in various schematics. In fact, pretty much everything is a schematic now, and the CLI is just a “schematic runner”. The CLI role is now to execute commands, and it does so with its new “Architect” package (@angular-devkit/architect).

The run command of architect accepts a target (which command to execute) and a project. So, in theory, all commands should be like:

 ng run <project>:<target>[:configuration] [...options]

But a few commands are a special case and can be run directly, like build, lint, test, xi18n. ng serve and ng e2e needs the project to be specified, except if there is just one with this target in the workspace.

So running ng build is the same as running ng run *:build, ng lint my-app is the same as running ng run my-app:lint, ng serve is the same as running ng run my-app:serve, you get it…

A few commands are not delegating to @angular-devkit/architect but to @angular-devkit/schematics. These commands are ng new my-app (which is the same as ng generate @schematics/angular:application my-app), ng update and ng add. But I’ll come back to these two lasts in a dedicated section.

This new architecture comes at a price though: a bunch of configuration files have changed. Some code has been moved around, a new dev dependency has been added (@angular-devkit/build-angular), but most importantly, .angular-cli.json is now deprecated and replaced by angular.json.

This new configuration file looks like:

{
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "ponyracer": {
      "root": "",
      "projectType": "application",
      "cli": {
        "packageManager": "yarn"
      },
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist",
            "index": "src/index.html",
            "main": "src/main.ts",
            // ...

It’s far bigger than this sample of course, but you can find what I was explaining about the new architecture. The new applications or libraries will be generated in the projects directory, My configuration is for one project, called ponyracer and it’s an application. The CLI can be customized to use another package manager like Yarn. And then you have a long section for architect, the command runner. Each available command is a key, for which a builder is needed. For example, build runs @angular-devkit/build-angular:browser, with a bunch of options you can override if you want to.

Migrating to this new configuration is a bit cumbersome, but not that hard. You can do it by hand, using angular-cli-diff to help you, or you can try the brand new ng update feature of the CLI.

ng update and ng add

The ng update command has been introduced in 1.7 but was a glorified npm install. With this release, it starts to express its potential!

It’s now a command that can install packages and run migration scripts automatically. The command will look into the package.json file of the package you’re specifying for a key called ng-update. If it finds one, it will try to run the migration scripts found. You have to specify from which version you update (and to which one if you want to).

The CLI itself offers a migration script to go from 1.x to 6.0. You can run the migration script alone with ng update @angular/cli --migrate-only --from=1.7.4, and it ill automatically add the missing dependencies, move the code around to match the new layout, and migrate the old configuration file to the new angular.json one. It works well enough in that case, even if it was not perfect when we tried it. So give it a try, but don’t trust it blindly and check manually if everything looks good.

RxJS also offers scripts to update your app to RxJS v6, with ng update rxjs --migrate-only --from=5.5.9 for example.

Note that the same is possible with ng add: when adding a package with ng add, the CLI will look for the ng-add key in the package.json file of the package you are installing and will run it. For example, if you add Angular Element to your project with ng add @angular/elements, a script will add the required polyfill to your application. Another example is Angular Material: just run ng add @angular/material and it will set up your application, by adding the CSS imports, the default theme, the necessary module import, etc. Material goes even further and provides a few schematics that you can use. For example, if your run ng generate @angular/material:material-nav --name=nav, it will generate a component NavComponent with the boilerplate necessary in its template to display a navbar.

On the paper, it looks great and kind of what Facebook does for React with the codemod project. In practice, it will greatly depend on whether the eco-system adopts it or not. But this could be quite cool if the feature becomes reliable. We can imagine migrating Angular or the CLI from one version to the next by relying solely on the tooling and one command line!

New schematics

Now that the CLI is broken down into several pieces, we have one package/schematic per functionnality. Let’s have an overview on which packages are currently available:

  • @angular-devkit/build-angular: this is the one to build an Angular application, now a required dependency in your CLI projects.
  • @angular-devkit/build-ng-packagr: this is the schematic for generating and building a library, based on ng-packagr.
  • @angular/pwa: the schematic to transform your app into a Progressive Web App. See our blog post about it for more details about PWA and Service Workers support. Just run ng add @angular/pwa and you’ll have transformed your application into a progressive one!
  • @angular-devkit/build-optimizer: the plugin that makes crazy optimizations to your application, to ship as few code as possible to your users.

Breaking changes

The CLI 6.0 supports only Angular 5.x and 6.x of course (check out our blog post about Angular 6.0), but not Angular 2.x et 4.x anymore.

The minimum NodeJS version has also changed to 8.9+ (and NPM to 5.5+).

The configuration files and the project layout have changed quite a bit, as we pointed out above, so you’ll have to move things around and migrate your configuration files (with ng update and/or manually by checking angular-cli-diff)

Note that the environment concept has slightly changed and is now called a configuration. You can’t run ng build --env=prod anymore as the option has been removed, and building with ng build --prod is now the same as running ng build --configuration=prod. A configuration can contain build options and file replacements. A build option is typically --aot for example. A file replacement is what is done natively with the environment.ts file, which is replaced at build time by environment.prod.ts as it was previously. The cool thing is that you can create several configurations to avoid memorizing a long command. For example, when you want to build the application in a specific locale, you have to type something like: ng build --aot --output-path=dist/fr --i18n-locale=fr --i18n-format=xlf --i18n-file=src/locale/messages.fr.xlf (which nobody can remember). With this new configuration system, you can add your configuration to your angular.json file:

"build": {
  "builder": "@angular-devkit/build-angular:browser",
  "configurations": {
    "fr": {
      "aot": true,
      "outputPath": "dist/fr",
      "i18nFile": "src/locale/messages.fr.xlf",
      "i18nFormat": "xlf",
      "i18nLocale": "fr"
    }

A configuration can also contain as many file replacements as you want. For example the production configuration replaces environment.ts by environment.prod.ts.

"configurations": {
  "production": {
    "fileReplacements": [
      {
        "replace": "src/environments/environment.ts",
        "with": "src/environments/environment.prod.ts"
      }
    ],

A configuration is specific to a command. In my example above, I added the fr configuration to the build command, allowing to run ng build --configuration=fr. But you can reuse a configuration for another command by referencing it:

"serve": {
  "builder": "@angular-devkit/build-angular:dev-server",
  "configurations": {
    "fr": {
      "browserTarget": "ponyracer:build:fr"
    }
  }

Another thing that can impact you: the generated files don’t have .bundle or .chunk in their names anymore. main.bundle.js is now main.js, but worst admin.module.chunk.js is now admin-admin-module-ngfactory.js, reflecting that my AdminModule is in an admin directory in my project. That’s to allow people to have two modules with the same name in different locations, at the price of a fucking long name for those who have just one… And inline.bundle.js has been renamed runtime.js. If you have scripts relying on these names, don’t forget to update them.

Also, a few commands have lost or renamed some options and gain others… Don’t be surprised if your usual command does not work right away… For example --single-run have been removed from ng test, and you should now use ng test --watch=false. The kind of stuff that will break a continuous integration (and the developer nerves) when upgrading…

ng get/set has been removed and replaced with ng config, for example you now have to use ng config cli.packageManager yarn.

And to finish, ng eject is currently not supported (but will come back soon).

Now that the unpleasant stuff is out of the way, let’s see what other stuff this new release brings.

Webpack 4

You probably know that under the hood the CLI uses Webpack to do the heavy lifting. Webpack has released the 4.0 version: you can read more about it on the offical blog.

TL;DR: Webpack 4 is faster, should be smarter for bundling common parts of the application, has a new option (sideEffects) that will help to have a better tree-shaking, and adds WebAssembly support.

The Angular CLI team has done an awesome job and integrated Webpack 4 right away in the CLI, and it brings some nice improvements on build times and bundle sizes.

Dynamic lazy-loading

Angular provides a nice way to have lazy-loading in your application via the router. This is usually enough, but sometimes you might find yourself in a situation where you would like to lazy-load a module programmatically, on demand.

Something like:

constructor(loader: SystemJsNgModuleLoader) {
  loader.load('app/admin/admin.module#AdminModule')
    .then(factory => ...);
}

The problem was that the CLI was only able to bundle modules separately if they are found in a loadChildren route configuration. So you had to “trick” the CLI and Webpack to build a separate chunk.

With Angular CLI 6.0, that’s no longer necessary. A new option, called lazyModules, can be added to your angular.json, to inform the CLI that you have other NgModules that need to be lazy-loaded, and Webpack will build the necessary chunks:

"lazyModules": [ "app/admin/admin.module" ]

Better error stacks

This is not really a CLI feature as it is a rather old Zone.js feature, but the environment.ts file has been enriched with an import you can uncomment:

import 'zone.js/dist/zone-error';

It transforms the usual stack traces containing all the Zone.js frames into a cleaner and less verbose one containing just the necessary frames.

This is only included in the development environment, because it can have performance impact on your production code.

Installation time

As the CLI is now split in several sub-packages, the installation time should be greatly reduced. So you should not have time to grab a coffee anymore when running npm install --global @angular/cli ;).

To sum up, this release is a huge one for the CLI. It does imply a bit of work from you to migrate, but it’s worth it for the modularity it brings. You might want to let things dry a little though, and wait for a few weeks to upgrade your main projects…

It took us quite some time to update our ebook and online training with these novelties, but we are up-to-date!

Check out our ebook, online training (Pro Pack) and training if you want to learn more!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


Angular CLI 1.7.0 is out with some nice new features!

If you want to upgrade to 1.7.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 (1.2.1 for example), and the target version (1.7.0 for example), and it gives you a diff of all files created by the CLI: angular-cli-diff/compare/1.2.1…1.7.0. You have no excuse for staying behind anymore!

Let’s see what new features we have!

App budgets

One of the major new features is the ability to set budgets for your applications. In .angular-cli.json, you can now add a new section looking like:

"apps": [
  {
    "budgets": [
      { "type": "bundle", "name": "main", "baseline": "300kb", "warning": "30kb" },
      { "type": "bundle", "name": "races", "maximumWarning": "360kb" },
      { "type": "allScript", "baseline": "1.4mb", "maximumError": "100kb" },
      { "type": "initial", "baseline": "1.6mb", "error": "100kb" },
      { "type": "any", "maximumError": "500kb" }
     ],

As you can see, there are several types of budget:

  • bundle, a specific bundle that you name;
  • allScript, all your application scripts;
  • all, all the application;
  • initial, the initial size of the application;
  • anyScript, any one of the script;
  • any, any one of the files.

The sizes are compared to the baseline you specify. If you don’t specify a baseline, then the baseline used is 0.

There are several types of error:

  • maximumWarning: warns you if size > baseline + maximumWarning;
  • minimumWarning: warns you if size < baseline - minimumWarning;
  • warning: same as defining the same maximumWarning and minimumWarning;
  • maximumError: errors if size > baseline + maximumError;
  • minimumError: errors if size < baseline - minimumError;
  • error: same as defining the same maximumError and minimumError.

This is a pretty cool feature, as it allows to keep the size in check without additional tooling (like bundlesize)! And these may be the only budgets your app won’t go over ;)

ng update

Good news, we have now a command to automatically update the Angular dependencies of our CLI applications.

If you use the new CLI 1.7, just run:

ng update

And all your @angular/* dependencies will be updated to the latest stable! This includes all the core packages in your dependencies and devDependencies, but also the CLI itself, and other Angular packages like Material, or DevKit. It does so recursively, so dependencies like rxjs, typescript or zone.js are automatically updated too!

The command does not have a lot of options (only a dry-run option and a next option to update not to the latest stable, but to the next version), so it’s currently an all or nothing process.

But it relies on a schematic (introduced in CLI 1.4, see our blog post), called package-update, that you can use directly. In broad lines, a schematic is a package that contains tasks allowing developers to create code (a full project, a component, a service…) and/or to update code (like updating configuration or classes, adding a dependency, etc…). All the “classic” tasks and blueprints of Angular CLI are in the @schematics/angular package, but the CLI team is gradually rolling in a few new ones to add features, like @schematics/package-update.

This new schematic offers 4 tasks:

  • @angular to update the Angular packages
  • @angular/cli to update the CLI
  • @angular-devkit to update the DevKit
  • all to update all at once

The ng update command calls the all task of the schematic, but you can use the schematic directly if you need or want to.

I’ve never really explained how to do so, so let’s take an example: you only want to update the Angular packages but not the CLI version.

First, install the schematic:

yarn add --dev @schematics/package-update

Add a schematics script in your package.json:

"scripts": {
  "ng": "ng",
  "schematics": "schematics"
  // ...
},

and run:

yarn schematics @schematics/package-update:@angular

And you’ll only have your Angular packages (and their own dependencies) updated.

You can also specify a version to the schematic:

yarn schematics @schematics/package-update:@angular --version 5.2.3

Configuration simplifications

I usually don’t mention that a few files have changed in the project template, but for once it comes with a few simplifications and new options, so you should definitively take a careful look at all the changes, especially in the:

  • test.ts file (new zone.js import, simplified logic)
  • polyfills.ts file (shows how to use some zone.js capabilities)
  • tslint.json file (rules added and removed)
  • package.json file (lots of dependency bumps)

You can easily see these changes with our angular-cli-diff repository, for example between an old version and the last one: angular-cli-diff/compare/1.2.1…1.7.0

E2e test suites

The e2e task can now take a --suite option, to run only part of your e2e tests. You can define suites of tests in your protractor.conf.js configuration file:

exports.config = {
  suites: {
    perf: 'e2e/perf/**/*.e2e-spec.ts',
    regression: [
      'e2e/regression/**/*.e2e-spec.ts',
      'e2e/bugs/**/*.e2e-spec.ts'
    ]
  },

And then run:

yarn e2e --suite perf,regression

Service worker safety

Service workers are a really nice feature of modern browsers, and Angular offers a package to help you use them, introduced in Angular 5 (see our blog post). Angular CLI also has a very good support for them, as we explained in our blog post.

But they can also be tricky, as everything involving caching in our industry… If you need to deactivate an already installed service worker, @angular/service-worker will include a safety-worker.js script starting with Angular 6, and the CLI 1.7 adds support to automatically include it in the production bundle. You must then serve the content of this script at the URL of the service worker you want to unregister.

Angular 6 support

As Angular 6 stable is right around the corner (end of March if everything goes well), the CLI is now compatible with it, meaning you can give a try to version 6 right now!

Angular Compiler options

The Angular Compiler options are now supported!

That means if you try to use for example the fullTemplateTypeCheck option introduced in Angular 5.0 (see our blog post), you can now just update the tsconfig.json file of your CLI project, and when you will run ng serve --aot or ng build --prod the option will be picked up!

TypeScript 2.5 and 2.6 support

As Angular 5.1 supports TypeScript 2.5 (see our blog post) and Angular 5.2 now supports TypeScript 2.6 (see our other blog post) , the CLI will no longer complain if you use these TS versions.

Webpack 4 support

As you may know, the CLI uses Webpack under the hood. Webpack is currently in version 3 but the version 4 should not be far away, bringing in some performance enhancements and some nice features (like the side-effect feature which should reduce our bundle sizes, better defaults, WebAssembly support, etc…).

The CLI is getting ready to switch to Webpack 4, and we should enjoy some of these nice features (reduce bundle sizes, faster builds) soon!

Better, faster, higher

The tasks have been slightly improved with the introduction of caching, so your build should be faster!

Check out our ebook, online training (Pro Pack) and training if you want to learn more!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


Angular 5.2.0 is here!

Angular logo

Let’s see what 5.2 has in stock for us!

Templates

Angular 5.0 introduced the fullTemplateTypeCheck option in the compiler. When activated, the Angular compiler will be stricter when checking your templates and catch potential type errors (check our Angular 5.0 blog post to learn more). The feature is really powerful but sometimes you can run into expressions in your templates that you know will work at runtime, even if the compiler can’t type-check them.

Angular 5.2 introduces a new function you can use in your templates, called $any(). $any() can be used in binding expressions to disable type checking of this expression. This is really similar to as any in TypeScript, and allows expressions that work at runtime but do not type-check.

interface PonyModel {
  name: string;
}

@Component({
  template: '<p>Hello {{ $any(ponyModel).age }}'
})
export class PonyComponent {
  ponyModel: PonyModel;
  // ponyModel has no field age, so the template should not compile
}

As for any in TypeScript, I’m not really a fan of using this: I usually prefer to have a correct type instead of “cheating” with any or $any(). So this is not really for the day to day use.

This is rather intended to help the applications using fullTemplateTypeCheck which can raise type errors hard to fix, usually from third party libraries. For example, we use ng-bootstrap and there were two errors in 1.0.0-beta.7. We fixed them, so if you use ng-bootstrap@1.0.0-beta.8 or a more recent one, you should be OK!

This was also introduced for internal use in the framework (see below).

Compiler

Still regarding this feature, some work has been done to have more accurate errors in your template if you use the strictNullChecks option form the TypeScript compiler (see our blog post about Angular 4.1 to learn more about this) with fullTemplateTypeCheck.

For example, the compiler was not really good at determining a situation like this one:

@Component({
  template: `<div *ngIf="ponyModel">{{ ponyModel.name }}</div>`
})
export class PonyComponent {
  // ponyModel can be a pony or null
  @Input() ponyModel: PonyModel | null;
}

Here, using strictNullChecks and fullTemplateTypeCheck, the compiled template would raise an error, as the TypeScript code generated could not see that, because of the *ngIf wrapping it, the evaluation of ponyModel.name was safe. The expression is only evaluated if ponyModel is not null, so there is no risk, but the compiler could not see it and was considering ponyModel to be PonyModel | null:

src/app/pony/pony.component.html(1,25): : Object is possibly 'null'.

Some work has been done by the Angular team to fix this: now the TypeScript code generated will take into account the *ngIf guard, and automatically consider ponyModel as a not null entity inside the *ngIf! So where we used to “cheat” and write:

{{ ponyModel!.name }}`

We can now simply write:

{{ ponyModel.name }}

and the compiler will understand the situation!

Note that this a generic feature: if you write your own structural directive, that works like an *ngIf, you can also leverage this type guard feature by adding a static field called ngIfUseIfTypeGuard to your directive.

Router parameters inheritance

Previously, the router would merge path and matrix params, as well as data/resolve, with special rules (only merging down when the route was an empty path, or was component-less).

Angular 5.2 adds an option called paramsInheritanceStrategy which can take different values:

  • when set to always, it makes child routes unconditionally inherit params from parent routes;
  • when set to emptyOnly, the default, it only inherits parent params for path-less or component-less routes (the former behavior).

Project Ivy: a faster and smaller renderer

This release doesn’t have many features because part of the team is currently rewriting one piece of the framework: the renderer.

We don’t know much about this project (codename Ivy) as the design doc is not public right now, except that it should make the renderer smaller and faster, with a simpler design, allowing a better incremental compilation (faster builds for us \o/), and will be fully backwards compatible (hopefully no breaking changes \o/). We’ll keep you up to date when this feature is ready (it’s still in early stages).

That’s all this release!

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


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


Angular CLI 1.6.0 is out with some nice new features!

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

Let’s see what new features we have!

Service Worker

A new flag has been added to the ng new command and allows to generate an application with service workers already enabled and configured. Service workers are a great new API in the browser, acting like a “client-side proxy”: when your application requests an asset, it will first “ask” the service worker if it is available, before really hitting the network if it isn’t. It can really speed up the second and following visits to your application, and can even be a step to working offline, and towards what’s called a Progressive Web Application (PWA).

This new flag uses the brand new @angular/service-worker package released in v5.0.0. Older versions of the CLI only work with the older version of this package: if you want to use the brand new one, you’ll have to update to the CLI v1.6.

The flag will add a file named ngsw-config.json which is the configuration file for the Angular Service Worker package.

The file looks like this:

{
  "index": "/index.html",
  "assetGroups": [{
    "name": "app",
    "installMode": "prefetch",
    "resources": {
      "files": [
        "/favicon.ico",
        "/index.html"
      ],
      "versionedFiles": [
        "/*.bundle.css",
        "/*.bundle.js",
        "/*.chunk.js"
      ]
    }
  }, {
    "name": "assets",
    "installMode": "lazy",
    "updateMode": "prefetch",
    "resources": {
      "files": [
        "/assets/**"
      ]
    }
  }]
}

This means that the main file is index.html, that you want to prefetch some resources, some of which have a fixed name, while some others are versioned. Some other resources are less critical assets and are loaded lazily (only when needed).

The flag will also add an import to your main module:

imports: [
  BrowserModule,
  ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
],

This will activate the ServiceWorkerModule if you are in “prod” mode, and register the service worker generated by the CLI based on the previous config. As the worker is only enabled in “prod” mode, you won’t see a difference using ng serve. It’s only when building your application with ng build --prod that you’ll see a few new files in your dist directory.

As this module is in @angular/service-worker, it will also add this package to your dependencies. And it will turn on the serviceWorker option in your .angular-cli.json.

This is pretty straightforward and gives a great basis. Even if you have an existing application, you can follow these steps and end up with the same result!

You can go much further, and add configuration for your API calls by selecting the strategy you want: always call the server (freshness), or always from cache (performance), etc.

"dataGroups": [
  {
    "name": "races-api",
    "urls": ["/api/races"],
    "cacheConfig": {
      "strategy": "performance",
      "maxSize": 10,
      "maxAge": "30m",
      "timeout": "5s"
    }
  }
]

Here I cache the calls to /api/races for 30 minutes, meaning all requests to this endpoint in the next half hour will return the same result as the first one, even if offline.

You can also add external resources like fonts to the configuration to also cache them.

To give it a try, build your app with ng build --prod, then serve your dist directory with a static HTTP server, like http-server. Open your application with Chrome, and go the Developer Tools in the Application tab. You should see the service worker registered in the Service Worker section! And you can see which parts are cached in the Cache Storage section.

Note that the service worker really caches your application, meaning that a new version deployed in production will not be seen immediately by your users. If you deploy a new version, the application will fetch the new NGSW file on reload, but will use the old one, until your user refreshes the page another time. That’s why you see on some websites a small popup “A new version is available, do you want to refresh?”. If you want to implement such a process, Angular can help you with its service SwUpdate:

export class AppComponent implements AfterViewInit {

  @ViewChild('modal')
  private modalContent: ElementRef;

  constructor(private swUpdate: SwUpdate, private modalService: NgbModal) {
  }

  ngAfterViewInit() {
    if (this.swUpdate.isEnabled) {
      this.swUpdate.available.subscribe(event =>
        // update available: ask the user to reload
        this.modalService.open(this.modalContent).result.then(
          () => this.swUpdate.activateUpdate()
            .then(() => document.location.reload()), // load the update
          () => {} // do nothing if the user wants to refresh later
        )
      );
    }
  }
}

Here I’m subscribing to the available observable exposed by SwUpdate. As soon as a new version of the application is available, the observable will emit an event. In the example above, I chose to open a modal with ng-bootstrap to ask the user to reload the application. If he/she chooses to do so, we load the new version with activateUpdate() and reload the page. If not, we do nothing. You can of course display what you want (just an alert, a toast…).

Universal

One of the main features of this release is the ability to add server side rendering capacity to your application with a simple command. Server-side rendering (called “universal” in Angular) is possible since quite some time, but the CLI had no automated way to do it.

This is now fixed: you just have to run ng generate universal server-app and Angular CLI automatically sets things up for you:

  • creates a new module app.server.module.ts, which uses ServerModule instead of BrowserModule;
  • creates a main file main.server.ts;
  • creates a TypeScript config tsconfig.server.ts
  • adds a dependency to your package.json @angular/platform-server;
  • updates .angular-cli.json to add a new “app”, called “server-app” in my example, in your project;
  • updates your main module to use the brand new (Angular 5) BrowserModule.withServerTransition() which ensures the client app has a smooth transition when it boots;
  • wraps the bootstrap call in a DOMContentLoaded event handler.

You can customize pretty much everything:

  • the application name, by default the one you gave in the command line
  • the clientApp name, by default 0, as you usually have only one app in your CLI project
  • the appId, used by withServerTransition(), by default serverApp
  • and the name of every files mentioned above!

Note that you’ll have to add the deprecated @angular/http package even if you don’t use it, because @angular/platform-server still depends on it.

Now you should be able to build the application!

ng build --prod --app=server-app

And you’ll get the bundles in dist-server/. Than it’s up to you to set up a server to use these, probably a NodeJS server, using something like Express and its ngExpressEngine (that’s the official example in the documentation). The job of the server will be to answer a request with an HTML generated using the JS bundles from dist-server.

Or you can continue reading, and discover another new feature of the CLI ;). You won’t be able to use ng serve with this app though (not yet, but I think it’s coming!).

Application Shell

The other new feature is the Application Shell. A new schematic has been added allowing to generate a “shell” - an index.html containing a static rendering of your application. This uses the universal part I mentioned above for the server-side rendering.

ng g app-shell appShell --universal-app=server-app

The command here uses the serverApp I created above. If you did not create it, the CLI will generate it for you ;)

The command will:

  • update .angular-cli.json to add the appShell key with its configuration "appShell": { "app": "server-app", "route": "shell" };
  • add an AppShellComponent to your application;
  • update the app.server.module.ts to add a route with the path specified pointing to the AppShellComponent.

Now when you’ll build the application with ng build --prod the dist and dist-server directories will be generated, and the index.html file in dist will contain the prerendered AppShellComponent. This means you’ll have a meaningful content served right away when deploying to production (as you can of course put whatever you want in the shell component). When the application is done starting, it will be displayed as usual.

The three features can be combined nicely: you can add a universal/server-side rendering capability to your application, add an application shell to have a fast first render using this capability, and use service worker for the following renderings!

These features are still very new (application shell was still quite buggy when I tested it…), but look promising for the applications that need to start faster.

Check out our ebook, online training (Pro Pack) and training if you want to learn more!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


À l’heure des étrennes de fin d’année, c’est le moment idéal pour faire un point sur notre argent (i.e. l’argent que vous nous avez donné), et sur la meilleure façon de le dilapider en toute sérénité morale.

Donations sur les ventes d’ebook

Dès notre premier ebook sur AngularJS, nous avions souhaité un mode de vente plus participatif : non seulement l’ebook serait sans DRM, mais nous le vendrions en direct sans éditeur, à prix libre*, et avec un don optionnel à une association caritative. L’association alors choisie fut Docteur Souris, qui offrait aux patients hospitalisés un accès Internet, et notamment aux enfants pour poursuivre leur scolarité et rester en contact avec leurs amis.

Docteur Souris propose un accès Internet aux enfants hospitalisés

Si nous en parlons au passé, c’est que Docteur Souris a dû malheureusement fermer ses portes en 2017. Après avoir déjà effectué un premier don de plus de 2000€, il restait encore plus de 1400€ à reverser, puisque vous aviez choisi de donner 24% en moyenne à l’association, comme vous pouvez le constater sur nos chiffres de ventes publics.

Nous avons donc dû choisir une association alternative. Pour ne pas trahir la finalité de vos dons, nous nous sommes arrêtés sur Le Rire Médecin, qui a pour mission d’aider les enfants hospitalisés et leurs parents à dépasser leur angoisse et leur solitude.

Et voici que nous venons de leur reverser 1400€ ! 👏

Si ce don ouvre droit à des déductions fiscales, nous ne l’exercerons pas. Nous ne donnons pas l’argent de Ninja Squad, mais celui reçu des acheteurs : on ne veut pas voler l’état de revenus qui n’ont aucune raison de nous revenir.

Pour un Internet libre

Avec le deuxième ebook sur Angular (Angular 2, Angular 4, Angular 5…), nos ambitions s’envolaient : nous visions l’international, avec un ebook écrit en anglais (et aussi traduit en français). Il nous fallait alors une association au périmètre plus large, connue dans le monde entier, dans laquelle non seulement nos fans autochtones pourraient se reconnaître, mais aussi nos nouveaux amis transatlantiques, et potentiellement tous ceux de la centaine de pays qui l’ont finalement acheté 👋💋. Nous avons alors choisi l’Electronic Frontier Foundation, qui défend un internet libre (et avec la volonté actuelle du congrès américain de vouloir tuer la neutralité du net, cela nous semble toujours terriblement important et actuel 😓).

Nous n’avions jusqu’alors pas encore reversé vos dons. C’est désormais chose faite : 4500€ ($5.140) viennent d’être donnés à l’EFF. C’est formidable, merci à vous ! ✌️

Donation de Ninja Squad d'un montant de 4500€ ($5.140) à l'Electronic Frontier Foundation

Développement solidaire bénévole

Une autre forme de contribution associative : le développement bénévole d’application pour ceux qui en ont besoin sans les moyens associés.

Notre siège social est dans la Loire, pas loin de Saint-Étienne. On y connait Globe42, un espace social et de santé participatif. Accueillant des migrants âgés, ils assuraient jusqu’alors la gestion de leurs membres sans l’aide de l’informatique, pour écarter toute faille de confidentialité qu’un non-spécialiste peut craindre, notamment vis-à-vis du cloud (qui n’est que l’ordinateur de quelqu’un d’autre).

Nous avons alors voulu les aider. En proposant bénévolement nos services de développeurs, non seulement nous nous offrions un side-project pour pratiquer les technologies du moment (Angular 5, Spring Boot 2, JUnit 5, …) sur une vraie application, tout en aidant une association qui le méritait, et dont on pouvait ainsi faciliter le travail.

Make the World a better place... through scalable fault-tolerant distributable databases with ACID transactions (Silicon Valley, the TV series)

Si cela vous intéresse, le code est sur Github.

Un engagement caritatif plus large

Chez Ninja Squad, on aime bien tout faire nous-même. Alors quand se pose chaque année la question de quoi faire de nos bénéfices, nous n’avions pas le courage d’engager des avocats spécialisés pour organiser notre évasion fiscale dans des paradis fiscaux, comme c’est normalement la tradition dans le business.

Nous avons alors décidé de nous doter d’un nouvel outil de dilapidation du capital de l’entreprise pour le bien de l’Humanité : chaque salarié se voit doté d’une enveloppe caritative annuelle.

Pour le moment, nous commençons modestement : Ninja Squad offrira 500€ par salarié à l’association de son choix.

Pourquoi une enveloppe d’entreprise, alors que chaque salarié pourrait donner à titre personnel, quitte à augmenter nos salaires d’autant ? Question légitime.
Quand l’entreprise verse un salaire, les charges patronales et salariales viennent le diviser par ~2. Et il semblerait que les déductions fiscales accordées aux entreprises sur les donations soient plus lâches que pour les particuliers (notamment envers les établissements publics d’enseignement, mais cela reste à confirmer formellement).

Prenons un exemple. On voudrait donner 1000€ à une association :

  • Ninja Squad donne 1000€.
  • Avec les déductions fiscales (60% dans la limite de 0,5% du chiffre d’affaire), cela lui coûte 400€.
  • Si ce montant de 400€ devait être versé en salaire pour être donné à titre personnel par le salarié, cela équivaudrait à ~200€ nets.

Ainsi, en donnant par l’entreprise, on a virtuellement multiplié le don par 5 ! Certes, c’est au détriment de l’impôt. C’est pourquoi, si comme nous on croit aux valeurs du service public, il convient de rester dans des montants raisonnables, marginaux par rapport aux salaires et bénéfices, ce qu’assure déjà partiellement le plafond de 0,5% du chiffre d’affaire.
Dans notre cas, pour un chiffre d’affaires de ~300 000€, la limite de déduction est donc à 1500€.

En donnant 500€ par salarié, on maximise ainsi la contribution aux associations, sans grever la contribution de Ninja Squad aux impôts nationaux.

Et plus globalement, nous trouvions tout simplement séduisante cette idée d’enveloppe caritative, non sans une certaine fierté d’avoir créé une entreprise commerciale qui contribue au tissu associatif. 💪✊

A bientôt pour de nouvelles aventures fiduciaires 🤓, et n’hésitez pas à suggérer à votre patron de faire de même ! 😘


* Les purs libristes vous expliqueraient mieux que nous qu’imposer un prix minimal n’est pas un prix libre mais seulement un artifice marketing. 🤷‍


Cyril Lacôte


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


Angular 5.1.0 is here!

Angular logo

This is a fairly small release, with some bugfixes but not a lot of features.

Let’s see what 5.1 has in stock for us!

i18n

The registerLocaleData method now has an optional parameter to set the locale id. This allows to use a custom locale id or locales that Angular does not support. You can now do something like:

registerLocaleData(localeFr, 'fr-ZZ');

and the french locale data will be available for the (fake) locale id fr-ZZ.

Service worker

The @angular/service-worker package evolves a little, with the possibility to register the ServiceWorkerModule without crashing the application even if the Service Worker API is not supported by the browser. The register method has now also a new option to enable the service worker or not. Previously you would have registered your service worker like this:

providers: [
  environment.production ? ServiceWorkerModule.register('/ngsw-worker.js') : [],
  // ...
]

which would have made the Service Worker services like SwUpdate only available to dependency injection in production. That was forcing us to use a trick like Optional to not crash the application in development:

constructor(@Optional() private swUpdate: SwUpdate) {
  // test if swUpdate is not null
}

With 5.1, we can do better:

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

With this new enabled option, the services will always be available to dependency injection, making the Optional trick no longer necessary. The services like SwUpdate now also has an isEnabled field to know if they are enabled or not:

constructor(private swUpdate: SwUpdate) {
  if (swUpdate.isEnabled) {
    // ...
  }
}

Compiler

It’s worth noting that behind the scenes, some work has been done to enable AoT unit testing. Currently units test are run using the JiT compiler. But as you may know, the Angular team is working to make this JiT compiler obsolete. It’s been recommended for a long time to use the AoT mode in production, and, starting with Angular 5.0, it’s no longer necessary to use JiT even in development as AoT has become faster (even it’s still slower than JiT right now). The last place where JiT is required is for unit testing. That should no longer be the case soon, as some key pieces are falling into place in the framework.

Another interesting point for the compiler: the error messages should now be clearer (especially when you make a mistake in a decorator)!

Angular now also officially supports TypeScript 2.5.x.

That’s all for this small release!

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


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


Tons of Angular projects are using the Angular CLI. This tool is really great as it wraps all the Webpack complexity, and helps you build, test and serve your application. It can also generate components, services, pipes… with their associated tests.

A few maintainers are working full-time to evolve the CLI, fix bugs and introduce awesome new features. As a developer relying on the CLI, you’ll want to update the CLI version your project depends on as often as possible.

Sadly, there is no automated way to do it. You may think that bumping the package version in your package.json is enough, but… no…

There are also often configuration files to update, and even if the committers do their best to guide us through the updates, it can be hard to track exactly what you need to change between your current version and the new shiny one. And these new releases happen quite often as you can see!

Some time ago, the CLI had an init command that was trying to help you in the upgrade, but it was an “all or nothing” process: you just could overwrite the file or ignore it. The command has been removed in later versions, so you don’t have a lot of help right now.

That’s why we built a small script that generates a bare application with every CLI version. The result is angular-cli-diff, a repository that allows you to see exactly what changed between your version and another one!

For example, you are currently using 1.0.3 and want to test the release 1.5.2?

Here you go: https://github.com/cexbrayat/angular-cli-diff/compare/1.0.3…1.5.2

As you can see there are some differences that you might have missed (new dependencies, new polyfill, new unit test configuration, new types, new linter rules…).

You can, of course, compare any version you want. They are listed in the README of the repository and new versions are added a few hours/days after the official release.

This problem is not really original, and similar repositories exist for tools like React Native with rn-diff (from a good friend of mine Nicolas Cuillery) which was definitely an inspiration!

It has been quite useful to us these last weeks to update our code samples and online training exercises, we hope it will help you too.

Check out our ebook, online training (Pro Pack) and training if you want to learn more!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24/05 à Lyon
18-20/06 à Paris

Angular avancé

21-22/06 à Paris


Suivez-nous


Posts plus anciens