Although a bit late to the party, I recently took on the task of upgrading a complex Angular project from version 16 to 17. While the official upgrade guide provides a great foundation, every project has unique challenges. Here’s my journey through the upgrade process, including the obstacles I encountered and how I resolved them. I hope sharing these experiences helps others facing similar challenges.
The Upgrade Strategy
When starting an upgrade, I always (re-)read the official announcement (Angular 17) to understand how our project might be impacted, what improvements I can bring to our codebase, and what new guidelines and concepts I can promote to our team.
The second step is to check Angular’s official update guide for similar reasons: getting an understanding of possible failure points and changes I can expect in the code as part of the migration to the new version.
The next and final step before starting the hands-on migration is to check the Angular-NX version compatibility matrix. Since our project uses NX this will be the driver for our migration steps.
Another step I take, usually before I even consider an upgrade, is to check all our third-party dependencies and see if we might have any compatibility issues and possible solutions for them. With this in mind, after our main migration has successfully taken place I update each one of them to a compatible version.
The Update Process
For the update process, I always take an incremental approach: updating through each minor version rather than jumping straight to the latest. This helps me better identify the cause and resolve issues at each step.
We’ve also decided to keep the NX version in sync with Angular and have not updated to the latest NX version. So, given the Angular-NX compatibility matrix below, we had a four-step migration on our hands: 17.1.0 -> 17.3.0 -> 18.1.1 -> 18.2.0.
For each NX version, we followed these steps:
-
npx nx migrate <nx-version>
— Initiate the migration - Review and validate changes
-
npm install
— Update dependencies - Commit changes
-
npx nx migrate --run-migrations
- Execute migrations - Test, lint, and build for production
Version-specific Challenges
npx nx migrate 17.1.0
Our first interesting challenge was upgrading to NX version 17.1.0. The migration failed instantly. Can you guess why? :) NX version 17.1.0 doesn’t exist. If you go digging through versions you will see there have been some 17.1.0 beta versions but then directly 17.1.1.
The solution was to use npx nx migrate 17.1
instead of 17.1.0
, which allowed us to upgrade to the latest 17.1.x version.
This first migration step updated the code base to the Angular 17 version and this brought our main issues of the migration, the unsupported libraries:
- ngx-matomo
- ngx-quill
ngx-matomo hasn’t seen updates in 2 years and it doesn’t support Angular 17. While this library has served us well until now, we moved to ngx-matomo-client which offers the same functionality with few code changes and it is better maintained. For more details into this transition, you can check out my ngx-matomo to ngx-matomo-client article.
The ngx-quill version that we had was using quill v1 underneath and only ngx-quill versions using quill v2 were also supporting Angular 17. While I thought quill v2 would bring many changes, the transition was quite smooth. We only encountered issues with our keyboard bindings, where we had to migrate from using key number values to names: key: 13 -> key: ‘Enter’
Other changes that we had to address included some changes to eslint rules that cause our linting step to fail. I reviewed the changes and decided for each to either adjust the code or adjust the rule.
npx nx migrate 17.3.0
During this phase, we encountered several (smaller) challenges:
- Jest undefined errors required explicit imports from @jest/globals
- Comply with new lint rules regarding paths and module boundaries
A notable issue we encountered was with the NX CLI commands. The nx serve --project=project-name
syntax stopped working in this version. While this was fixed in later NX versions, we temporarily switched to using nx run project-name:serve
as a workaround.
Versions 18.1.0 and 18.2.0
I have no issues to report for versions 18.1.0 and 18.2.0. The NX migrations worked perfectly on our code!
Additional Angular 17 Improvements
We took this upgrade opportunity to implement some significant improvements in our codebase:
Standalone Components Migration
While we have been migrating components to standalone one-by-one as part of our day-to-day business, we now took the opportunity to migrate all components (except the main app component). While this wasn’t strictly required for Angular 17, it aligned well with the framework’s direction and helped modernize our codebase.
Built-in Control Flow Implementation
Implementing the new control flow syntax was one of our major goals. To optimise this step, I used the automatic migration command npx nx generate @angular/core:control-flow-migration
and then checked each changed file (yeah, about 300 of them), to make sure no defects were introduced. Plus, additional changes were needed for the @for track by to be properly set. Besides this, I also discovered some important caveats of using the automated migration:
- At times it deleted
<ng-template>
tags which led to duplicated code and broken ViewChild references - Elements within new if/else statements that were used for content projection using
<ng-content select="...">
needed wrapping with<ng-container>
to work properly
Looking forward
This upgrade has been an exciting journey. The performance benefits from the new control flow syntax are already noticeable in our application. I’m particularly looking forward to expanding our use of Angular 17’s features, especially implementing signals and deferrable views in the coming months.
Conclusion
While every Angular project is unique, I hope sharing my way of approaching the upgrade, as well as the specific challenges and solutions I encountered, helps you plan your upgrade to Angular 17.
Remember that the official upgrade guide is your foundation, but be prepared to tackle project-specific issues along the way. Take time to review your project’s dependencies and test thoroughly at each step.
Cheers!
Top comments (0)