9 Lessons Learned on an AngularJS to Angular 4 Upgrade
By Rich Franzmeier
I recently had the pleasure of working with a great team on an AngularJS to Angular 4 upgrade (Angular 1.5 project to Angular 4.3.6 to be specific). It was a side-by-side upgrade so we ran both versions of Angular until the end of the project. We learned some things along the way, some the hard way, others by looking in the rear view mirror. Some of these will be specific to our AngularJS to Angular 4 project but the hope is that you can take away at least one nugget to help you in your upgrade.
1. Build the framework by using the Angular CLI Immediately
At first when I planned the AngularJS to Angular 4 project I figured I needed to use SystemJS because that’s what one site said on upgrading Angular. I’m glad I had a guy on the team who took the initiative to get us on the CLI right off the bat. Otherwise, we would have been forever dealing with build issues, etc. Building the framework on the CLI was definitely the right move.
And the framework we built was just to get the two frameworks running side-by-side with the “old” code bootstrapped on Angular CLI. Make sure you get to this point first before doing upgrade work.
2. Use ‘paths’ in your tsconfig.json file early
I don’t know how many times we had to refactor the code. It would have been a lot easier to refactor had we known about the TypeScript compiler option ‘paths’.
Here is how it’s done:
So instead of having a relative path like this:
You have this:
Then when you refactor, there is no need to figure out all the issues with the relative paths. This is one thing we found later thanks to this article that we wish we found earlier.
3. Know your Router — If you are using UI Router, the upgrade posts are no help
I was following Victor Savkins post on 5 steps to upgrade and so the plan was to upgrade the routes after each module was completed. The problem was, that post is specific to the AngularJS router and we were using the UI Router. There were really no good posts on upgrading UI-Router. It turned out we had to improvise to get UI router to work. There is a UI router upgrade package but it didn’t work for us.
We ended up doing the following to get routing to work from Angular 1.5 to Angular 4:
- In the route, we changed the “templateUrl” to “template” and then added the Angular 4 component like this: ‘<ng4-component></ng4-component>’
- Assuming here that you know how to downgrade an ng4 component 🙂
- Also, if we needed to pass something into the component, no problem, do that through the component as well using @Input variables: ‘<ng4-component [parm1]=”hello world”></ng4-component>
To route from Angular 4 to Angular 1.5, we used a downgraded service that used UI router navigation commands. This went away after AngularJS was gone.
In the end, we had one guy upgrade all of the routes to Angular 4…but not until all of the views were upgraded.
4. Upgrade the services early
We found that a lot of the stuff we were trying to do couldn’t use upgraded services because it was too early in the Angular 4 start-up pipeline. So we made the call to upgrade the services in one sprint. That made it quite easy to do our thing later on. One example is trying to use the APP_INITIALIZER injection token (see my post on this), we couldn’t have Angular 1.5 upgraded services in there. Usually it was because the AngularJS piece wasn’t bootstrapped yet.
5. Keep the HTML similar until after the upgrade
We had the opportunity early on to upgrade the HTML to use the client’s component library instead of the current HTML, which was using Bootstrap. We decided before we started not to upgrade the HTML components and I’m glad we made that call. Dealing with a new library and figuring out how to get the same look and feel would have added at least 2 sprints to the project. That’s not what the client wanted and it’s frankly not what us developers wanted also.
6. Upgrade directives along with the view
Most AngularJS projects have some list of directives that are reused throughout the application. Well our project was no different. So my initial thinking was that we’d upgrade those separately because it would be easy. Well, that turned out to be a bad call. It turns out we couldn’t get Angular 4 directives to work with Angular 1.5 views. So the new plan became to only upgrade directives when the view needed it.
This was a good call and had the following benefits:
- It was very easy to test the directive because it was on the page that was being upgraded
- The person upgrading the directive found a better way to reuse the directive by combining them or creating a validator directive, etc.
7. Look for re-use opportunities (and do code reviews)
I was blessed with a relatively small team so we had a great chance to see the whole picture of the code base. Having that helped to allow us to reuse components, directives, validator directives, pipes and even services. We also were doing code reviews of each others work and that also allowed us to say “Hey, I did that already, you can use this component”. So if you don’t have a small team and can’t see the big picture well, at least do code reviews for every check in so that re-use opportunities can be spotted.
8. Test every sprint
We worked in an agile environment so we had 3 week sprints. By the end of the sprint, all of our code had to be tested by QA and then approved by user acceptance testing. This was invaluable to delivering a quality product. With the amount of refactoring we were doing, bugs were bound to surface.
9. Unit test later in the project
My plan for unit testing was to unit test everything by the end of each sprint. Of course I realized early that this wasn’t going to happen. I was kind of OK with it, though, because we were making such good progress on the upgrade effort. I think now that for an upgrade, unit testing should be pushed out until later in the project. I know that is a religious issue for some of you and I just crossed the line so I’m going to list out why I think this is the way to go (at least for upgrades.)
We did a lot of refactoring of the code, had we created unit tests early on, there would have been a lot of tech debt in unit tests to maintain
- For example, although the plan was to use NGRX for state management, I was really the only one doing it until the rest of the team caught on to the awesomeness of it
- So a lot of the services moved to effects…had we unit tested all of the services, they would have all had to change
Some of the Angular 4 code we had early on went away because it was only for the upgrade
- Had we been anal on unit testing, that would have been wasted effort
A lot of the code moved from Angular 4 components to NGRX reducers (and this not until later in the project)
- Reducers are much easier to test than components
AngularJS to Angular 4+ upgrade projects have a lot of challenging moving pieces. Knowing things before planning begins can save a lot of time potentially. Hopefully this list of lessons learned will help your team in their successful upgrade.
Originally published at www.intertech.com on December 19, 2017.