Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Angular 2 Migration - JHipster Meetup 6

2,493 views

Published on

How JHipster migrated from AngularJS 1.x to Angular 2 ?
William Marques and Flavien Cathala, JHipster Core Team Member show you how !

Published in: Internet
  • Login to see the comments

Angular 2 Migration - JHipster Meetup 6

  1. 1. JHipster 4.0 The Angular Migration by Flavien Cathala and William Marques
  2. 2. Who are we ? William Marques Flavien Cathala @wylmarq wmarques@ippon.fr JHipster Member Ippon Consultant @flaviencathala fcathala@ippon.fr JHipster Member Epitech Student
  3. 3. Summary 1. Introduction 2. Prepare your migration 3. Angular 2 ecosystem 4. Step-by-step migration 5. After the migration
  4. 4. Migration on JHipster JHipster Team VictorJulien Deepu William Flavien Sendil Kurman
  5. 5. Migration on JHipster Contributors Chris Thielen UI Router founder Sean Larkin Webpack member
  6. 6. Migration on JHipster Chronology Start of migration June Migration to Webpack November Entities Tests December End ? January Dependencies September
  7. 7. Angular 2 - New syntax - New concepts Officially released in September 2016 with:
  8. 8. AngularJS vs Angular 2 Javascript Typescript MVC Component Oriented Promise Observable AngularJS Angular 2
  9. 9. Why migrating ? - Better performances - More adapted to mobile terminals - Better productivity - AngularJS will be deprecated
  10. 10. PREPARE YOURSELF
  11. 11. Follow the John Papa style Major rules : Folder-By-Feature Scope Isolation (controllerAs “vm”) IIFE (avoid minification conflicts) https://github.com/johnpapa/angular-styleguide/tree/master/a1 (that’s him)
  12. 12. Be modular ! Create module files and declare your controllers and factories there Code is cleaner Easy module loader setup Source: https://github.com/tuchk4/requirejs-angular-loader
  13. 13. Do Components Only available in >= 1.5.x Easy switch to Angular 2 Component Promote best practices (scope isolation) One-way binding possible angular.module('heroApp').component('heroDetail', { templateUrl: 'heroDetail.html', controller: HeroDetailController, bindings: { hero: '=' } });
  14. 14. BONUS 1 : Do TypeScript Spoiler : You will write TypeScript with Angular 2 (widely recommended) Add classes, types, imports in your code Very easy migration to Angular 2 https://codepen.io/martinmcwhorter/post/angularjs-1-x-with-typescript-or-es6-best-practices
  15. 15. BONUS 2 : Yarn New package manager (another one) Much faster Easy to use (same command as NPM) Avoid “works on my machine” issue Offline Installation
  16. 16. Angular 2 ecosystem
  17. 17. Module loader Why ? - Code complexity - Performances - Avoid injection of huge number of files in index
  18. 18. Module loader Complexity ** ** Maintainability * *** Performances * *** SystemJS Webpack Which one ?
  19. 19. Module loader Why Webpack ?
  20. 20. Migration to Webpack +
  21. 21. Webpack webpack.common webpack.dev webpack.prod polyfills vendor
  22. 22. webpack.dev.js const webpackMerge = require('webpack-merge'); const commonConfig = require('./webpack.common.js'); const ENV = 'prod'; module.exports = webpackMerge(commonConfig({env: ENV}), { output: { filename: '[hash].[name].bundle.js', chunkFilename: '[hash].[id].chunk.js' }, plugins: [ new ExtractTextPlugin('[hash].styles.css') ] }); Webpack webpack.prod.js const webpackMerge = require('webpack-merge'); const commonConfig = require('./webpack.common.js'); const ENV = 'dev'; module.exports = webpackMerge(commonConfig({env: ENV}), { module: { rules: [{ test: /.ts$/, loaders: [ 'tslint' ] }] }, plugins: [ new BrowserSyncPlugin({ host: 'localhost', port: 9000, proxy: 'http://localhost:8080' }), new ExtractTextPlugin('styles.css'), new webpack.NoErrorsPlugin() ] });
  23. 23. polyfills.ts import 'bootstrap/dist/css/bootstrap.min.css'; import 'font-awesome/css/font-awesome.min.css'; Webpack vendor.ts import 'reflect-metadata/Reflect'; import 'zone.js/dist/zone'; module.exports = function (options) { const DATAS = { VERSION: JSON.stringify(require("../package.json").version), DEBUG_INFO_ENABLED: options.env === 'dev' }; return { entry: { 'polyfills': './src/main/webapp/app/polyfills', 'vendor': './src/main/webapp/app/vendor', 'main': './src/main/webapp/app/app.main' }, resolve: { extensions: ['.ts', '.js'], modules: ['node_modules'] }, output: { path: './target/www', filename: '[name].bundle.js', chunkFilename: '[id].chunk.js' }, webpack.common.js
  24. 24. Webpack How to run Webpack ? webpack --watch --config webpack/webpack.dev.js webpack -p --config webpack/webpack.prod.js Using NPM scripts package.json "scripts": { "webpack:dev": "webpack --watch --config webpack/webpack.dev.js", "webpack:prod": "webpack -p --config webpack/webpack.prod.js" } npm run webpack:dev npm run webpack:prod Command lines
  25. 25. Package managers
  26. 26. THE MIGRATION
  27. 27. Migration Plan : Bottom Up 1. Setup migration (install Angular 2 packages, the hybrid app) 2. Migrate small controllers, services, templates (leafs) and then their parents 3. Migrate routes 4. Check 3rd party dependencies (Angular UI, Angular Translate) 5. Remove AngularJS Code / Dependencies
  28. 28. upgradeAdapter Incremental Update (hybrid app) Upgrade your Angular 1 Services, Controllers… Downgrade your Angular 2 Services, Components… Bad performance (temporary solution) Why ?
  29. 29. Setup Remove ng-app and strict-di attribute in your template Create an app.main.ts : upgradeAdapter.bootstrap(document.body, ['myApp.app'], {strictDi: true});
  30. 30. Setup import * as angular from 'angular'; import { UpgradeAdapter } from '@angular/upgrade'; import { forwardRef } from '@angular/core'; import { Ng2BasicAppModule } from './app.ng2module'; export var upgradeAdapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2BasicAppModule)); Create an upgrade_adapter.ts file
  31. 31. Usage Downgrade an Angular 2 Component to use it in your Angular 1 App, add in your module file : For a service : .directive(‘home’, <angular.IDirectiveFactory> upgradeAdapter.downgradeNg2Component(HomeComponent)) .factory(‘example’, adapter.downgradeNg2Provider(Example));
  32. 32. Controller Migration - Remove the IIFE - Remove the $inject - Use the @Component annotation - Replace controller function by class
  33. 33. Controller Migration import { Component, OnInit, Inject } from '@angular/core'; import { StateService } from "ui-router-ng2"; import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { Account, LoginModalService, Principal } from "../shared"; @Component({ selector: 'home', templateUrl: './home.html' }) export class HomeComponent implements OnInit { account: Account; modalRef: NgbModalRef; constructor( private principal: Principal, private $state: StateService, private loginModalService: LoginModalService ) {} ngOnInit() { this.principal.identity().then((account) => { this.account = account; }); } isAuthenticated() { return this.principal.isAuthenticated(); } login() { this.modalRef = this.loginModalService.open(); } } (function() { 'use strict'; angular .module('ng2FinalApp') .controller('HomeController', HomeController); HomeController.$inject = ['$scope', 'Principal', 'LoginService', '$state']; function HomeController ($scope, Principal, LoginService, $state) { var vm = this; vm.account = null; vm.isAuthenticated = null; vm.login = LoginService.open; vm.register = register; $scope.$on('authenticationSuccess', function() { getAccount(); }); getAccount(); function getAccount() { Principal.identity().then(function(account) { vm.account = account; vm.isAuthenticated = Principal.isAuthenticated; }); } function register () { $state.go('register'); } } })();
  34. 34. Same refactoring as controllers Add your service in the providers array of your Angular 2 Module in order to inject it in your Angular 2 Components Downgrade it using the upgradeAdapter in your Angular 1 Module : Service migration .factory('example', adapter.downgradeNg2Provider(Example));
  35. 35. Service Migration 1 2 (function() { 'use strict'; angular .module('ng2FinalApp') .factory('LogsService', LogsService); LogsService.$inject = ['$resource']; function LogsService ($resource) { var service = $resource('management/jhipster/logs', {}, { 'findAll': { method: 'GET', isArray: true}, 'changeLevel': { method: 'PUT'} }); return service; } })(); import { Injectable } from '@angular/core'; import { Http, Response } from '@angular/http'; import { Observable } from 'rxjs/Rx'; import { Log } from './log.model'; @Injectable() export class LogsService { constructor(private http: Http) { } changeLevel(log: Log): Observable<Response> { return this.http.put('management/jhipster/logs', log); } findAll(): Observable<Log[]> { return this.http.get('management/jhipster/logs').map((res: Response) => res.json()); } }
  36. 36. Angular 1 Dependency in Angular 2 ? Upgrade the Angular 1 provider in your module file, using the upgradeAdapter: Use the @Inject annotation in your Angular 2 controller/service constructor : Same for Angular 1 lib dependencies ($state, $rootScope… ) @Inject('heroes') heroes: HeroesService adapter.upgradeNg1Provider('heroes');
  37. 37. Routes Migration Angular 2 Router UI-Router NG2 Default solution for Angular Team Inspired by AngularJS UI Router Component Oriented Easy migration from UI Router NG 1 Visualizer feature Breaking changes from UI Router NG1 Not the official Solution Final Decision : UI-Router NG2, because of their contribution to JHipster NG2 Router or UI-Router ?
  38. 38. Route Migration: Setup Install ui-router-ng1-to-ng2 and ui-router-ng2 NPM packages Add uirouter.upgrade module dependency in your Angular 1 Module Add Ng1ToNg2Module in your Angular 2 Module let ng1module = angular.module("myApp", [uiRouter, 'ui.router.upgrade']); @NgModule({ imports: [ BrowserModule, Ng1ToNg2Module ] }) class SampleAppModule {}
  39. 39. Route Migration : UpgradeAdapter In your upgrade_adapter.ts file, add these lines : import { uiRouterNgUpgrade } from "ui-router-ng1-to-ng2"; uiRouterNgUpgrade.setUpgradeAdapter(upgradeAdapter);
  40. 40. Route migration : refactoring import { RegisterComponent } from './register.component'; import { JhiLanguageService } from '../../shared'; export const registerState = { name: 'register', parent: 'account', url: '/register', data: { authorities: [], pageTitle: 'register.title' }, views: { 'content@': { component: RegisterComponent } }, resolve: [{ token: 'translate', deps: [JhiLanguageService], resolveFn: (languageService) => languageService.setLocations(['register']) }] }; (function() { 'use strict'; angular .module('ng2FinalApp') .config(stateConfig); stateConfig.$inject = ['$stateProvider']; function stateConfig($stateProvider) { $stateProvider.state('register', { parent: 'account', url: '/register', data: { authorities: [], pageTitle: 'register.title' }, views: { 'content@': { templateUrl: 'app/account/register/register.html', controller: 'RegisterController', controllerAs: 'vm' } }, resolve: { translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { $translatePartialLoader.addPart('register'); return $translate.refresh(); }] } }); } })();
  41. 41. Route migration : Route Declaration let ACCOUNT_STATES = [ accountState, activateState, passwordState, finishResetState, requestResetState, registerState, sessionsState, settingsState ]; @NgModule({ imports: [ Ng2BasicSharedModule, UIRouterModule.forChild({ states: ACCOUNT_STATES }) ], declarations: [ ActivateComponent, RegisterComponent, PasswordComponent, PasswordResetInitComponent, PasswordResetFinishComponent, SessionsComponent, SettingsComponent ], providers: [ SessionsService, Register, Activate, Password, PasswordResetInit, PasswordResetFinish ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class Ng2BasicAccountModule {} Add your routes in a variable and then import them using UIRouterModule.forChild :
  42. 42. Templates migration ng-class [ngClass] ng-click (click) ng-if *ngIf ng-model [(ngModel)] ng-repeat *ngFor AngularJS Angular 2
  43. 43. Templates migration <div class="modal-header"> <button class="close" type="button" (click)="activeModal.dismiss('closed')">x </button> <h4 class="modal-title">Sign in</h4> </div> <div class="modal-body"> <div class="row"> <div class="col-md-4 col-md-offset-4"> <h1 jhi-translate="login.title">Sign in</h1> </div> <div class="col-md-8 col-md-offset-2"> <div class="alert-danger" *ngIf="authenticationError"> <strong>Failed to sign in!</strong> </div> </div> <div class="col-md-8 col-md-offset-2"> <form class="form" role="form" (ngSubmit)="login()"> <div class="form-group"> <label for="username">Login</label> <input type="text" class="form-control" name="username" id="username" [(ngModel)]="username"> </div> <div class="modal-header"> <button type="button" class="close" ng-click="vm.cancel()">&times;</button> <h4 class="modal-title">Sign in</h4> </div> <div class="modal-body"> <div class="row"> <div class="col-md-4 col-md-offset-4"> <h1 data-translate="login.title">Sign in</h1> </div> <div class="col-md-8 col-md-offset-2"> <div class="alert-danger" ng-show="vm.authenticationError"> <strong>Failed to sign in!</strong> </div> </div> <div class="col-md-8 col-md-offset-2"> <form class="form" role="form" ng-submit="vm.login($event)"> <div class="form-group"> <label for="username">Login</label> <input type="text" class="form-control" id="username" ng-model="vm.username"> </div>
  44. 44. Dependencies migration - angular-ui ng-bootstrap- angular-translate ng2-translate Some external dependencies needed to be replaced/updated: - ...
  45. 45. Remove AngularJS - Remove upgradeAdapter - Remove all AngularJS files Once everything has been migrated:
  46. 46. CONCLUSION
  47. 47. Migration Feedback A lot of new technologies and architectures Difficult process Some libs are poorly documented and in alpha Only a few projects already migrated Many different choices (Router, Module Loader) Don’t do it yourself : Use JHipster ;-)
  48. 48. About Angular 2... Modern approach (Component oriented) TypeScript Features (types, ES6) Cleaner code Less tools (only NPM)
  49. 49. What’s next ? Router discussions Hot Module Loader Ahead Of Time compilation Finish migration for all configurations
  50. 50. Demo
  51. 51. Questions ?

×