📧 Reste informé(e) !

Reçois les derniers articles et conseils EasyAngularKit directement dans ta boîte mail.

S'inscrire gratuitement

~5 min de lecture

Angular v20 : style guide et migration depuis v19, le guide complet

Angular v20 ne s'est pas contentée d'évolutions techniques. Elle a aussi réécrit son style guide — plus court, plus pragmatique, opinionnated. Et la migration depuis la v19 réserve quelques pièges, surtout côté tests.

J'ai migré mon stack Angular/Nx/Vitest vers la v20, lu le nouveau style guide en entier, et appliqué les recommandations sur EasyAngularKit. Voici le retour brut : ce qui change vraiment, et ce qu'on aurait aimé savoir avant de lancer ng update.


TL;DR

  • Style guide : organisation par feature (fini components/, services/, directives/), inject() au lieu du constructeur, protected au lieu de public, readonly par défaut, plus de suffixe .component.ts. La règle d'or : cohérence avant règles.
  • Migration : prévoir un upgrade manuel de vite + vitest, configurer le zoneless dans test-setup.ts, lancer ng generate @angular/core:inject pour faire le ménage dans l'injection par constructeur, remplacer BrowserDynamicTestingModule par BrowserTestingModule.
  • Verdict : la v20 simplifie l'expérience dev sur la durée, mais la migration n'est pas un simple ng update. Compter 1-2 jours sur une codebase moyenne.

Partie 1 — Le nouveau style guide

Un guide plus court. Et plus clair.

Premier choc : il est incroyablement plus court que les versions précédentes. La toute première règle donne le ton :

"When in doubt, prefer consistency (within a file)."

Autrement dit : la cohérence > les règles. C'est pragmatique, moderne, et pertinent — exactement l'esprit qu'on défend sur EasyAngularKit.

Fini les répertoires components/, services/, directives/

Le guide recommande d'organiser les fichiers par feature, et non par type technique. Plutôt que :

src/app/
  components/
    user-card.ts
    user-list.ts
  services/
    user.service.ts
  models/
    user.model.ts

Le pattern préféré :

src/app/
  user/
    user-card.ts
    user-list.ts
    user.service.ts
    user.model.ts

Ce découpage rend l'architecture lisible du point de vue métier, pas seulement technique. C'est aussi exactement le pattern de co-location que recommande la skill architecture-review qu'on utilise en interne sur EAK.

1 concept = 1 fichier (en général)

Il est désormais recommandé d'avoir un seul concept par fichier : un composant, une directive, un pipe.

Mais (et c'est là que c'est malin) : si plusieurs éléments sont profondément liés — par exemple une directive interne à un composant, ou un pipe utilisé uniquement par lui — les regrouper dans le même fichier reste acceptable.

En cas de doute : on découpe.

Vive inject() au lieu du constructeur

L'usage de inject() est désormais recommandé à la place de l'injection via constructeur.

// ❌ Avant
@Injectable()
class UserService {
  constructor(private readonly http: HttpClient) {}
}

// ✅ Maintenant
@Injectable()
class UserService {
  private readonly http = inject(HttpClient);
}

Et pour faciliter la transition, Angular fournit le schematic :

ng generate @angular/core:inject

Un seul appel sur toute la codebase, ça fait le ménage en une fois.

protected > public

Angular recommande désormais de privilégier protected aux propriétés public. La règle implicite : ce qui est dans la classe d'un composant n'est consommé que par son template — donc protected suffit, et c'est plus honnête sur l'intention.

@Component({...})
export class UserCard {
  protected readonly user = input.required<User>();
  protected readonly isExpanded = signal(false);
}

readonly par défaut

Toutes les propriétés initialisées par Angular (input(), output(), viewChild(), etc.) doivent être marquées readonly.

À titre personnel, je pousse plus loin : readonly partout, sauf si on a une bonne raison de faire autrement. Le compilateur attrape les mutations qu'on aurait laissé passer dans une review.

Pas de logique dans les templates

Petit rappel salutaire :

Le template n'est pas le bon endroit pour la logique.

Pas de {{ veryComplexExpression() }} ou de @if (deepCheck(obj?.nested?.value?.something?.truthy)). Tout passe par une computed() (ou un signal dérivé) côté TypeScript.

Fini les suffixes .component.ts, .directive.ts

Oui, c'est terminé. Plus besoin de user-card.component.tsuser-card.ts suffit, à condition que le nom soit explicite.

Un fichier doit parler de lui-même. On devrait pouvoir deviner son contenu sans avoir besoin de l'ouvrir.

Quand j'ai lancé un sondage sur le sujet, j'ai été surpris de voir que la majorité y est opposée. Mais je continue de penser qu'il faut un peu d'effort initial pour gagner en lisibilité globale.


Partie 2 — Retex migration v19 → v20

Maintenant que le décor est posé, place aux pièges concrets rencontrés pendant la migration.

Des tests qui ne s'exécutent plus

Surprise après ng update : des tests bloqués à l'état queued, sans exécution réelle. Le problème venait d'un décalage entre les versions de vite et vitest poussées par Angular et celles attendues par Nx.

Solution : upgrade manuel dans package.json :

{
  "devDependencies": {
    "vite": "7.0.5",
    "vitest": "3.2.4"
  }
}

Puis pnpm install + relancer la suite. Pas glorieux, mais ça débloque.

Le passage au zoneless dans les tests

La v20 pousse l'approche zoneless par défaut. Encore faut-il le configurer aussi côté tests — sinon les whenStable() et detectChanges() ne se comportent pas comme attendu.

Setup dans test-setup.ts :

@NgModule({
  providers: [
    provideZonelessChangeDetection(),
    { provide: ComponentFixtureAutoDetect, useValue: true },
  ],
})
export class ZonelessTestModule {}

getTestBed().initTestEnvironment(
  [BrowserTestingModule, ZonelessTestModule],
  platformBrowserTesting(),
);

⚠️ Attention : provideExperimentalZonelessChangeDetection() a été renommé en provideZonelessChangeDetection() sans mise à jour automatique par le schematic. Si tu vois cette API dans tes tests, c'est à remplacer à la main.

Erreurs d'injection par constructeur

Angular v20 est plus stricte sur les formes d'injection implicites. Résultat : des erreurs parfois obscures au runtime, du style NG0203: inject() must be called from an injection context.

// ❌ Forme qui pose problème en v20 stricte
@Injectable()
class ExampleService {
  constructor(private readonly _httpClient: HttpClient) {}
}

// ✅ Forme à utiliser
@Injectable()
class ExampleService {
  private readonly _httpClient = inject(HttpClient);
}

Solution officielle : le schematic de migration :

ng generate @angular/core:inject

Doc officielle de la migration inject.

Modules de test obsolètes

Quelques dépréciations à corriger pour garder un projet propre :

Avant Maintenant
BrowserDynamicTestingModule BrowserTestingModule
platformBrowserDynamicTesting() platformBrowserTesting()

Pas de grosse conséquence, mais Angular signale ça en warning à chaque run de test. Autant nettoyer.


Récap : ce qu'il faut retenir

Problème Solution
Style : où mettre mes fichiers ? Par feature, plus par type
Style : injection inject() partout (ng generate @angular/core:inject)
Style : visibilité protected plutôt que public
Style : suffixes Noms explicites, plus de .component.ts
Tests bloqués Upgrade manuel de vite / vitest
provideExperimentalZonelessChangeDetection Remplacé par provideZonelessChangeDetection()
Erreurs d'injection au runtime ng generate @angular/core:inject
Warnings sur modules de test Migrer vers BrowserTestingModule

Verdict

Malgré les frictions, Angular v20 simplifie vraiment l'expérience dev :

  • Meilleur support de Signals
  • Performances accrues avec le zoneless par défaut
  • API plus stricte mais plus claire
  • Style guide enfin pragmatique

Si tu prends le temps d'adapter ta stack, tu y gagnes sur la durée. Compter une journée pour la migration technique + une demi-journée pour appliquer le style guide (organisation par feature, inject(), readonly).


Tu veux apprendre Angular avec ces conventions dès le départ ? 👉 EasyAngularKit couvre tout le cycle, de la structure de projet aux tests zoneless.

📧 Reste informé(e) !

Reçois les derniers articles et conseils EasyAngularKit directement dans ta boîte mail.

S'inscrire gratuitement

AngularKit

Suite d'outils pour développeurs Angular francophones. Apprends, modernise tes réflexes, audite ta codebase.

Produits

Contact

Légal

© 2026 AngularKit. Tous droits réservés.