What this talk is NOT about
This is not an Angular 2 introduction.
Before any migration you should already know at least the basics of the
‘new’ framework.
This talk is about things you might 'need' to consider in order to start the
migration journey.
Do NOT migrate to learn
You should not start this process just to 'try out‘ Angular 2.
Start a new pet project or a create a prototype (maybe something used
internally).
Learn the framework, understand what you CAN and CANNOT do.
Ask yourself some questions…
Do I want to migrate because ng2 is the hot new thing ?
What’s the current state of my project ?
For how long will I maintain this project ?
Will ‘vNext’ be a complete overhaul/rewrite ?
What's my priority in maintaining the current code base and keep
delivering values to my customers ?
Do I have a S.L.A. ?
More questions...
What’s the size of my project ?
How many external dependencies does my project have ?
Do they have an Angular 2 implementation ?
Do they play well with Angular 2 ?
Should look for something different ?
What’s the team skill level ?
Also...
Am I ready to bring in new technologies (and new tools) ?
Task Runners
Module Loaders
Build Pipeline
Angular CLI
Material Design
Angular Universal
Angular Mobile Toolkit
WTF are those ZONES ?!
OMG! TypeScript ?!
I’m not here to tell you…
…that Angular 2 is: New and Shiny, FASTER (way faster), built on
modern web standards, supports many interesting features like Lazy
Loading, Server Side Rendering…
You already know that!
I’m not here to tell you that you NEED Angular 2 at all.
It’s up to you to decide if you want Angular 2 in your project, I’m not
taking any responsibility.
Strategies
You'll have 3 options to migrate:
1) Don't do it.
2) Full rewrite (possibly keeping 2 codebases, or stopping the
development of you previous one).
3) Embrace a ‘minimize risk / potentially slow’ side by side migration
process.
So... Option 3
It turns out that a migration ‘is doable’ and the Angular team offers you
a tool to do just that:
ngUpgrade
Technically it allows for the coexistence of Angular 1 and Angular 2 in the
same application.
Both the frameworks will be active and will control independent portions of
the DOM with ngUpgrade being the glue between the two worlds, doing the
heavy job of keeping things in sync.
How do ngUpgrade work?
Angular 1 directive
Angular 2 service
Angular 2 component
Angular 2 serviceAngular 1 service
Angular 1 service
Angular 1 directiveAngular 1 directive
Cool! ....is it that easy ?
Kinda… but there are some limitations:
The Outer node must be an Angular 1 application.
Only the services in Angular 2 Root Injector can be downgraded.
You need to use string tokens to inject Angular 1 services in Angular 2
components: @Inject(<token>)
The ‘framework switch’ only happens inside the children of a Directive or
Component DOM node.
The ‘big ball of mud’ effect!
There's a very high risk of confusion, with a mixture of both frameworks,
‘different languages’ and coding styles that will hang around forever.
You should head towards a clean migration path that:
Minimizes Risks.
Allows for 'small' changes over time, that can improve even
your current Angular 1 code base.
Planning is the key!
You’ll want a plan that allows you to:
Keep developing and maintaining your application, deliverying value to your
customers (which is always your n°1 priority).
Gradually introduce ‘mutations’ in the way you code your product.
In the meanwhile preparing the ground for the ‘real’ migration.
Keep the code as clean as possible (following an internal styleguide).
A 2-phases plan: Preparation
This phase has almost nothing to do with Angular 2; it’s devoted to
changing the way you build your Angular 1 application today:
Bring in some of the tools we’ll extensively use in Angular 2.
Say hi to TypeScript.
(optional) Use a module loader and change your build pipeline.
Upgrade to the latest version of ng1 (double check the libraries).
Analyze and refactor the application: find and fix the weak points and
anti-patterns.
A 2-phases plan: Migration
Migration
Add the new Angular 2 framework to the project.
Setup up a mixed environment using ngUpgrade.
Write your new code in Angular 2.
Migrate Angular 1 code along the way.
Replace the old Angular 1 Router and clean-up.
Assessment
Review your project and do a proper check-up:
Angular version.
External libraries.
Update to the latest version of Angular (anything from 1.3.x will be
good).
Consider replacing unamaintained external libraries, look for libraries
that will have Angular 2 support.
Look for what’s forbidden
You might have heard that: Angular 2 has no $scope!
Everything works in isolation, so no more: ng-controller, ng-include or
shared $scope, live with that!
Compile(): is not supported anymore, Angular 2 has it’s own way to deal
with the DOM.
Some features were removed: no more ‘replace, terminal, priority’.
Filters are no more, we now have @pipe… Be prepared to rewrite them.
(optional) Module Loaders
Consider switching to a module loader to deliver your application
instead of all those <script> tags.
Some options are: SystemJS, WebPack, Browserify, etc…
Main Drawbacks:
It will require an overhaul of your building pipeline.
It will probably require a massive refactoring in you JS files.
You can delay this step and wait for Angular 2 migration to introduce a
module loader.
Welcome TypeScript!
Some of you might think of it as a necessary evil.
But it has some benefits:
Once you get accustomed to it, it can really increase your productivity
helping you avoid trivial bugs (it also has very good tooling).
Allows you to use ES2015 JavaScript Syntax.
Will also ‘force’ some structure in your code base.
Write ng1 code in a ‘good’ way
(with TypeScript)
Write your Controllers and Services as classes:
It will help you to get rid of the $scope (controllerAs, bindToController).
Take advantage of type checking, interfaces, intellisense, refctoring and
all the other goodies.
It will ease the code migration to Angular 2.
If you upgraded to angular 1.5.x consider using the new ‘component api’ to
define directives, it’s really very similar to how you’ll define components in
Angular 2.
NG1 TS – Service as class
The function becomes a class.
Dependency injection is specified with a static property.
Start using Type declarations.
NG1 TS – Service as class
‘this’ to refererence the members of the class.
NG1 TS – Service as class
Use the Arrow Syntax to define callback functions:
So the ‘this’ always refers to the instance of the class
The function becomes a class.
Dependency injection is specified with a static property.
Start using Type declarations.
NG1 TS – Controller as Class
NG1 TS – Controller as Class
The initialization goes in the constructor
NG1 TS – Controller as Class
‘this’ to refererence the members of the class.
Use the Arrow Syntax to define callback functions:
So the ‘this’ always refers to the instance of the class
NG1 TS – Controller as Class
The ‘this’ is really important when it comes
to classes.
You should know how it work!
TypeScript is your friend but…
Rewriting your code might not be always straightfoward… and it can be
a process that require some time.
TypeScript hides some JavaScript’s complexities (like the use of
prototypes and the ‘this’ management).
There are some special cases in which you need to know what the
compiler does in order to avoid subtile bugs.
Fix / Refactor the existing code
Fix your directives removing the incompatible features.
Warning: NON TRIVIAL ACTIVITIES INVOLVED!!
No more shared scope: everything should use an isolated scope
(remove all the ng-include / ng-controller and create explicit directives).
Use the ‘controllerAs’ and ‘bindToController’ syntax for your bindings.
Remove all the non supported features: replace, terminal, etc. If you
cannot do it, you’ll be forced to rethink the UI.
It can also be a good idea change the project structure to a ‘Folder by
Feature’ approach.
Take a look at the Angular 1 Style Guide for other anti-patterns.
Angular 2 Setup
You’ll need to find a way to add Angular 2 that suits your project:
The Outermost element MUST be an Angular 1 application.
There are several options you can consider:
o The Angular quickstart guide.
o A seeding project.
o Code generators (like angular-cli, yeoman, etc…).
All them involve the introduction of a module loader.
All of them will require some changes to your build pipeline process.
Angular 2 setup - do it simple
Start by following the quickstart guide.
Use ‘SystemJS’ as your first module loader.
Keep your build pipeline simple at start (avoid bundling and minification
in the early stage of the migration process).
Once the migration process is on its way, you can rework the build
process adding the other stages and optionally replace the module
loader.
Project Configuration
Add the ng2 libraries to the
package.json.
Modify the Application template
to load Angular 2 required
libraries.
Add your SystemJS configuration
file to load the new application
entry point.
ngUpgrade… finally!
This module will handle the cooperation of Angular 1 and Angular 2:
It will take over the application bootstrap process.
Will be used to downgrade Angular 2 Components and Services so they
can be used in an Angular 1 controlled environment.
Will be used to upgrade Angular 1 Directives and Services so they can
be used in an Angular 2 controlled environment.
Will take care of keeping the change detection mechanics in sync.
ngUpgrade Hybrid Bootstrap
You’ll need to switch to the manual bootstrap and delegate the startup code do
ngUpgrade’s UpgradeAdapter:
Remove your old Angular 1 bootstrapping code.
In the main Angular 2 NgModule:
Import the UpgradeAdapter
import { UpgradeAdapter } from '@angular/upgrade';
Create a single instance of the adapter
const adapter = new UpgradeAdapter(forwardRef(() => AppModule));
Bootstrap the application through the adapter
adapter.bootstrap(document.body, ["app"], { strictDi: true });
Downgrade Angular 2
Components and Services
In the main NgModule file:
Downgrade a Component
angular.module('app').directive('ng2HeartbeatView',
adapter.downgradeNg2Component(HeartbeatView));
Downgrade a Service
angular.module('app').service('ng2LogService',
adapter.downgradeNg2Provider(LogsService));
Upgrade ng1 directives and
services
In the main NgModule file:
Upgrade a Directive (in the NgModule declaration list)
@NgModule({
declarations: [
adapter.upgradeNg1Component("sidMonitoringHeartbeats")
]
})
Upgrade a Service (not in the NgModule providers list, it will be included in the root
injector anyway)
adapter.upgradeNg1Provider('logsService');
Migrate Service ng1 -> ng2
Angular 1 Angular 2
Service registration replaced by @Injectable() decorator.
The service class need to be registered in the providers list
of the root module.
Migrate Service ng1 -> ng2
Angular 1 Angular 2
Injection is made via constructor parameters and Type tokens.
Optionally using the @Inject(<name>) attribute.
Migrate directive ng1 -> ng2
The directive declaration is replaced by the @Component() decorator.
The Component class need to be added to the declarations list of the NgModule
Angular 1 Angular 2
Migrate directive ng1 -> ng2
Angular 1 Angular 2
Injection is made via constructor parameters.
Optionally using the @Inject(<name>) attribute.
Migrate directive ng1 -> ng2
Angular 1 Angular 2
Initialization and cleanup code go in the lifecycle hooks.
With angular 1.5.x you have almost the same lifecycle hooks for the component api,
migration would have been even easier!
Filters: rewrite as Pipes
You cannot Upgrade or Downgrade them: live with the duplicated code.
The Last Step: Routing,
Bootstrap & Clean-up
Let’s suppose you have migrated all your directives to components…
The Router (and the application template) will be the last thing to be
replaced!
Now you can get rid of the UpgradeAdapter and switch to the native
Angular 2 bootstrap.
Finally you can wave goodbye to all the Angular 1 dependencies and
libraries!
… and here we are, on the
path to the Holy Grail!
Alessandro Giorgetti
SID s.r.l.
member of: DotNetMarche / DevMarche
Facebook: https://www.facebook.com/giorgetti.alessandro
Twitter: @a_giorgetti
LinkedIn: https://it.linkedin.com/in/giorgettialessandro
E-mail: alessandro.giorgetti@live.com
Blog: www.primordialcode.com