Hi! In this article I'll describe the tool and approach we took to migrate our code base from AngularJS to Elm. The goal is to share and to help anyone who could possibly have to go down the same route at any given moment.
AngularJS is in the Long Term Support period at the moment. December 31, 2021 is the official deprecation date for AngularJS. Development teams and businesses will have to make a decision of which technology to migrate existing AngularJS code base to. We have decided to migrate to Elm. There are many good articles describing why Elm is a good choice. I'll focus on the migration part only.
There are various migration approaches like full rewrite from scratch and gradual migration, etc. A code base size may influence the migration strategy. Small code bases are very good for full rewrites. Full rewrites of bigger code bases are long and expensive. Depending on a current business situation the correct migration strategy may vary.
We had a relatively big code base with around 100k lines of AngularJS code, around 150 different pages and 8 frontend developers. The business is in a growth stage and it's important to maintain and deliver new functionality with improvements to the customers.
We have chosen a gradual migration strategy. We want to reuse existing code as much as possible until we find a good time to do a full rewrite of a particular page. We want to write all new code in Elm. A good time for a full rewrite might be when significant changes are planned for a particular page or when a page is small enough for a fast migration. To be able to write new code in Elm we need to replicate the existing internal framework (shared functionality between all pages).
So the strategy is to reuse existing AngularJS pages, directives, components in Elm when possible to speed up the migration and write new code in Elm. Never reuse Elm code in AngularJS (e.g. by wrapping Elm code with components) to stop AngularJS code base growth. Instead do a migration of the page to Elm.
To reuse existing AngularJS code in Elm we have created and open sourced angularjs-custom-element service to wrap any directive/component with a custom element. It has few usage examples in readme. Custom elements can be used in Elm very easily.
We started with an independent Elm program for each page. When AngularJS route changes a controller is initialized and an Elm program is embedded. On route leave an Elm program is destroyed. Here you can find details on how to destroy an Elm program.
The next step was to combine all Elm programs into one single program. The first thing to do after AngularJS app bootstrap is to embed the main Elm program and not to render AngularJS page. The main entry point (an HTML element) for the main Elm program should be somewhere right after
ng-app. Elm program will decide when to render AngularJS page. In Elm program we add a special case (usually a page constructor) to fallback to AngularJS page (via custom element for
ui-view). Global subscription for route changes is added and a current URL is sent to Elm program via flags or a flag that current page is AngularJS page is sent. An Elm program parses URL and renders appropriate page.
AngularJS state router is removed. Elm manages all pages and routing. AngularJS app is bootstrapped when needed for existing legacy. A new custom element is created to bootstrap AngularJS page.
It was a very nice experience for us and we are happy with what we've got now. It's still a long way for us to rewrite all pages to Elm. But the ability to move fast and do a migration at the same time is key for us as a development team and for a business!