So you have an Angular JS in prod and you want to migrate it to the latest version of Angular. The first question to answer is why? While talking to our clients, I’ve heard the following answers:
– We have a large app and it has issues with performance.
– Our company is moving to Angular/TypeScript and we want all apps to use these technologies.
– We need to improve performance of our AngularJS app
– Since all new apps will be written in Angular, it’s going to become hard to support apps written in two different languages and frameworks. The pool of developers who can/want write in AngularJS will be shrinking.
Any of the above answers sounds reasonable. But think about it for a moment. You have a working app with a certain functionality. After spending X amount of dollars your end users will get an app with the same functionality. Does it worth the trouble? Let’s say it does and the budget for the migration is approved.
Two approaches for migration
There are a couple of approaches to the AngularJS-Angular migration process.
1. Rewrite the app from scratch.
IMO, this is the best approach if your circumstances permit. A complete re-write can be the most cost-effective strategy. If you’re a manager, put your team through Angular training (live, online, videos, books). Allocate time and budget for getting your developers up to speed with Angular as the learning curve is steep and prior experience with AngularJS is not overly helpful. Then your developers will write the new version of the app as per best practices recommended for Angular/TypeScript projects. Ideally, your team should include a developer who has at least one year of practical development in Angular. If you don’t already have such a developer, hire one. He should be both a developer and a mentor.
But a complete rewrite may not be an option. Your existing (small-to-midsize) AngularJS app is in prod, works well, and the end users keep asking for new features that have to be released in prod on a regular basis. This means that you can’t just stop developing in AngularJS, and spending several months doing greenfield development is not an option.
You can’t do a complete rewrite if an existing app is large (think hundreds of views). In this case, a rewrite could take a couple of years.
2. Gradual migration
If you decide to go this route, start with reading the document titled “Upgrading from AngularJS“. It’s a well-written document, but you need to understand that it’s about migration from AngularJS to a completely different framework. Don’t be tricked by the statements like “Angular is a reimagined version of the best parts of AngularJS”. Angular is a different framework with different architecture and principles of building apps.
Plan your migration
You need to come up with a plan for your migration project. The plan will depend on how your current AngularJS app was written. While the Angular’s migration guide mentioned above recommends preparing your AngularJS app to have one component per file (see Rule 1 in the migration guide) and use module loaders, the chances are slim that your existing AngularJS app followed this rule. Refactoring your AngularJS app just to follow this rule is a project on its own; it may be costly and your refactored app would require additional testing and bug fixing.
The Angular migration guide explains how the AngularJS app should use component directives to simplify migration to Angular. Once again, changing your existing app to follow these guidelines is yet another project.
Depending on the production release schedule of the existing AngularJS app, you can pick one of two approaches for the migration:
– Feature by feature
– Route by route
When you migrate feature by feature, identify a group of component and services implementing this feature in the new Angular code.
Migrating route by route would also require a similar activity, but you’d need to pick a route and identify which components and services would need to be there. The route by route strategy works well if the views of your app are relatively simple and don’t use complex custom components.
If your AngularJS app has complex UI components, you may need to convert them first.
Running Angular and AngularJS side by side
The next step is to learn how the ngUpgrade and UpgradeModule work. The UpgradeModule serves as a bridge between the Angular and AngularJS parts of your app.
No matter how you’ll approach the migration, for some period of time your app will include two frameworks: AngularJS and Angular. When our company is involved with migration projects, we start with creating an Angular app that just bootstraps the existing AngularJS app as is with the help of the UpgradeModule.
With the UpgradeModule, you’ll run a hybrid app that’ll have two parts – one part will include Angular framework, and another – AngularJS. The components and services from the Angular part will communicate with their counterparts from the part written in AngularJS. Read the Angular migration guide about the differences in Dependency Injection (DI), change detection, and working with DOM.
While Angular DI is more flexible and allows either having services as singletons for the entire app or a specific component branch, in AngularJS services are always app-level singletons. This is not a big deal as in a typical Angular app we use app-level singletons anyway. In particular, you can use a singleton and DI for storing the state of the hybrid app. During the migration, you need to identify which services will be injected from Angular to AngularJS and those that will be injected in the opposite direction.
Components of both frameworks need to communicate with each other. If you’re not familiar with how to arrange a loosely-coupled component communication in Angular using injectable services, watch my video on the subject.
While running a mixed Angular/AngularJS app, the Angular framework will be responsible for triggering change detection of the entire app. Angular includes a library zone.js that serves as an execution context for all asynchronous processes of the app. On any change that may need to update a UI, it makes a single pass through the entire component tree and triggers the UI updates. There is no need to invoke $scope.$apply() as it’s done in AngularJS. In a hybrid app, on any async change that would start Angular change detection, the UpgradeModule will invoke $rootScope.$apply() in your AngularJS code.
Finally, roll-up your sleeves, start reading the AngularJS code and gradually implement it in Angular.
Don’t forget about re-thinking your deployment process. Most likely you have an automated deployment implemented using Gulp or Grunt. In Angular apps most of the features that we had to manually configure in AngularJS are provided by the tool called Angular CLI. We wrap Angular CLI commands into npm scripts and add Gulp tasks if need be. It takes only several lines of code in npm scripts to build the bundles for deployment in Angular. In this video I show how to write a script that will build the Angular bundles and deploy them under a Java Spring server. If I wanted to gzip the files before deployment, I could have added one more line like `“postbuild:prod”: “gulp –gulpfile compress.js”` that invokes my script that uses the Gulp plugin for compression.
Good luck with your migration projects!