Front-end

AngularJS vs Angular : comparaison complète

Angularjs Angular Comparaison Migration Architecture
AngularJS vs Angular : comparaison complète

AngularJS 1.x vs Angular 21 : architecture, performance, DI, routing, RxJS, Signals – comparaison technique pour choisir ou migrer.

Histoire et contexte

AngularJS (version 1.x) a été créé par Google en 2010 et a révolutionné le développement web en popularisant le two-way data binding et le MVC côté client. Pendant des années, il a dominé l'écosystème frontend.

En 2016, Google publie Angular 2 — une réécriture complète en TypeScript, incompatible avec AngularJS. La confusion des noms persiste encore aujourd'hui : "AngularJS" désigne la version 1.x, "Angular" (sans JS) désigne les versions 2 et supérieures (v21 en 2026).

AngularJS a atteint sa fin de vie officielle le 31 décembre 2021. Les applications AngularJS encore en production ne reçoivent plus de correctifs de sécurité.

En chiffres (2026) : Angular est utilisé par plus de 3 millions de développeurs. AngularJS compte encore des millions de lignes de code en production dans des systèmes legacy — c'est pourquoi comprendre les deux reste stratégique.

Architecture : MVC vs Composants

La différence architecturale la plus profonde est le paradigme de construction de l'UI : AngularJS suit le pattern MVC avec des controllers et des scopes, Angular adopte entièrement l'architecture par composants.

AngularJS : Model-View-Controller

// Controller AngularJS : logique dans un objet $scope
angular.module('app')
  .controller('ProductCtrl', function($scope, ProductService) {
    $scope.products = [];       // modèle
    $scope.filter = '';         // état UI

    // Charge les produits au démarrage
    ProductService.getAll().then(function(data) {
      $scope.products = data;
    });

    // Filtre les produits par nom
    $scope.filtered = function() {
      return $scope.products.filter(function(p) {
        return p.name.includes($scope.filter);
      });
    };
  });

Angular 21 : Architecture composants

// Composant Angular : logique encapsulée avec Signals
@Component({
  selector: 'app-products',
  standalone: true,
  imports: [FormsModule],
  template: `
    <input [(ngModel)]="filter" />
    @for (p of filtered(); track p.id) {
      <div>{{ p.name }}</div>
    }
  `,
})
export class ProductsComponent {
  private svc = inject(ProductService);
  products = signal<Product[]>([]);
  filter = signal('');

  // computed() recalcule uniquement quand products() ou filter() change
  filtered = computed(() =>
    this.products().filter(p => p.name.includes(this.filter()))
  );

  ngOnInit() {
    this.svc.getAll().subscribe(data => this.products.set(data));
  }
}
AspectAngularJSAngular 21
ParadigmeMVC + $scopeComposants + Signals
Unité de baseController + TemplateComposant autonome
État$scope (mutable)signal() (réactif)
LangageJavaScript ES5TypeScript strict
Modulesangular.module()NgModules / standalone

Change detection : $digest vs Signals

Le mécanisme de détection des changements est la différence de performance la plus significative entre les deux frameworks.

AngularJS : le cycle $digest (dirty checking)

// AngularJS parcourt TOUS les watchers à chaque cycle
// Un simple clic peut déclencher des centaines de vérifications

angular.module('app')
  .controller('PerfCtrl', function($scope) {
    // Chaque $watch enregistre une expression à surveiller
    $scope.$watch('user.name', function(newVal, oldVal) {
      // Déclenché quand user.name change
      console.log('Changement détecté:', newVal);
    });

    // $apply force un nouveau cycle $digest manuellement
    // (nécessaire quand on modifie le scope hors d'Angular)
    setTimeout(function() {
      $scope.$apply(function() {
        $scope.user.name = 'Alice'; // sans $apply, l'UI ne se met pas à jour
      });
    }, 1000);
  });

// Problème de performance : avec 2000 watchers,
// chaque interaction déclenche 2000 vérifications
// C'est le "2000 watchers problem" bien documenté

Angular 21 : Signals (réactif, précis)

// Angular Signals : seuls les composants dépendants de ce signal
// sont re-rendus — zéro dirty checking

@Component({ standalone: true, template: `{{ userName() }}` })
export class UserComponent {
  // signal() crée une valeur réactive
  userName = signal('Bob');

  // computed() dépend automatiquement de userName
  userLabel = computed(() => 'Utilisateur : ' + this.userName());

  // effect() réagit aux changements sans $watch manuel
  logEffect = effect(() => {
    console.log('Nom mis à jour :', this.userName());
    // Déclenché uniquement quand userName() change
  });

  updateName(name: string) {
    this.userName.set(name); // Angular sait exactement quoi re-rendre
  }
}
Gain de performance : Signals + mode zoneless éliminent entièrement zone.js (~14KB gzip) et rendent le re-rendu jusqu'à 10× plus précis qu'AngularJS sur des listes de données importantes.

Injection de dépendances

AngularJS : tokens sous forme de chaînes

// AngularJS : DI basé sur les noms de paramètres (fragile en minification)
angular.module('app')
  .controller('OrderCtrl', function($scope, OrderService, UserService) {
    // Les noms '$scope', 'OrderService', 'UserService' sont des tokens
    // PROBLÈME : la minification renomme les paramètres → DI cassée !
  });

// Solution : annotation explicite $inject
angular.module('app')
  .controller('OrderCtrl', ['$scope', 'OrderService', 'UserService',
    function($scope, OrderService, UserService) {
      // Maintenant la minification ne casse plus rien
    }
  ]);

Angular 21 : DI basée sur les types TypeScript

// Angular : DI via types — robuste, compile-time safe
@Component({ standalone: true })
export class OrderComponent {
  // inject() — pattern moderne (Angular 14+)
  private orderService = inject(OrderService);
  private userService = inject(UserService);

  // Ou via constructeur (pattern classique toujours valide)
  constructor(
    private http: HttpClient,
    private router: Router,
  ) {}
}

Templates et routing

Templates : directives vs syntaxe native

FonctionnalitéAngularJSAngular 21
Conditionng-if="expr"@if (expr) { }
Boucleng-repeat="x in list"@for (x of list; track x.id) { }
Switchng-switch@switch (val) { @case (x) { } }
Liaison valeurng-model="x"[(ngModel)]="x"
Événement clicng-click="fn()"(click)="fn()"
Interpolation{{ expr }}{{ expr }}
Classe conditionnelleng-class="{active: x}"[class.active]="x"
Chargement différé❌ (manuel)@defer { } @loading { }

Routing comparé

// AngularJS : ngRoute
angular.module('app', ['ngRoute'])
  .config(function($routeProvider) {
    $routeProvider
      .when('/users', { templateUrl: 'users.html', controller: 'UserCtrl' })
      .when('/users/:id', { templateUrl: 'user.html', controller: 'UserDetailCtrl' })
      .otherwise({ redirectTo: '/' });
  });
// Angular 21 : Router standalone avec lazy loading
export const routes: Routes = [
  { path: 'users', component: UserListComponent },
  { path: 'users/:id', component: UserDetailComponent },
  {
    path: 'admin',
    // Lazy loading : le module admin est chargé à la demande
    loadChildren: () => import('./admin/routes').then(m => m.adminRoutes),
    canActivate: [authGuard],
  },
  { path: '', redirectTo: 'users', pathMatch: 'full' },
];

Performance et bundle size

MétriqueAngularJS 1.xAngular 21 (standalone)
Bundle minimal (gzip)~55KB~45KB
Re-rendu 1000 lignes~80ms (dirty check)~8ms (Signals)
SSR / Hydration✅ (hydration incrémentale)
Tree-shaking❌ (tout ou rien)✅ (standalone complet)
Lazy loadingPartiel (ui-router)✅ natif (Router)
Web WorkersDifficile✅ (Angular CDK)
Lighthouse Score~60-70~95-100 (optimisé)

Écosystème et tooling

OutilAngularJSAngular 21
CLIGrunt/Gulp (manuel)Angular CLI (ng)
BundlerWebpack (manuel)esbuild + Vite (natif)
Tests unitairesKarma + JasmineVitest / Jest
Tests e2eProtractor (EOL)Playwright / Cypress
State management$scope, $rootScopeSignals, NgRx Signal Store
UI ComponentsUI Bootstrap (archivé)Angular Material 3 (MDC)
DevToolsBatarang (obsolète)Angular DevTools v2 (Chrome)
Mises à jour sécurité❌ (EOL 2021)✅ (active)

Quand choisir quoi ?

Utiliser AngularJS si…

  • Vous maintenez une application legacy qui ne peut pas être migrée immédiatement
  • Le budget ou le temps de migration n'est pas disponible dans l'immédiat
  • L'application est en fin de vie et sera remplacée par un nouveau projet

Utiliser Angular 21 si…

  • Vous démarrez un nouveau projet frontend en 2026
  • Vous avez besoin de SSR, d'hydration ou de performances Lighthouse élevées
  • Votre équipe utilise TypeScript et veut un framework opinionné et maintenu
  • Vous avez besoin de support à long terme et de mises à jour de sécurité
  • Vous construisez une application enterprise scalable
Verdict : Pour tout nouveau projet, Angular 21 est le seul choix raisonnable. Pour les projets existants AngularJS, planifiez la migration dès maintenant — chaque mois sans migration est un risque de sécurité et une dette technique croissante.

Questions fréquentes

AngularJS (1.x) est basé sur JavaScript avec un système de contrôleurs et de scopes, tandis qu'Angular (2+) est un framework TypeScript moderne avec une architecture basée sur les composants, les modules et les services injectables.

AngularJS a atteint sa fin de vie en décembre 2021. Il est fortement recommandé de migrer vers Angular pour bénéficier des mises à jour de sécurité, des performances améliorées et de l'écosystème actif. La migration peut se faire progressivement grâce à ngUpgrade.

Oui, Angular offre de bien meilleures performances grâce à la détection de changements optimisée, le rendu Ivy, le lazy loading des modules et la compilation AOT (Ahead-of-Time) qui réduit la taille des bundles et améliore le temps de démarrage.

Oui, grâce à la bibliothèque ngUpgrade fournie par Angular, il est possible de faire cohabiter AngularJS et Angular dans la même application. Cela permet une migration incrémentale, en migrant les composants un par un tout en maintenant l'application fonctionnelle.

Partager