AngularJS à Angular
William Marques
William Marques
- Freelance
- JHipster Angular Stream Leader
- JavaScript Lover
@wylmarq
Nomenclature
- AngularJS: v1 en 2012
- Angular 2: Septembre 2016
Ces deux frameworks n'ont rien à voir !
AngularJS: Angular version 1.x
Angular: Angular version 2+
Pourquoi migrer ?
Depuis Juillet 2018, AngularJS est entré en période LTS.
Les seules mises à jours concerneront:
- Patch de sécurité
- Incompatibilité avec jQuery
- Bugs suite à des mises à jour navigateur
Après le 30 juin 2021, AngularJS ne sera plus maintenu !
D'autres raisons
- Meilleures performances
- Support TypeScript
- Web Components
- Angular CLI
- Programmation réactive avec RxJS
- Recrutement
Notre cas
Les contraintes
- Migration en best effort
- Migration incrémentale
- Livraison de features
Notre choix: NgUpgrade
- Permet de faire cohabiter AngularJS et Angular
- Système de downgrade/upgrade des composants, services
Taille du JS
Somme de la taille des fichiers JavaScript fournis lors du chargement de la page d'accueil
AngularJS: 4.3Mo
Angular: 1.4Mo
- Lazy Loading des locales
- Utilisation de l'Ahead Of Time Compilation
Avant de migrer...
Pré-requis
- Utiliser au maximum les composants AngularJS
- Utiliser webpack comme outil de build
- Limiter les dépendances à $rootScope
C'est parti !
Démarrage en mode hybride
import { UpgradeModule } from '@angular/upgrade/static';
import { AppModule } from './app.module';
@NgModule({
imports: [
BrowserModule,
UpgradeModule,
],
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, [AppModule]);
}
}
Fichier main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { Ng2AppModule } from './app.ng.module';
platformBrowserDynamic().bootstrapModule(Ng2AppModule);
Faire cohabiter AngularJS et Angular
Ce qui est possible
- Downgrader un composant Angular
- Upgrader un composant AngularJS
- Downgrader un service Angular
- Upgrader un service AngularJS
Ce qui n'est pas possible
- Upgrader un filtre AngularJS
- Downgrader un pipe Angular
- Upgrader/downgrader une directive
Downgrader un composant Angular
@Component({
selector: 'home',
templateUrl: 'home.html',
styleUrls: ['home.scss']
})
export class HomeComponent implements OnInit {
constructor() {}
ngOnInit() {}
}
@NgModule({
imports: [SharedModule],
declarations: [HomeComponent]
})
export class HomeNgModule {}
export const HomeNg1Module = angular.module('myApp.home', []).directive(
'home',
downgradeComponent({
component: HomeComponent
})
).name;
Upgrader un composant AngularJS
export const HomeComponent = {
template: `
<div class="container">
This is my home
</div>
`,
controller: class HomeController {}
};
export const HomeNg1Module = angular.module('myApp.home', []).component(
'home',
HomeComponent)
).name;
@Directive({
selector: 'home'
})
export class UpgradedHomeComponent extends UpgradeComponent {
@Input() text: string;
constructor(elementRef: ElementRef, injector: Injector) {
super('home', elementRef, injector);
}
}
@NgModule({
imports: [SharedModule],
declarations: [UpgradedHomeComponent]
})
export class HomeNgModule {}
Downgrader un service Angular
@Injectable({ providedIn: 'root' })
export class HeroService {
constructor(private http: HttpClient) {}
getHeroes() {
// Getting heroes
}
}
export const MyModule = angular
.module('myApp.hero', [])
.factory('heroService', downgradeInjectable(HeroService)).name;
Upgrader un service AngularJS (1)
export class HeroService {
constructor($http) {
'ngInject';
this.$http = $http;
}
getHeroes() {
// Getting heroes
}
}
export default angular
.module('myApp.hero', [])
.service('heroService', HeroService)
Upgrader un service AngularJS (2)
export function heroServiceFactory(i) {
return i.get('heroService');
}
@NgModule({
imports: [SharedModule],
declarations: [HeaderComponent],
providers: [{
provide: 'heroService',
useFactory: heroServiceFactory,
deps: ['$injector']
},]
})
export class HeroNgModule {}
@Component({
selector: 'header',
templateUrl: 'header.html',
styleUrls: ['header.scss']
})
export class HeaderComponent implements OnInit {
constructor(
@Inject('heroService') private heroService
) {}
ngOnInit() {}
}
Le routeur
Deux options
- Faire cohabiter les deux routeurs
- Tout migrer à la fin
Notre choix
Migrer tout à la fin:
- Configuration plus simple
- Pas d'exception à maintenir sur les deux routeurs
Pas si évident...
Principaux problèmes
- Régressions: compatibilité IE, effets de bords
- Equivalence de librairies
- Spaghetti code : trop de downgrade/upgrade
Recommandations
- Ecrivez des tests et / ou end-to-end
- Commencez par les pages les moins critiques
- Typez tout votre code
Merci !
AngularJS à Angular
By William Marques
AngularJS à Angular
- 574