TL;DR : “If I go there will be trouble and If I stay it will be double.”
Hello dear Angular developers, I’ll let you know,
For those of you who don’t live in a cave or work in a company where angular.io is blocked by the firewall, you are probably aware that Angular 2 is already at it’s release candidate version so the final version will be available soon!!!
We’re all excited of course… but what happens to our old precious little AngularJS apps?
Should I stick to Angular 1.x?
Should I forget about my apps and start from scratch with Angular 2+?
What if I have to start developing a new app tomorrow? Which one should I pick?
Well, at Wishtack, we’ve been playing with Angular 2 for a couple of months now and we came up to the following conclusions.
Angular 2+ is getting pretty stable now and it has so many new vital features
Powerful and Customizable Change Detection
With AngularJS, one-time binding is quite fine most of the time to reduce the number of watchers but what if you have multiple forms and dynamic stuff on the same page?
Well, anytime you press a key on an input, you’ll trigger the digest cycle on the whole page while you pertinently know that nothing will change outside of your form. There are some hacky and tricky ways to avoid this but nothing that comes out of the box.
With Angular 2, you can control the change detection completely.
Imagine the following situation. You have a “wt-user” component containing a “wt-user-info” and a “wt-wishlist” component using another component “wt-wish” to display user wishes.
With Angular 2+, you can tell the component “wt-wish” to get updated only if the wish changes and/or the “wt-wishlist” component to update only if the wishlist changes. This gives you so much control, power and performance!!!
The power of Angular 2+ is to mix the power of the change detection (like AngularJS digest cycle) and the developer controlled changes for performance’s sake. For example, ReactJS is powerful because developers have to control all the changes and you can easily fall in a infinite change loop.
TODO: I will add a plunker example that crashes with ReactJS but not with Angular 2.
All those who have already made a public single page application should know that search engines (even google) are not that friendly with JS or maybe they are just lazy thus your server has to render the app for them.
On Wishtack, we are using prerender.io which is using PrerenderJS, a service that runs PhantomJS as a browser that runs your app and outputs the resulting HTML for search engines.
Well, it works but it’s not that clean and not that performant.
With server-side rendering, Angular 2 will run on your server and simulate a browser in order to generate the right output. Sounds cool?
Actually, it’s cooler than that. As you might notice on most single-page applications, the browser has to download the HTML, the JS, execute the JS then produce the output. When your app gets bigger, the startup will get slower…
… but with Server-Side Rendering:
1 – Angular 2 will prerender the page on your server
2 – hand it to the browser
3 – the browser will display the page prerendered by the server
4 – while starting up your single-page application, Angular 2 will capture all the events triggered by the user (clicks / inputs etc…)
5 – once the application is started, Angular 2 will trigger all the actions associated to the events triggered by the user.
6 – the user won’t notice the app startup and will interact with it before it starts.
Angular 2 is Strict and Verbose
A cool thing with Angular 2 compared to AngularJS and other frameworks is its verbosity and consistency. With AngularJS we are able to use undeclared and undefined objects in the view like this:
<input ng-model="$ctrl.user.info.firstName" type="text">
and AngularJS will create a new “user” object, “user.info” object and initialize the “user.info.name” field.
While this might sound cool, it’s error prone and if you don’t unit-test your views correctly, you might miss that.
Example: a typo like this one “$ctrl.user.info.firstname” will not produce any error but will initialize the wrong field.
With Angular 2, the component’s class has to initialize all the objects with a valid type, otherwise you will get an error telling you that the object is not initialized or the field does not exist.
Of course, this will need few additional code but it guarantees consistency.
With Angular 2 + webpack, you can lazy load views so Angular 2 will not load all the services and components needed by that view until the user navigates to it.
… but Angular 2 is quite young and a bit lonely
As described above, Angular 2 mixes the power of all modern technologies (AngularJS / Shadow DOM / Observables / Server-Side Rendering / … ) but it currently lacks one thing, the ecosystem.
As an example, on Wishtack, we are using more than 20 AngularJS external modules for which there’s no current alternative on Angular 2, like Angular Material.
So what? Should we wait for Angular Material 2 to be released with all the features from Angular Material?
The answer is no!
Angular 2+ loves AngularJS 1.x
No worries! The answer is here.
Thanks to Angular 2’s built-in upgrade module, you can use AngularJS components inside Angular 2 (and Angular 2 components in AngularJS).
In order to use AngularJS with Angular 2, you have to create a hybrid app. A hybrid app is nothing more than an AngularJS app using Angular 2 components and services and inside these Angular 2 components you can use AngularJS components and services etc…
This works with simple calls to magic methods like `UpgradeAdapter.upgradeNg1Component` and `UpgradeAdapter.downgradeNg2Component`.
Whenever you want to use an AngularJS component inside Angular 2, you upgrade it and vice versa.
AngularJS will run the digest cycle on AngularJS components and Angular 2 will use it’s magic change detection on Angular 2 components.
Migration Strategy & Preparation
IMHO, the leanest migration strategy is the following:
0 – Write AngularJS code in the most framework-agnostic way
At Wishtack, we started doing so even before the idea of Angular 2 was born.
Why? Simply because we didn’t want to be stuck to a framework even if it’s as superheroic as AngularJS.
How? Since the beginning we started using classes using http://indigounited.com/dejavu/. First, because we love classes and secondly because we wanted our business and app logic to be outside of AngularJS. We didn’t want any of AngularJS services and $scope etc… inside our app logic.
If you are using ES6 or TypeScript (yes, you can write AngularJS apps with TypeScript), then use native classes of course.
Each component must be independent
Do not share information with other components through events or scopes.
Components should share information directly through HTML attributes (inputs/outputs we call bindings). You can also share information through services.
Each component has a class, a template and optional style files.
Think about using transclusion (Angular 2 calls it projection) for template code sharing.
Components’ replace attribute should be always set to it’s default value: false.
Use AngularJS 1.5 component method: https://docs.angularjs.org/api/ng/provider/$compileProvider#component
Do not use $scope
1 – Set up webpack if you are not already using it in order to be able to use ES5 / ES6 / TypeScript in the same app.
There are two nice boilerplates for this by AngularClass:
wt-djangular2 will have all this settled up for you:
– Protractor (with BrowserStack) support.
– Heroku ready app.
– Optional Python backend with MongoDB descriptive API generation + permissions management.
Let us know if you are interested by wt-djangular2, if you have any feature ideas and if you want to contribute.
2 – Start writing your new components and services with Angular 2 and use them inside your existing AngularJS app.
Don’t forget that you can use your AngularJS components and services inside your new Angular 2 code.
3 – Use ngComponentRouter for routing as it’s similar to Angular 2 routing logic so the migration will be easier.
4 – Once you get rid of all your AngularJS code, you can move your routing logic to Angular 2 and bootstrap your Angular 2 app without AngularJS.
5 – Unit-test everything
We’ve been playing with hybrid apps testing lately and discovered that it was quite tricky.
We’ll post an article about this soon. Meanwhile, you can have a look at the issues we’ve opened on Angular 2 as they contain some plunker examples:
And their respective plunkers:
Current issues with Angular 2 migration
At Wishtack, we still didn’t migrate to Angular 2 for the following reasons.
TypeScript compile time [SOLVED using awesome-typescript-loader]
With our current gulp configuration it takes less than 3 seconds for the whole project to build.
With Webpack and TypeScript compilation, a simple hello world app takes at least 10 to 15 seconds.
This might sound like a stupid issue but this is really important for us, when you edit your code or design, you can’t wait 10 seconds before the tests to run or for the page to refresh.
We call this developer frustration and it’s very important to avoid it. We even bought SSDs for our computers and optimized our gulp tasks in order to build in less than 3 seconds 🙂
Webpack / Angular 2 CDN version [SOLVED webpack 2 has systemjs support]
We are waiting for Webpack to fully support SystemJS async loading in order to use Angular 2 from a CDN while still keeping the ES6 import syntax.
Documentation [SOLVED documentation is ready!]
The Angular 2 team has done a nice documentation work but it still misses some tricky parts like hybrid app testing.
We’ll keep you posted with more technical details, boilerplates and examples soon!
By the way, did you try our chrome extension?